diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index e0cd825e02..b26747cc90 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -853,6 +853,7 @@ sandbox_preview=Preview Website sandbox_create=Create New Content sandbox_browse=Browse Website sandbox_submitall=Submit All +sandbox_submitselected=Submit Selected sandbox_icon=Browse Website import_website_content=Import Website Content title_browse_sandbox=Browse Sandbox diff --git a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java index f978f0a0d8..4833391ba5 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java @@ -807,6 +807,16 @@ public class AVMBrowseBean implements IContextListener } } + public void submitSelected(ActionEvent event) + { + UIActionLink link = (UIActionLink)event.getComponent(); + Map params = link.getParameterMap(); + String store = params.get("store"); + String username = params.get("username"); + + List selected = this.userSandboxes.getSelectedNodes(username); + } + // ------------------------------------------------------------------------------ // Private helpers diff --git a/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java b/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java index 7663f866e3..3be876c2e3 100644 --- a/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java +++ b/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java @@ -18,7 +18,9 @@ package org.alfresco.web.ui.wcm.component; import java.io.IOException; import java.text.DateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -77,6 +79,8 @@ public class UIUserSandboxes extends SelfRenderingComponent private static final String COMPONENT_ACTIONS = "org.alfresco.faces.Actions"; + private static final String ACT_PANEL = "_panel"; + private static final String MSG_MODIFIED_ITEMS = "modified_items"; private static final String MSG_SIZE = "size"; private static final String MSG_CREATED = "created_date"; @@ -92,10 +96,19 @@ public class UIUserSandboxes extends SelfRenderingComponent /** website to show sandboxes for */ private NodeRef value; + /** cached converter instance */ private ByteSizeConverter sizeConverter = null; + /** set of exanded user panels */ private Set expandedPanels = new HashSet(); + /** map of users to modified item nodes - used for multi-select action lookup */ + private Map userToRowLookup = new HashMap(8, 1.0f); + private Map rowToUserLookup = new HashMap(8, 1.0f); + private Map> userNodes = new HashMap>(8, 1.0f); + + private String[] checkedItems = null; + // ------------------------------------------------------------------------------ // Component implementation @@ -115,15 +128,23 @@ public class UIUserSandboxes extends SelfRenderingComponent super.restoreState(context, values[0]); this.value = (NodeRef)values[1]; this.expandedPanels = (Set)values[2]; + this.userToRowLookup = (Map)values[3]; + this.rowToUserLookup = (Map)values[4]; + this.userNodes = (Map)values[5]; + this.checkedItems = (String[])values[6]; } public Object saveState(FacesContext context) { - Object values[] = new Object[3]; + Object values[] = new Object[7]; // standard component attributes are saved by the super class values[0] = super.saveState(context); values[1] = this.value; values[2] = this.expandedPanels; + values[3] = this.userToRowLookup; + values[4] = this.rowToUserLookup; + values[5] = this.userNodes; + values[6] = this.checkedItems; return values; } @@ -149,9 +170,11 @@ public class UIUserSandboxes extends SelfRenderingComponent public void decode(FacesContext context) { Map requestMap = context.getExternalContext().getRequestParameterMap(); - String fieldId = getClientId(context); - String value = (String)requestMap.get(fieldId); + Map valuesMap = context.getExternalContext().getRequestParameterValuesMap(); + // detect if a panel has been expanded/collapsed + String fieldId = getClientId(context) + ACT_PANEL; + String value = (String)requestMap.get(fieldId); if (value != null && value.length() != 0) { // expand/collapse the specified users panel @@ -166,6 +189,9 @@ public class UIUserSandboxes extends SelfRenderingComponent this.expandedPanels.add(value); } } + + // store the list of checked items for multi-select action context + this.checkedItems = (String[])valuesMap.get(getClientId(context)); } /** @@ -181,6 +207,10 @@ public class UIUserSandboxes extends SelfRenderingComponent ResponseWriter out = context.getResponseWriter(); + this.rowToUserLookup.clear(); + this.userToRowLookup.clear(); + this.userNodes.clear(); + ResourceBundle bundle = Application.getBundle(context); AVMService avmService = getAVMService(context); NodeService nodeService = getNodeService(context); @@ -209,6 +239,10 @@ public class UIUserSandboxes extends SelfRenderingComponent String username = (String)nodeService.getProperty(userInfoRef, ContentModel.PROP_WEBUSERNAME); String userrole = (String)nodeService.getProperty(userInfoRef, ContentModel.PROP_WEBUSERROLE); + // create the lookup value of sandbox index to username + this.userToRowLookup.put(index, username); + this.rowToUserLookup.put(username, index); + // build the name of the main store for this user String mainStore = AVMConstants.buildAVMUserMainStoreName(storeRoot, username); @@ -225,6 +259,17 @@ public class UIUserSandboxes extends SelfRenderingComponent if (logger.isDebugEnabled()) logger.debug("Building sandbox view for user store: " + mainStore); + // output a javascript function we need for multi-select functionality + out.write(""); + // for each user sandbox, generate an outer panel table PanelGenerator.generatePanelStart(out, context.getExternalContext().getRequestContextPath(), @@ -254,7 +299,7 @@ public class UIUserSandboxes extends SelfRenderingComponent null, null, sandboxUrl)); out.write(" "); - // TODO: add this action back once we can create in a specific sub-folder + // TODO: add this action back once we can create via configured form attached to website project /*Utils.encodeRecursive(context, aquireAction( context, mainStore, username, "sandbox_create", "/images/icons/new_content.gif", "#{AVMBrowseBean.setupSandboxAction}", "wizard:createWebContent", null)); @@ -278,7 +323,7 @@ public class UIUserSandboxes extends SelfRenderingComponent panelImage = WebResources.IMAGE_EXPANDED; } out.write(Utils.buildImageTag(context, panelImage, 11, 11, "", - Utils.generateFormSubmit(context, this, getClientId(context), username))); + Utils.generateFormSubmit(context, this, getClientId(context) + ACT_PANEL, username))); out.write(" "); out.write(bundle.getString(MSG_MODIFIED_ITEMS)); out.write(""); @@ -287,7 +332,7 @@ public class UIUserSandboxes extends SelfRenderingComponent out.write("
"); // list the modified docs for this sandbox user - renderUserFiles(context, out, username, storeRoot); + renderUserFiles(context, out, username, index, storeRoot); } out.write(""); @@ -320,11 +365,12 @@ public class UIUserSandboxes extends SelfRenderingComponent * @param fc FacesContext * @param out ResponseWriter * @param username The username to render the modified files for + * @param index Index of the sandbox in the list of sandboxes * @param storeRoot Root name of the store containing the users sandbox * * @throws IOException */ - private void renderUserFiles(FacesContext fc, ResponseWriter out, String username, String storeRoot) + private void renderUserFiles(FacesContext fc, ResponseWriter out, String username, int index, String storeRoot) throws IOException { AVMSyncService avmSyncService = getAVMSyncService(fc); @@ -349,15 +395,28 @@ public class UIUserSandboxes extends SelfRenderingComponent UIActions uiFolderActions = aquireUIActions(ACTIONS_FOLDER, userStorePrefix); UIActions uiDeletedActions = aquireUIActions(ACTIONS_DELETED, userStorePrefix); + String id = getClientId(fc); + // use the sync service to get the list of diffs between the stores List diffs = avmSyncService.compare(-1, userStore, -1, stagingStore); if (diffs.size() != 0) { + // store lookup of username to list of modified nodes + List nodes = new ArrayList(diffs.size()); + this.userNodes.put(username, nodes); + // output the table of modified items out.write(""); // header row - out.write(""); + out.write(""); // output each of the modified files as a row in the table + int rowIndex = 0; for (AVMDifference diff : diffs) { - // TODO: display cases for diff.getDifferenceCode()? + // TODO: different display cases for diff.getDifferenceCode()? + boolean isGhost = false; String sourcePath = diff.getSourcePath(); AVMNodeDescriptor node = avmService.lookup(-1, sourcePath); - if (node != null) + if (node == null) + { + // may have been deleted from this sandbox - which is a ghost node + node = avmService.lookup(-1, diff.getSourcePath(), true); + isGhost = true; + } + + // handle missing node case by skipping the row rendering + if (node == null) + { + continue; + } + + // save reference to this node for multi-select action lookup later + nodes.add(node); + + // output multi-select checkbox + out.write(""); + + if (isGhost == false) { // icon and name of the file/folder - files are clickable to see the content String name = node.getName(); @@ -384,7 +471,7 @@ public class UIUserSandboxes extends SelfRenderingComponent fc.getExternalContext().getRequestContextPath() + DownloadContentServlet.generateBrowserURL(AVMNodeConverter.ToNodeRef(-1, sourcePath), name) + "\" target='new'>"; - out.write(""); } else { - // must have been deleted from this sandbox - show ghosted - AVMNodeDescriptor ghost = avmService.lookup(-1, diff.getSourcePath(), true); - if (ghost != null) + // must have been deleted from this sandbox - show as ghosted + String name = node.getName(); + out.write(""); + out.write(name + " [" + bundle.getString(MSG_DELETED_ITEM) + "]"); + out.write(""); } + else + { + out.write(Utils.buildImageTag(fc, SPACE_ICON, 16, 16, "")); + out.write(""); } + out.write(""); + // end table out.write("
"); + out.write("
"); + // multi-select checkbox + out.write(""); out.write(bundle.getString(MSG_NAME)); out.write(""); out.write(bundle.getString(MSG_CREATED)); @@ -370,12 +429,40 @@ public class UIUserSandboxes extends SelfRenderingComponent out.write("
"); + out.write(""); if (node.isFile()) { out.write(linkPrefix); @@ -435,56 +522,55 @@ public class UIUserSandboxes extends SelfRenderingComponent uiFolderActions.setContext(avmNode); Utils.encodeRecursive(fc, uiFolderActions); } - out.write("
"); + if (node.isFile()) { - // icon and name of the file/folder - files are clickable to see the content - String name = ghost.getName(); - out.write("
"); - if (ghost.isFile()) - { - out.write(Utils.buildImageTag(fc, Utils.getFileTypeImage(fc, name, true), "")); - out.write(""); - out.write(name + " [" + bundle.getString(MSG_DELETED_ITEM) + "]"); - out.write(""); - } - else - { - out.write(Utils.buildImageTag(fc, SPACE_ICON, 16, 16, "")); - out.write(""); - out.write(name + " [" + bundle.getString(MSG_DELETED_ITEM) + "]"); - } + out.write(Utils.buildImageTag(fc, Utils.getFileTypeImage(fc, name, true), "")); out.write(""); - - // created date - out.write(df.format(new Date(ghost.getCreateDate()))); - out.write(""); - - // modified date - out.write(df.format(new Date(ghost.getModDate()))); - out.write(""); - - // size of files - if (ghost.isFile()) - { - out.write(getSizeConverter().getAsString(fc, this, ghost.getLength())); - } - out.write(""); - - // deleted UI actions for this item - uiDeletedActions.setContext(new AVMNode(ghost, true)); - Utils.encodeRecursive(fc, uiDeletedActions); - - out.write("
"); + out.write(name + " [" + bundle.getString(MSG_DELETED_ITEM) + "]"); + } + out.write(""); + + // created date + out.write(df.format(new Date(node.getCreateDate()))); + out.write(""); + + // modified date + out.write(df.format(new Date(node.getModDate()))); + out.write(""); + + // size of files + if (node.isFile()) + { + out.write(getSizeConverter().getAsString(fc, this, node.getLength())); + } + out.write(""); + + // deleted UI actions for this item + uiDeletedActions.setContext(new AVMNode(node, true)); + Utils.encodeRecursive(fc, uiDeletedActions); } + out.write("
"); + Utils.encodeRecursive(fc, aquireAction( + fc, userStorePrefix, username, "sandbox_submitselected", "/images/icons/submit.gif", + "#{AVMBrowseBean.submitSelected}", null, null)); + out.write("
"); } @@ -709,4 +795,56 @@ public class UIUserSandboxes extends SelfRenderingComponent { this.value = value; } + + /** + * Get the selected nodes for a specified sandbox user + * + * @param username User in the user sandbox list + * + * @return List of AVMNodeDescriptor object representing the selected items + */ + public List getSelectedNodes(String username) + { + return getSelectedNodes(username, this.rowToUserLookup.get(username)); + } + + /** + * Get the selected nodes for a specified sandbox index + * + * @param sandbox Index of sandbox in the user sandbox list + * + * @return List of AVMNodeDescriptor object representing the selected items + */ + public List getSelectedNodes(int sandbox) + { + return getSelectedNodes(this.userToRowLookup.get(sandbox), sandbox); + } + + private List getSelectedNodes(String username, int sandbox) + { + List nodes = null; + + if (username != null) + { + List paths = this.userNodes.get(username); + if (paths != null) + { + nodes = new ArrayList(paths.size()); + String sandboxPrefix = Integer.toString(sandbox) + '_'; + + // check against the selected items + for (int i=0; i