/** * Copyright (C) 2009 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.navigation.webui.component; import java.util.Collection; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.exoplatform.navigation.webui.TreeNode; import org.exoplatform.portal.application.PortalRequestContext; import org.exoplatform.portal.config.UserACL; import org.exoplatform.portal.config.UserPortalConfigService; import org.exoplatform.portal.config.model.Page; import org.exoplatform.portal.mop.Described.State; import org.exoplatform.portal.mop.SiteKey; import org.exoplatform.portal.mop.Visibility; import org.exoplatform.portal.mop.description.DescriptionService; import org.exoplatform.portal.mop.navigation.NavigationError; import org.exoplatform.portal.mop.navigation.NavigationServiceException; import org.exoplatform.portal.mop.navigation.Scope; import org.exoplatform.portal.mop.page.PageContext; import org.exoplatform.portal.mop.page.PageKey; import org.exoplatform.portal.mop.page.PageService; import org.exoplatform.portal.mop.user.UserNavigation; import org.exoplatform.portal.mop.user.UserNode; import org.exoplatform.portal.mop.user.UserNodeFilterConfig; import org.exoplatform.portal.mop.user.UserPortal; import org.exoplatform.portal.webui.page.UIPage; import org.exoplatform.portal.webui.portal.UIPortalComposer; import org.exoplatform.portal.webui.util.PortalDataMapper; import org.exoplatform.portal.webui.util.Util; import org.exoplatform.portal.webui.workspace.UIEditInlineWorkspace; import org.exoplatform.portal.webui.workspace.UIPortalApplication; import org.exoplatform.portal.webui.workspace.UIPortalToolPanel; import org.exoplatform.portal.webui.workspace.UIWorkingWorkspace; import org.exoplatform.portal.webui.workspace.UIPortalApplication.ComponentTab; import org.exoplatform.portal.webui.workspace.UIPortalApplication.EditLevel; import org.exoplatform.web.application.ApplicationMessage; import org.exoplatform.webui.application.WebuiRequestContext; import org.exoplatform.webui.config.annotation.ComponentConfig; import org.exoplatform.webui.config.annotation.ComponentConfigs; import org.exoplatform.webui.config.annotation.EventConfig; import org.exoplatform.webui.core.UIApplication; import org.exoplatform.webui.core.UIComponent; import org.exoplatform.webui.core.UIContainer; import org.exoplatform.webui.core.UIPopupWindow; import org.exoplatform.webui.core.UIRightClickPopupMenu; import org.exoplatform.webui.core.UITree; import org.exoplatform.webui.event.Event; import org.exoplatform.webui.event.Event.Phase; import org.exoplatform.webui.event.EventListener; import org.gatein.common.util.ParameterValidation; /** Copied by The eXo Platform SARL Author May 28, 2009 3:07:15 PM */ @ComponentConfigs({ @ComponentConfig(template = "system:/groovy/portal/webui/navigation/UINavigationNodeSelector.gtmpl", events = { @EventConfig(listeners = UINavigationNodeSelector.ChangeNodeActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.NodeModifiedActionListener.class) }), @ComponentConfig(id = "NavigationNodePopupMenu", type = UIRightClickPopupMenu.class, template = "system:/groovy/webui/core/UIRightClickPopupMenu.gtmpl", events = { @EventConfig(listeners = UINavigationNodeSelector.AddNodeActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.EditPageNodeActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.EditSelectedNodeActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.CopyNodeActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.CutNodeActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.CloneNodeActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.PasteNodeActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.MoveUpActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.MoveDownActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.DeleteNodeActionListener.class, confirm = "UIPageNodeSelector.deleteNavigation") }), @ComponentConfig(id = "UINavigationNodeSelectorPopupMenu", type = UIRightClickPopupMenu.class, template = "system:/groovy/webui/core/UIRightClickPopupMenu.gtmpl", events = { @EventConfig(listeners = UINavigationNodeSelector.AddNodeActionListener.class), @EventConfig(listeners = UINavigationNodeSelector.PasteNodeActionListener.class) }) }) public class UINavigationNodeSelector extends UIContainer { private UserNavigation edittedNavigation; /** * This field holds transient copy of edittedTreeNodeData, which is used when user pastes the content to a new tree node */ private TreeNode copyOfTreeNodeData; private TreeNode rootNode; private UserPortal userPortal; private UserNodeFilterConfig filterConfig; private Map<String, Map<Locale, State>> userNodeLabels; private static final Scope DEFAULT_SCOPE = Scope.GRANDCHILDREN; private Scope navigationScope = DEFAULT_SCOPE; public UINavigationNodeSelector() throws Exception { UIRightClickPopupMenu rightClickPopup = addChild(UIRightClickPopupMenu.class, "UINavigationNodeSelectorPopupMenu", null) .setRendered(true); rightClickPopup.setActions(new String[] { "AddNode", "PasteNode" }); UITree uiTree = addChild(UITree.class, null, "TreeNodeSelector"); uiTree.setIcon("DefaultPageIcon"); uiTree.setSelectedIcon("DefaultPageIcon"); uiTree.setBeanIdField("Id"); uiTree.setBeanChildCountField("childrenCount"); uiTree.setBeanLabelField("encodedResolvedLabel"); uiTree.setBeanIconField("icon"); UIRightClickPopupMenu uiPopupMenu = createUIComponent(UIRightClickPopupMenu.class, "NavigationNodePopupMenu", null); uiPopupMenu.setActions(new String[] { "AddNode", "EditPageNode", "EditSelectedNode", "CopyNode", "CloneNode", "CutNode", "DeleteNode", "MoveUp", "MoveDown" }); uiTree.setUIRightClickPopupMenu(uiPopupMenu); userNodeLabels = new HashMap<String, Map<Locale, State>>(); } public void setUserNodeLabels(Map<String, Map<Locale, State>> labels) { this.userNodeLabels = labels; } public Map<String, Map<Locale, State>> getUserNodeLabels() { return this.userNodeLabels; } /** * Init the UITree wrapped in UINavigationNodeSelector * * @throws Exception */ public void initTreeData() throws Exception { if (edittedNavigation == null || userPortal == null) { throw new IllegalStateException("edittedNavigation and userPortal must be initialized first"); } try { this.rootNode = new TreeNode(edittedNavigation, userPortal.getNode(edittedNavigation, navigationScope, filterConfig, null)); TreeNode node = this.rootNode; if (this.rootNode.getChildren().size() > 0) { node = rebaseNode(this.rootNode.getChild(0), navigationScope); if (node == null) { initTreeData(); return; } } selectNode(node); } catch (Exception ex) { // Navigation deleted --> close the editor this.rootNode = null; WebuiRequestContext context = WebuiRequestContext.getCurrentInstance(); context.getUIApplication().addMessage( new ApplicationMessage("UINavigationNodeSelector.msg." + NavigationError.NAVIGATION_NO_SITE.name(), null, ApplicationMessage.ERROR)); UIPopupWindow popup = getAncestorOfType(UIPopupWindow.class); popup.createEvent("ClosePopup", Phase.PROCESS, context).broadcast(); PortalRequestContext prContext = Util.getPortalRequestContext(); UIWorkingWorkspace uiWorkingWS = Util.getUIPortalApplication().getChild(UIWorkingWorkspace.class); prContext.addUIComponentToUpdateByAjax(uiWorkingWS); prContext.setFullRender(true); } } public TreeNode selectNode(TreeNode node) { if (node == null) { return null; } UITree tree = getChild(UITree.class); tree.setSelected(node); if (node.getId().equals(rootNode.getId())) { tree.setChildren(null); tree.setSibbling(node.getChildren()); tree.setParentSelected(node); } else { TreeNode parentNode = node.getParent(); tree.setChildren(node.getChildren()); tree.setSibbling(parentNode.getChildren()); tree.setParentSelected(parentNode); } return node; } public TreeNode rebaseNode(TreeNode treeNode, Scope scope) { if (treeNode == null || treeNode.getNode() == null) { return null; } UserNode userNode = treeNode.getNode(); if (userNode.getId() == null) { // Transient node return treeNode; } userPortal.rebaseNode(userNode, scope, getRootNode()); // this line return null if node has been deleted return findNode(treeNode.getId()); } public void save() { WebuiRequestContext context = WebuiRequestContext.getCurrentInstance(); try { userPortal.saveNode(getRootNode().getNode(), getRootNode()); DescriptionService descriptionService = getApplicationComponent(DescriptionService.class); Map<String, Map<Locale, State>> i18nizedLabels = this.userNodeLabels; for (String treeNodeId : i18nizedLabels.keySet()) { TreeNode node = findNode(treeNodeId); if (node != null) { Map<Locale, State> labels = i18nizedLabels.get(treeNodeId); if (labels != null && labels.size() > 0) { descriptionService.setDescriptions(node.getNode().getId(), labels); } } } } catch (NavigationServiceException ex) { context.getUIApplication().addMessage( new ApplicationMessage("UINavigationNodeSelector.msg." + ex.getError().name(), null, ApplicationMessage.ERROR)); } } public TreeNode getCopyNode() { return copyOfTreeNodeData; } public void setCopyNode(TreeNode copyNode) { this.copyOfTreeNodeData = copyNode; } public TreeNode getRootNode() { return rootNode; } public void setUserPortal(UserPortal userPortal) { this.userPortal = userPortal; setFilterConfig(UserNodeFilterConfig.builder().withReadWriteCheck().build()); } private void setFilterConfig(UserNodeFilterConfig config) { this.filterConfig = config; } public void setEdittedNavigation(UserNavigation nav) { this.edittedNavigation = nav; } public UserNavigation getEdittedNavigation() { return this.edittedNavigation; } public TreeNode findNode(String nodeID) { if (getRootNode() == null) { return null; } return getRootNode().findNode(nodeID); } public void setScope(Scope scope) { this.navigationScope = scope; } public Scope getScope() { return this.navigationScope; } private void invokeI18NizedLabels(TreeNode node) { DescriptionService descriptionService = this.getApplicationComponent(DescriptionService.class); try { Map<Locale, State> labels = descriptionService.getDescriptions(node.getId()); node.setI18nizedLabels(labels); } catch (NullPointerException npe) { // set label list is null if Described mixin has been removed or not exists. node.setI18nizedLabels(null); } } public abstract static class BaseActionListener<T> extends EventListener<T> { protected TreeNode rebaseNode(TreeNode node, UINavigationNodeSelector selector) throws Exception { return rebaseNode(node, selector.getScope(), selector); } protected TreeNode rebaseNode(TreeNode node, Scope scope, UINavigationNodeSelector selector) throws Exception { WebuiRequestContext context = WebuiRequestContext.getCurrentInstance(); TreeNode rebased = selector.rebaseNode(node, scope); if (rebased == null) { selector.getUserNodeLabels().remove(node.getId()); context.getUIApplication().addMessage( new ApplicationMessage("UINavigationNodeSelector.msg.staleData", null, ApplicationMessage.WARNING)); selector.selectNode(selector.getRootNode()); context.addUIComponentToUpdateByAjax(selector); } return rebased; } protected void handleError(NavigationError error, UINavigationNodeSelector selector) throws Exception { selector.initTreeData(); selector.getUserNodeLabels().clear(); if (selector.getRootNode() != null) { WebuiRequestContext context = WebuiRequestContext.getCurrentInstance(); UIApplication uiApp = context.getUIApplication(); uiApp.addMessage(new ApplicationMessage("UINavigationNodeSelector.msg." + error.name(), null, ApplicationMessage.ERROR)); } } } public static class ChangeNodeActionListener extends BaseActionListener<UITree> { public void execute(Event<UITree> event) throws Exception { WebuiRequestContext context = event.getRequestContext(); UINavigationNodeSelector uiNodeSelector = event.getSource().getParent(); String nodeID = context.getRequestParameter(OBJECTID); TreeNode node = uiNodeSelector.findNode(nodeID); try { node = rebaseNode(node, uiNodeSelector); } catch (NavigationServiceException ex) { handleError(ex.getError(), uiNodeSelector); return; } uiNodeSelector.selectNode(node); context.addUIComponentToUpdateByAjax(uiNodeSelector); } } public static class AddNodeActionListener extends BaseActionListener<UIRightClickPopupMenu> { public void execute(Event<UIRightClickPopupMenu> event) throws Exception { WebuiRequestContext context = event.getRequestContext(); UIRightClickPopupMenu uiPopupMenu = event.getSource(); UINavigationNodeSelector uiNodeSelector = uiPopupMenu.getAncestorOfType(UINavigationNodeSelector.class); String nodeID = context.getRequestParameter(UIComponent.OBJECTID); TreeNode node; if (ParameterValidation.isNullOrEmpty(nodeID)) { node = uiNodeSelector.getSelectedNode(); if (node == null) { node = uiNodeSelector.getRootNode(); } } else { node = uiNodeSelector.findNode(nodeID); } try { node = rebaseNode(node, uiNodeSelector); if (node == null) return; } catch (NavigationServiceException ex) { handleError(ex.getError(), uiNodeSelector); return; } UIPopupWindow uiManagementPopup = uiNodeSelector.getAncestorOfType(UIPopupWindow.class); UIPageNodeForm uiNodeForm = uiManagementPopup.createUIComponent(UIPageNodeForm.class, null, null); uiNodeForm.setValues(null); uiManagementPopup.setUIComponent(uiNodeForm); uiNodeForm.setSelectedParent(node); UserNavigation edittedNavigation = uiNodeSelector.getEdittedNavigation(); uiNodeForm.setContextPageNavigation(edittedNavigation); uiManagementPopup.setWindowSize(800, 500); event.getRequestContext().addUIComponentToUpdateByAjax(uiManagementPopup.getParent()); } } public static class NodeModifiedActionListener extends BaseActionListener<UINavigationNodeSelector> { @Override public void execute(Event<UINavigationNodeSelector> event) throws Exception { UINavigationNodeSelector uiNodeSelector = event.getSource(); try { rebaseNode(uiNodeSelector.getRootNode(), uiNodeSelector); } catch (NavigationServiceException ex) { handleError(ex.getError(), uiNodeSelector); } } } public static class EditPageNodeActionListener extends BaseActionListener<UIRightClickPopupMenu> { public void execute(Event<UIRightClickPopupMenu> event) throws Exception { UIPortalApplication uiApp = Util.getUIPortalApplication(); UIRightClickPopupMenu popupMenu = event.getSource(); UINavigationNodeSelector uiNodeSelector = popupMenu.getAncestorOfType(UINavigationNodeSelector.class); String nodeID = event.getRequestContext().getRequestParameter(UIComponent.OBJECTID); TreeNode node = uiNodeSelector.findNode(nodeID); try { node = rebaseNode(node, uiNodeSelector); if (node == null) return; } catch (NavigationServiceException ex) { handleError(ex.getError(), uiNodeSelector); return; } UserPortalConfigService userService = uiNodeSelector.getApplicationComponent(UserPortalConfigService.class); // get selected page String pageId = node.getPageRef(); PageContext pageContext = (pageId != null) ? userService.getPageService().loadPage(PageKey.parse(pageId)) : null; if (pageContext != null) { UserACL userACL = uiApp.getApplicationComponent(UserACL.class); if (!userACL.hasEditPermission(pageContext)) { uiApp.addMessage(new ApplicationMessage("UIPageBrowser.msg.UserNotPermission", new String[] { pageId }, 1)); return; } uiApp.setDefaultEditMode(ComponentTab.APPLICATIONS, EditLevel.EDIT_PAGE); UIWorkingWorkspace uiWorkingWS = uiApp.getChildById(UIPortalApplication.UI_WORKING_WS_ID); UIPortalToolPanel uiToolPanel = uiWorkingWS.findFirstComponentOfType(UIPortalToolPanel.class).setRendered(true); uiWorkingWS.setRenderedChild(UIEditInlineWorkspace.class); UIPortalComposer portalComposer = uiWorkingWS.findFirstComponentOfType(UIPortalComposer.class) .setRendered(true); portalComposer.setShowControl(true); portalComposer.setEditted(false); portalComposer.setCollapse(false); portalComposer.setId(UIPortalComposer.UIPAGE_EDITOR); portalComposer.setComponentConfig(UIPortalComposer.class, UIPortalComposer.UIPAGE_EDITOR); uiToolPanel.setShowMaskLayer(false); uiToolPanel.setWorkingComponent(UIPage.class, null); UIPage uiPage = (UIPage) uiToolPanel.getUIComponent(); if (pageContext.getState().getDisplayName() == null) pageContext.getState().builder().displayName(node.getLabel()); Page page = userService.getDataStorage().getPage(pageId); pageContext.update(page); // convert Page to UIPage PortalDataMapper.toUIPage(uiPage, page); Util.getPortalRequestContext().addUIComponentToUpdateByAjax(uiWorkingWS); Util.getPortalRequestContext().ignoreAJAXUpdateOnPortlets(true); } else { uiApp.addMessage(new ApplicationMessage("UIPageNodeSelector.msg.notAvailable", null)); } } } public static class EditSelectedNodeActionListener extends BaseActionListener<UIRightClickPopupMenu> { public void execute(Event<UIRightClickPopupMenu> event) throws Exception { WebuiRequestContext context = event.getRequestContext(); UIRightClickPopupMenu popupMenu = event.getSource(); UINavigationNodeSelector uiNodeSelector = popupMenu.getAncestorOfType(UINavigationNodeSelector.class); String nodeID = event.getRequestContext().getRequestParameter(UIComponent.OBJECTID); TreeNode node = uiNodeSelector.findNode(nodeID); try { node = rebaseNode(node, uiNodeSelector); if (node == null) return; } catch (NavigationServiceException ex) { handleError(ex.getError(), uiNodeSelector); return; } UIApplication uiApp = context.getUIApplication(); UserPortalConfigService service = uiApp.getApplicationComponent(UserPortalConfigService.class); String pageId = node.getPageRef(); // Page page = (pageId != null) ? service.getPage(pageId) : null; PageContext page = (pageId != null) ? service.getPageService().loadPage(PageKey.parse(pageId)) : null; if (page != null) { UserACL userACL = uiApp.getApplicationComponent(UserACL.class); if (!userACL.hasPermission(page)) { uiApp.addMessage(new ApplicationMessage("UIPageBrowser.msg.UserNotPermission", new String[] { pageId }, 1)); return; } } if (node.getI18nizedLabels() == null) { uiNodeSelector.invokeI18NizedLabels(node); } UIPopupWindow uiManagementPopup = uiNodeSelector.getAncestorOfType(UIPopupWindow.class); UIPageNodeForm uiNodeForm = uiApp.createUIComponent(UIPageNodeForm.class, null, null); uiManagementPopup.setUIComponent(uiNodeForm); UserNavigation edittedNav = uiNodeSelector.getEdittedNavigation(); uiNodeForm.setContextPageNavigation(edittedNav); uiNodeForm.setValues(node); uiNodeForm.setSelectedParent(node.getParent()); uiManagementPopup.setWindowSize(800, 500); event.getRequestContext().addUIComponentToUpdateByAjax(uiManagementPopup.getParent()); } } public static class CopyNodeActionListener extends BaseActionListener<UIRightClickPopupMenu> { public void execute(Event<UIRightClickPopupMenu> event) throws Exception { WebuiRequestContext context = event.getRequestContext(); UINavigationNodeSelector uiNodeSelector = event.getSource().getAncestorOfType(UINavigationNodeSelector.class); event.getRequestContext().addUIComponentToUpdateByAjax(uiNodeSelector); String nodeID = context.getRequestParameter(UIComponent.OBJECTID); TreeNode node = uiNodeSelector.findNode(nodeID); if (Visibility.SYSTEM.equals(node.getVisibility())) { UIApplication uiApp = context.getUIApplication(); uiApp.addMessage(new ApplicationMessage("UINavigationNodeSelector.msg.systemnode-copyclone", null)); return; } try { node = rebaseNode(node, Scope.ALL, uiNodeSelector); if (node == null) return; } catch (NavigationServiceException ex) { handleError(ex.getError(), uiNodeSelector); return; } node.setDeleteNode(false); if (node.getI18nizedLabels() == null) { uiNodeSelector.invokeI18NizedLabels(node); } uiNodeSelector.setCopyNode(node); event.getSource().setActions( new String[] { "AddNode", "EditPageNode", "EditSelectedNode", "CopyNode", "CloneNode", "CutNode", "PasteNode", "DeleteNode", "MoveUp", "MoveDown" }); } } public static class CutNodeActionListener extends BaseActionListener<UIRightClickPopupMenu> { public void execute(Event<UIRightClickPopupMenu> event) throws Exception { WebuiRequestContext context = event.getRequestContext(); UINavigationNodeSelector uiNodeSelector = event.getSource().getAncestorOfType(UINavigationNodeSelector.class); context.addUIComponentToUpdateByAjax(uiNodeSelector); String nodeID = context.getRequestParameter(UIComponent.OBJECTID); TreeNode node = uiNodeSelector.findNode(nodeID); try { node = rebaseNode(node, Scope.SINGLE, uiNodeSelector); if (node == null) return; } catch (NavigationServiceException ex) { handleError(ex.getError(), uiNodeSelector); return; } if (node != null && Visibility.SYSTEM.equals(node.getVisibility())) { context.getUIApplication().addMessage( new ApplicationMessage("UINavigationNodeSelector.msg.systemnode-move", null)); return; } node.setDeleteNode(true); uiNodeSelector.setCopyNode(node); event.getSource().setActions( new String[] { "AddNode", "EditPageNode", "EditSelectedNode", "CopyNode", "CloneNode", "CutNode", "PasteNode", "DeleteNode", "MoveUp", "MoveDown" }); } } public static class CloneNodeActionListener extends CopyNodeActionListener { public void execute(Event<UIRightClickPopupMenu> event) throws Exception { super.execute(event); UINavigationNodeSelector uiNodeSelector = event.getSource().getAncestorOfType(UINavigationNodeSelector.class); TreeNode currNode = uiNodeSelector.getCopyNode(); String nodeID = event.getRequestContext().getRequestParameter(UIComponent.OBJECTID); if (currNode == null) return; else if (currNode.getId().equals(nodeID)) currNode.setCloneNode(true); if (currNode.getI18nizedLabels() == null) { uiNodeSelector.invokeI18NizedLabels(currNode); } } } public static class PasteNodeActionListener extends BaseActionListener<UIRightClickPopupMenu> { private UINavigationNodeSelector uiNodeSelector; private PageService pageService; public void execute(Event<UIRightClickPopupMenu> event) throws Exception { WebuiRequestContext context = event.getRequestContext(); UIRightClickPopupMenu uiPopupMenu = event.getSource(); uiNodeSelector = uiPopupMenu.getAncestorOfType(UINavigationNodeSelector.class); context.addUIComponentToUpdateByAjax(uiNodeSelector); String nodeID = context.getRequestParameter(UIComponent.OBJECTID); TreeNode targetNode = uiNodeSelector.findNode(nodeID); TreeNode sourceNode = uiNodeSelector.getCopyNode(); if (sourceNode == null) return; try { targetNode = rebaseNode(targetNode, uiNodeSelector); if (targetNode == null) return; } catch (NavigationServiceException ex) { handleError(ex.getError(), uiNodeSelector); return; } if (sourceNode.getId().equals(targetNode.getId())) { context.getUIApplication().addMessage( new ApplicationMessage("UIPageNodeSelector.msg.paste.sameSrcAndDes", null)); return; } if (isExistChild(targetNode, sourceNode)) { context.getUIApplication().addMessage(new ApplicationMessage("UIPageNodeSelector.msg.paste.sameName", null)); return; } if(isExistsInTree(sourceNode, targetNode)) { context.getUIApplication().addMessage(new ApplicationMessage("UIPageNodeSelector.msg.paste.wrongLocation", null, ApplicationMessage.WARNING)); return; } UITree uitree = uiNodeSelector.getChild(UITree.class); UIRightClickPopupMenu popup = uitree.getUIRightClickPopupMenu(); popup.setActions(new String[] { "AddNode", "EditPageNode", "EditSelectedNode", "CopyNode", "CutNode", "CloneNode", "DeleteNode", "MoveUp", "MoveDown" }); uiNodeSelector.setCopyNode(null); if (uiNodeSelector.findNode(sourceNode.getId()) == null) { context.getUIApplication().addMessage( new ApplicationMessage("UINavigationNodeSelector.msg.copiedNode.deleted", null, ApplicationMessage.WARNING)); uiNodeSelector.selectNode(uiNodeSelector.getRootNode()); return; } if (sourceNode.isDeleteNode()) { targetNode.addChild(sourceNode); uiNodeSelector.selectNode(targetNode); return; } pageService = uiNodeSelector.getApplicationComponent(PageService.class); pasteNode(sourceNode, targetNode, sourceNode.isCloneNode()); uiNodeSelector.selectNode(targetNode); } private TreeNode pasteNode(TreeNode sourceNode, TreeNode parent, boolean isClone) throws Exception { TreeNode node = parent.addChild(sourceNode.getName()); node.setLabel(sourceNode.getLabel()); node.setVisibility(sourceNode.getVisibility()); node.setIcon(sourceNode.getIcon()); node.setStartPublicationTime(sourceNode.getStartPublicationTime()); node.setEndPublicationTime(sourceNode.getEndPublicationTime()); if (isClone) { String pageName = "page" + node.hashCode(); node.setPageRef(clonePageFromNode(sourceNode, pageName, sourceNode.getPageNavigation().getKey())); } else { node.setPageRef(sourceNode.getPageRef()); } for (TreeNode child : sourceNode.getChildren()) { pasteNode(child, node, isClone); } node.setI18nizedLabels(sourceNode.getI18nizedLabels()); uiNodeSelector.getUserNodeLabels().put(node.getId(), node.getI18nizedLabels()); return node; } private String clonePageFromNode(TreeNode node, String pageName, SiteKey siteKey) { String pageId = node.getPageRef(); if (pageId != null) { PageKey sourceKey = PageKey.parse(pageId); PageContext page = pageService.loadPage(sourceKey); if (page != null) { page = pageService.clone(sourceKey, siteKey.page(pageName)); return page.getKey().format(); } } return null; } private boolean isExistChild(TreeNode parent, TreeNode child) { return parent != null && parent.getChild(child.getName()) != null; } private boolean isExistsInTree(TreeNode parent, TreeNode child) { if(parent == null || child == null) { return false; } TreeNode p = child.getParent(); while (p != null) { if(parent.getId().equals(p.getId())) { return true; } p = p.getParent(); } return false; } } public static class MoveUpActionListener extends BaseActionListener<UIRightClickPopupMenu> { public void execute(Event<UIRightClickPopupMenu> event) throws Exception { moveNode(event, -1); } protected void moveNode(Event<UIRightClickPopupMenu> event, int i) throws Exception { WebuiRequestContext context = event.getRequestContext(); UINavigationNodeSelector uiNodeSelector = event.getSource().getAncestorOfType(UINavigationNodeSelector.class); context.addUIComponentToUpdateByAjax(uiNodeSelector.getParent()); String nodeID = context.getRequestParameter(UIComponent.OBJECTID); TreeNode targetNode = uiNodeSelector.findNode(nodeID); // This happen when browser's not sync with server if (targetNode == null) return; TreeNode parentNode = targetNode.getParent(); try { parentNode = rebaseNode(parentNode, uiNodeSelector); if (parentNode == null) return; // After update the parentNode, maybe targetNode has been deleted or moved TreeNode temp = parentNode.getChild(targetNode.getName()); if (temp == null || !temp.getId().equals(targetNode.getId())) { context.getUIApplication().addMessage( new ApplicationMessage("UINavigationNodeSelector.msg.staleData", null, ApplicationMessage.WARNING)); uiNodeSelector.selectNode(uiNodeSelector.getRootNode()); context.addUIComponentToUpdateByAjax(uiNodeSelector); return; } } catch (NavigationServiceException ex) { handleError(ex.getError(), uiNodeSelector); return; } Collection<TreeNode> children = parentNode.getChildren(); int k; for (k = 0; k < children.size(); k++) { if (parentNode.getChild(k).getId().equals(targetNode.getId())) { break; } } if (k == 0 && i == -1) { return; } if (k == children.size() - 1 && i == 2) { return; } parentNode.addChild(k + i, targetNode); // These lines help to refresh the tree TreeNode selectedNode = uiNodeSelector.getSelectedNode(); uiNodeSelector.selectNode(parentNode); uiNodeSelector.selectNode(selectedNode); } } public static class MoveDownActionListener extends UINavigationNodeSelector.MoveUpActionListener { public void execute(Event<UIRightClickPopupMenu> event) throws Exception { super.moveNode(event, 2); } } public static class DeleteNodeActionListener extends EventListener<UIRightClickPopupMenu> { public void execute(Event<UIRightClickPopupMenu> event) throws Exception { WebuiRequestContext pcontext = event.getRequestContext(); UINavigationNodeSelector uiNodeSelector = event.getSource().getAncestorOfType(UINavigationNodeSelector.class); pcontext.addUIComponentToUpdateByAjax(uiNodeSelector); String nodeID = pcontext.getRequestParameter(UIComponent.OBJECTID); TreeNode childNode = uiNodeSelector.findNode(nodeID); if (childNode == null) { return; } TreeNode parentNode = childNode.getParent(); if (Visibility.SYSTEM.equals(childNode.getVisibility())) { UIApplication uiApp = pcontext.getUIApplication(); uiApp.addMessage(new ApplicationMessage("UINavigationNodeSelector.msg.systemnode-delete", null)); return; } uiNodeSelector.getUserNodeLabels().remove(childNode.getId()); parentNode.removeChild(childNode); uiNodeSelector.selectNode(parentNode); } } public TreeNode getSelectedNode() { return getChild(UITree.class).getSelected(); } }