From bd25cfa86f83f55eef6650e1decb1a0a9612840a Mon Sep 17 00:00:00 2001 From: Kevin Roast Date: Wed, 24 Jan 2007 18:41:49 +0000 Subject: [PATCH] . First part of the Clipboard UI refactoring ready for AVM node support - Clipboard actions now based on NodeRef not "id" - Added notion of "workspace" and "AVM" specific clipboard items - Clipboard bean supports creating different ClipboardItem types (workspace or avm) . ActionLink parameters are now "toString()"ed rather than assumed String . Optimization to Portal Tree Navigator support git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4924 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- config/alfresco/web-client-config-actions.xml | 30 +--- .../web-client-config-forum-actions.xml | 4 +- .../web/app/servlet/ajax/InvokeCommand.java | 25 ++-- .../web/bean/clipboard/AVMClipboardItem.java | 36 +++++ .../bean/clipboard/AbstractClipboardItem.java | 129 ++++++++++++++++++ .../web/bean/clipboard/ClipboardBean.java | 95 ++++++------- .../web/bean/clipboard/ClipboardItem.java | 57 +++----- .../clipboard/WorkspaceClipboardItem.java | 36 +++++ .../web/ui/common/renderer/BaseRenderer.java | 11 +- .../component/shelf/UIClipboardShelfItem.java | 12 +- 10 files changed, 294 insertions(+), 141 deletions(-) create mode 100644 source/java/org/alfresco/web/bean/clipboard/AVMClipboardItem.java create mode 100644 source/java/org/alfresco/web/bean/clipboard/AbstractClipboardItem.java create mode 100644 source/java/org/alfresco/web/bean/clipboard/WorkspaceClipboardItem.java diff --git a/config/alfresco/web-client-config-actions.xml b/config/alfresco/web-client-config-actions.xml index b071c8c459..5cc8ed411d 100644 --- a/config/alfresco/web-client-config-actions.xml +++ b/config/alfresco/web-client-config-actions.xml @@ -311,7 +311,8 @@ /images/icons/cut.gif #{ClipboardBean.cutNode} - #{actionContext.id} + #{actionContext.nodeRef} + @@ -322,36 +323,11 @@ /images/icons/copy.gif #{ClipboardBean.copyNode} - #{actionContext.id} + #{actionContext.nodeRef} - - - - - - diff --git a/config/alfresco/web-client-config-forum-actions.xml b/config/alfresco/web-client-config-forum-actions.xml index 7416ddd145..562da81a08 100644 --- a/config/alfresco/web-client-config-forum-actions.xml +++ b/config/alfresco/web-client-config-forum-actions.xml @@ -28,7 +28,7 @@ /images/icons/cut.gif #{ClipboardBean.cutNode} - #{actionContext.id} + #{actionContext.nodeRef} @@ -41,7 +41,7 @@ /images/icons/copy.gif #{ClipboardBean.copyNode} - #{actionContext.id} + #{actionContext.nodeRef} diff --git a/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java b/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java index 16bba53def..beb03b1e38 100644 --- a/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java +++ b/source/java/org/alfresco/web/app/servlet/ajax/InvokeCommand.java @@ -42,6 +42,7 @@ import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.web.app.Application; import org.alfresco.web.bean.repository.Repository; /** @@ -98,18 +99,22 @@ public class InvokeCommand extends BaseAjaxCommand // to cover this scenario we have to go through the names of // all the objects in the session to find the bean we want. Object bean = null; - Enumeration enumNames = request.getSession().getAttributeNames(); - while (enumNames.hasMoreElements()) + + if (Application.inPortalServer()) { - String name = (String)enumNames.nextElement(); - if (name.endsWith(variableName)) + Enumeration enumNames = request.getSession().getAttributeNames(); + while (enumNames.hasMoreElements()) { - bean = request.getSession().getAttribute(name); - - if (logger.isDebugEnabled()) - logger.debug("Found bean " + bean + " in the session"); - - break; + String name = (String)enumNames.nextElement(); + if (name.endsWith(variableName)) + { + bean = request.getSession().getAttribute(name); + + if (logger.isDebugEnabled()) + logger.debug("Found bean " + bean + " in the session"); + + break; + } } } diff --git a/source/java/org/alfresco/web/bean/clipboard/AVMClipboardItem.java b/source/java/org/alfresco/web/bean/clipboard/AVMClipboardItem.java new file mode 100644 index 0000000000..982f2cfdb4 --- /dev/null +++ b/source/java/org/alfresco/web/bean/clipboard/AVMClipboardItem.java @@ -0,0 +1,36 @@ +/* + * 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.bean.clipboard; + +import org.alfresco.service.cmr.repository.NodeRef; + +/** + * Class representing an 'avm' store protocol clipboard item + * + * @author Kevin Roast + */ +public class AVMClipboardItem extends AbstractClipboardItem +{ + /** + * @param ref + * @param mode + */ + public AVMClipboardItem(NodeRef ref, ClipboardStatus mode) + { + super(ref, mode); + } +} diff --git a/source/java/org/alfresco/web/bean/clipboard/AbstractClipboardItem.java b/source/java/org/alfresco/web/bean/clipboard/AbstractClipboardItem.java new file mode 100644 index 0000000000..61d3607e9d --- /dev/null +++ b/source/java/org/alfresco/web/bean/clipboard/AbstractClipboardItem.java @@ -0,0 +1,129 @@ +/* + * 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.bean.clipboard; + +import javax.faces.context.FacesContext; + +import org.alfresco.model.ApplicationModel; +import org.alfresco.model.ContentModel; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.namespace.QName; +import org.alfresco.web.bean.repository.Node; +import org.alfresco.web.bean.repository.Repository; + +/** + * Base class representing a single item added to the clipboard. + * + * @author Kevin Roast + */ +abstract class AbstractClipboardItem implements ClipboardItem +{ + /** + * Constructor + * + * @param ref The ref of the item on the clipboard + * @param mode The ClipboardStatus enum value + */ + public AbstractClipboardItem(NodeRef ref, ClipboardStatus mode) + { + this.ref = ref; + this.mode = mode; + } + + public ClipboardStatus getMode() + { + return this.mode; + } + + public String getName() + { + if (this.name == null) + { + this.name = (String)getNodeService().getProperty(this.ref, ContentModel.PROP_NAME); + } + return this.name; + } + + public QName getType() + { + if (this.type == null) + { + this.type = getNodeService().getType(this.ref); + } + return this.type; + } + + public String getIcon() + { + if (this.icon == null) + { + this.icon = (String)getNodeService().getProperty(this.ref, ApplicationModel.PROP_ICON); + } + return this.icon; + } + + public String getId() + { + return this.ref.getId(); + } + + public NodeRef getNodeRef() + { + return this.ref; + } + + /** + * Override equals() to compare NodeRefs + */ + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + if (obj instanceof ClipboardItem) + { + return ((ClipboardItem)obj).getNodeRef().equals(this.ref); + } + else + { + return false; + } + } + + /** + * Override hashCode() to use the internal NodeRef hashcode instead + */ + public int hashCode() + { + return ref.hashCode(); + } + + protected static NodeService getNodeService() + { + return Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getNodeService(); + } + + protected NodeRef ref; + protected ClipboardStatus mode; + + // cached values + private String name; + private QName type; + private String icon; +} diff --git a/source/java/org/alfresco/web/bean/clipboard/ClipboardBean.java b/source/java/org/alfresco/web/bean/clipboard/ClipboardBean.java index a491670828..0bbc6fa6bc 100644 --- a/source/java/org/alfresco/web/bean/clipboard/ClipboardBean.java +++ b/source/java/org/alfresco/web/bean/clipboard/ClipboardBean.java @@ -17,7 +17,6 @@ package org.alfresco.web.bean.clipboard; import java.io.Serializable; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -37,16 +36,15 @@ import org.alfresco.service.cmr.model.FileExistsException; import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.cmr.repository.CopyService; -import org.alfresco.service.cmr.repository.InvalidNodeRefException; 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.search.QueryParameterDefinition; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.namespace.QName; import org.alfresco.web.app.Application; import org.alfresco.web.app.context.UIContextService; import org.alfresco.web.bean.NavigationBean; -import org.alfresco.web.bean.repository.Node; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.UIActionLink; @@ -128,10 +126,10 @@ public class ClipboardBean { UIActionLink link = (UIActionLink)event.getComponent(); Map params = link.getParameterMap(); - String id = params.get("id"); - if (id != null && id.length() != 0) + String ref = params.get("ref"); + if (ref != null && ref.length() != 0) { - addClipboardNode(id, ClipboardStatus.COPY); + addClipboardNode(new NodeRef(ref), ClipboardStatus.COPY); } } @@ -142,10 +140,10 @@ public class ClipboardBean { UIActionLink link = (UIActionLink)event.getComponent(); Map params = link.getParameterMap(); - String id = params.get("id"); - if (id != null && id.length() != 0) + String ref = params.get("ref"); + if (ref != null && ref.length() != 0) { - addClipboardNode(id, ClipboardStatus.CUT); + addClipboardNode(new NodeRef(ref), ClipboardStatus.CUT); } } @@ -195,7 +193,7 @@ public class ClipboardBean for (int i=0; i props = new HashMap(2, 1.0f); props.put(ContentModel.PROP_NAME, name + ".lnk"); - props.put(ContentModel.PROP_LINK_DESTINATION, item.Node.getNodeRef()); - if (dd.isSubClass(item.Node.getType(), ContentModel.TYPE_CONTENT)) + props.put(ContentModel.PROP_LINK_DESTINATION, item.getNodeRef()); + if (dd.isSubClass(item.getType(), ContentModel.TYPE_CONTENT)) { // create File Link node ChildAssociationRef childRef = this.nodeService.createNode( @@ -320,21 +318,21 @@ public class ClipboardBean { // COPY operation if (logger.isDebugEnabled()) - logger.debug("Attempting to copy node ID: " + item.Node.getId() + " into node ID: " + destRef.getId()); + logger.debug("Attempting to copy node ID: " + item.getId() + " into node ID: " + destRef.getId()); - if (dd.isSubClass(item.Node.getType(), ContentModel.TYPE_CONTENT) || - dd.isSubClass(item.Node.getType(), ContentModel.TYPE_FOLDER)) + if (dd.isSubClass(item.getType(), ContentModel.TYPE_CONTENT) || + dd.isSubClass(item.getType(), ContentModel.TYPE_FOLDER)) { // copy the file/folder // first check that we are not attempting to copy a duplicate into the same parent - if (destRef.equals(assocRef.getParentRef()) && name.equals(item.Node.getName())) + if (destRef.equals(assocRef.getParentRef()) && name.equals(item.getName())) { // manually change the name if this occurs String copyOf = Application.getMessage(FacesContext.getCurrentInstance(), MSG_COPY_OF); name = copyOf + ' ' + name; } this.fileFolderService.copy( - item.Node.getNodeRef(), + item.getNodeRef(), destRef, name); } @@ -344,7 +342,7 @@ public class ClipboardBean if (checkExists(name, destRef) == false) { this.copyService.copy( - item.Node.getNodeRef(), + item.getNodeRef(), destRef, ContentModel.ASSOC_CONTAINS, assocRef.getQName(), @@ -360,14 +358,14 @@ public class ClipboardBean { // MOVE operation if (logger.isDebugEnabled()) - logger.debug("Attempting to move node ID: " + item.Node.getId() + " into node ID: " + destRef.getId()); + logger.debug("Attempting to move node ID: " + item.getId() + " into node ID: " + destRef.getId()); - if (dd.isSubClass(item.Node.getType(), ContentModel.TYPE_CONTENT) || - dd.isSubClass(item.Node.getType(), ContentModel.TYPE_FOLDER)) + if (dd.isSubClass(item.getType(), ContentModel.TYPE_CONTENT) || + dd.isSubClass(item.getType(), ContentModel.TYPE_FOLDER)) { // move the file/folder this.fileFolderService.move( - item.Node.getNodeRef(), + item.getNodeRef(), destRef, name); } @@ -375,7 +373,7 @@ public class ClipboardBean { // move the node this.nodeService.moveNode( - item.Node.getNodeRef(), + item.getNodeRef(), destRef, ContentModel.ASSOC_CONTAINS, assocRef.getQName()); @@ -387,7 +385,7 @@ public class ClipboardBean } catch (FileExistsException fileExistsErr) { - if (item.Mode != ClipboardStatus.COPY) + if (item.getMode() != ClipboardStatus.COPY) { // we should not rename an item when it is being moved - so exit throw fileExistsErr; @@ -439,27 +437,32 @@ public class ClipboardBean return (nodeRefs.size() != 0); } - /** Shallow search for nodes with a name pattern */ - private static final String XPATH_QUERY_NODE_MATCH = - "./*" + - "[like(@cm:name, $cm:name, false)]";// + - //" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" + - //" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "'))]"; - /** * Add a clipboard node for an operation to the clipboard * - * @param id ID of the node for the operation + * @param ref NodeRef of the item for the operation * @param mode ClipboardStatus for the operation */ - private void addClipboardNode(String id, ClipboardStatus mode) + private void addClipboardNode(NodeRef ref, ClipboardStatus mode) { - try + // construct item based on store protocol + ClipboardItem item = null; + if (StoreRef.PROTOCOL_WORKSPACE.equals(ref.getStoreRef().getProtocol())) + { + item = new WorkspaceClipboardItem(ref, mode); + } + else if (StoreRef.PROTOCOL_AVM.equals(ref.getStoreRef().getProtocol())) + { + item = new AVMClipboardItem(ref, mode); + } + else + { + logger.warn("Unable to add item to clipboard - unknown store protocol: " + ref.getStoreRef().getProtocol()); + } + + if (item != null) { - NodeRef ref = new NodeRef(Repository.getStoreRef(), id); - // check for duplicates first - ClipboardItem item = new ClipboardItem(new Node(ref), mode); boolean foundDuplicate = false; for (int i=0; i"); - if (item.Mode == ClipboardStatus.COPY) + if (item.getMode() == ClipboardStatus.COPY) { out.write(Utils.buildImageTag(context, WebResources.IMAGE_COPY, 14, 16, bundle.getString(MSG_COPY), null, "absmiddle")); } @@ -170,10 +170,10 @@ public class UIClipboardShelfItem extends UIShelfItem } out.write(""); - if (dd.isSubClass(item.Node.getType(), ContentModel.TYPE_FOLDER)) + if (dd.isSubClass(item.getType(), ContentModel.TYPE_FOLDER)) { // start row with correct node icon - String icon = (String)item.Node.getProperties().get("app:icon"); + String icon = (String)item.getIcon(); if (icon != null) { icon = "/images/icons/" + icon + "-16.gif"; @@ -186,21 +186,21 @@ public class UIClipboardShelfItem extends UIShelfItem } else { - String image = Utils.getFileTypeImage(item.Node.getName(), true); + String image = Utils.getFileTypeImage(item.getName(), true); out.write(Utils.buildImageTag(context, image, null, "absmiddle")); } // output cropped item label - we also output with no breaks, this is ok // as the copped label will ensure a sensible maximum width out.write(" "); - out.write(Utils.cropEncode(item.Node.getName())); + out.write(Utils.cropEncode(item.getName())); // output actions out.write(""); out.write(buildActionLink(ACTION_REMOVE_ITEM, i, bundle.getString(MSG_REMOVE_ITEM), WebResources.IMAGE_REMOVE)); out.write(" "); out.write(buildActionLink(ACTION_PASTE_ITEM, i, bundle.getString(MSG_PASTE_ITEM), WebResources.IMAGE_PASTE)); - if (item.Mode == ClipboardStatus.COPY && dd.isSubClass(item.Node.getType(), ContentModel.TYPE_LINK) == false) + if (item.getMode() == ClipboardStatus.COPY && dd.isSubClass(item.getType(), ContentModel.TYPE_LINK) == false) { out.write(" "); out.write(buildActionLink(ACTION_PASTE_LINK, i, bundle.getString(MSG_PASTE_LINK), WebResources.IMAGE_PASTE_LINK));