diff --git a/ccm-ldn-navigation/pdl/com/arsdigita/london/navigation/portlet/NavigationDirectoryPortlet.pdl b/ccm-ldn-navigation/pdl/com/arsdigita/london/navigation/portlet/NavigationDirectoryPortlet.pdl new file mode 100644 index 000000000..a3872acf9 --- /dev/null +++ b/ccm-ldn-navigation/pdl/com/arsdigita/london/navigation/portlet/NavigationDirectoryPortlet.pdl @@ -0,0 +1,26 @@ +// Copyright (C) 2008 Permeance Technologies Pty Ltd. All Rights Reserved. +// +// This library 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 library 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 library; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +model com.arsdigita.london.navigation.portlet; + +import com.arsdigita.london.navigation.Navigation; +import com.arsdigita.portal.Portlet; + +object type NavigationTreePortlet extends Portlet { + Navigation[1..1] navigation = join portlet_navigation_tree.navigation_id to nav_app.application_id; + Integer[1..1] depth = portlet_navigation_tree.depth INTEGER; + reference key (portlet_navigation_tree.portlet_id); +} \ No newline at end of file diff --git a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/Initializer.java b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/Initializer.java index 7d9a8c4c1..fb18e3559 100755 --- a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/Initializer.java +++ b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/Initializer.java @@ -58,6 +58,7 @@ import com.arsdigita.kernel.ResourceType; import com.arsdigita.kernel.ui.ResourceConfigFormSection; import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.london.navigation.portlet.NavigationTreePortlet; import com.arsdigita.london.navigation.portlet.ObjectListPortlet; import com.arsdigita.london.navigation.portlet.ItemListPortlet; @@ -133,6 +134,9 @@ public class Initializer extends CompoundInitializer { } }); + NavigationTreePortlet.registerInstantiator(); + NavigationTreePortlet.registerResourceTypeConfig(); + e.getFactory().registerInstantiator (ItemListPortlet.BASE_DATA_OBJECT_TYPE, new ACSObjectInstantiator() { diff --git a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/Loader.java b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/Loader.java index 6eb479911..d16c76009 100755 --- a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/Loader.java +++ b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/Loader.java @@ -37,6 +37,7 @@ import com.arsdigita.web.ApplicationType; import com.arsdigita.london.navigation.portlet.ObjectListPortlet; import com.arsdigita.london.navigation.portlet.ItemListPortlet; +import com.arsdigita.london.navigation.portlet.NavigationTreePortlet; import com.arsdigita.portal.PortletType; @@ -74,6 +75,8 @@ public class Loader extends PackageLoader { setupNavigation(); Loader.loadObjectListPortlet(); Loader.loadItemListPortlet(); + NavigationTreePortlet.loadPortletType(); + try { setupTemplates(); @@ -156,7 +159,7 @@ public class Loader extends PackageLoader { public static void loadItemListPortlet() { PortletType type = PortletType - .createPortletType("Object List", + .createPortletType("Navigation Object List", PortletType.WIDE_PROFILE, ObjectListPortlet.BASE_DATA_OBJECT_TYPE); type.setDescription("Displays a list of objects"); @@ -164,7 +167,7 @@ public class Loader extends PackageLoader { public static void loadObjectListPortlet() { PortletType type = PortletType - .createPortletType("Content Item List", + .createPortletType("Navigation Content Item List", PortletType.WIDE_PROFILE, ItemListPortlet.BASE_DATA_OBJECT_TYPE); type.setDescription("Displays a list of content items"); diff --git a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/portlet/NavigationTreePortlet.java b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/portlet/NavigationTreePortlet.java new file mode 100644 index 000000000..097124c37 --- /dev/null +++ b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/portlet/NavigationTreePortlet.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2008 Permeance Technologies Pty Ltd. All Rights Reserved. + * + * This library 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 library 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 library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +package com.arsdigita.london.navigation.portlet; + +import org.apache.log4j.Logger; + +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.portal.AbstractPortletRenderer; +import com.arsdigita.domain.DomainObject; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.kernel.ACSObjectInstantiator; +import com.arsdigita.kernel.ResourceType; +import com.arsdigita.kernel.ResourceTypeConfig; +import com.arsdigita.kernel.ui.ResourceConfigFormSection; +import com.arsdigita.london.navigation.Navigation; +import com.arsdigita.london.navigation.ui.portlet.NavigationTreePortletEditor; +import com.arsdigita.london.navigation.ui.portlet.NavigationTreePortletRenderer; +import com.arsdigita.persistence.DataObject; +import com.arsdigita.portal.Portlet; +import com.arsdigita.portal.PortletType; + +/** + * Displays the navigation tree as the navigation application does and provides + * a way to step into the navigation application presentation system. + * + * Links are provided for each navigation category item if selected (clicked) + * invokes the corresponding navigation index page (and leaves the portal workspace). + * + * In a configuration screen you may select which navigation tree to use and the + * depth categories are exposed. + * + */ +public class NavigationTreePortlet extends Portlet +{ + private static final Logger s_log = Logger.getLogger(NavigationTreePortlet.class); + + public static final String BASE_DATA_OBJECT_TYPE = + "com.arsdigita.london.navigation.portlet.NavigationTreePortlet"; + + public static final String DEPTH = "depth"; + + public static final String NAVIGATION = "navigation"; + + /** + * + */ + public static void loadPortletType() + { + PortletType type = PortletType.createPortletType("Navigation Tree", PortletType.WIDE_PROFILE, + NavigationTreePortlet.BASE_DATA_OBJECT_TYPE); + type.setDescription("Displays a tree of navigation categories"); + s_log.info("Loading portlet type " + type); + } + + /** + * + */ + public static void registerInstantiator() + { + DomainObjectFactory.registerInstantiator(BASE_DATA_OBJECT_TYPE, new ACSObjectInstantiator() + { + public DomainObject doNewInstance(DataObject dataObject) + { + return new NavigationTreePortlet(dataObject); + } + }); + } + + /** + * + */ + public static void registerResourceTypeConfig() + { + new ResourceTypeConfig(BASE_DATA_OBJECT_TYPE) + { + public ResourceConfigFormSection getCreateFormSection(final ResourceType resType, + final RequestLocal parentAppRL) + { + return new NavigationTreePortletEditor(resType, parentAppRL); + } + + public ResourceConfigFormSection getModifyFormSection(final RequestLocal application) + { + return new NavigationTreePortletEditor(application); + } + }; + } + + /** + * + * @param dataObject + */ + public NavigationTreePortlet(DataObject dataObject) + { + super(dataObject); + } + + /** + * + * @param depth + */ + public void setDepth(int depth) + { + set(DEPTH, new Integer(depth)); + } + + /** + * + * @return + */ + public int getDepth() + { + return ((Integer) get(DEPTH)).intValue(); + } + + /** + * + * @return + */ + public Navigation getNavigation() + { + return new Navigation((DataObject) get(NAVIGATION)); + } + + /** + * + * @param navigation + */ + public void setNavigation(Navigation navigation) + { + set(NAVIGATION, navigation); + } + + /** + * + * @return + */ + protected AbstractPortletRenderer doGetPortletRenderer() + { + return new NavigationTreePortletRenderer(this); + } + + /** + * + * @return + */ + protected String getBaseDataObjectType() + { + return BASE_DATA_OBJECT_TYPE; + } +} diff --git a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/portlet/NavigationTreePortletEditor.java b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/portlet/NavigationTreePortletEditor.java new file mode 100644 index 000000000..4f6d2b99e --- /dev/null +++ b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/portlet/NavigationTreePortletEditor.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2008 Permeance Technologies Pty Ltd. All Rights Reserved. + * + * This library 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 library 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 library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +package com.arsdigita.london.navigation.ui.portlet; + +import java.math.BigDecimal; +import java.util.TooManyListenersException; + +import org.apache.log4j.Logger; + +import com.arsdigita.bebop.ColumnPanel; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.portal.PortletConfigFormSection; +import com.arsdigita.bebop.RequestLocal; +import com.arsdigita.bebop.event.PrintEvent; +import com.arsdigita.bebop.event.PrintListener; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.bebop.parameters.BigDecimalParameter; +import com.arsdigita.bebop.parameters.IntegerParameter; +import com.arsdigita.cms.TemplateContext; +import com.arsdigita.domain.DataObjectNotFoundException; +import com.arsdigita.domain.DomainCollection; +import com.arsdigita.domain.DomainObjectFactory; +import com.arsdigita.kernel.ResourceType; +import com.arsdigita.london.navigation.Navigation; +import com.arsdigita.london.navigation.portlet.NavigationTreePortlet; +// @deprecated use com.arsdigita.bebop.portal.PortletConfigFormSection +// import com.arsdigita.london.portal.ui.PortletConfigFormSection; +import com.arsdigita.persistence.OID; +import com.arsdigita.persistence.SessionManager; +import com.arsdigita.portal.Portlet; +import com.arsdigita.util.UncheckedWrapperException; + +/** + * Editor for a {@link NavigationTreePortlet}. + * + * @author terry_permeance + */ +public class NavigationTreePortletEditor extends PortletConfigFormSection +{ + private static final Logger s_log = Logger.getLogger(NavigationTreePortletEditor.class); + + private SingleSelect m_root; + + private SingleSelect m_depth; + + public NavigationTreePortletEditor(ResourceType resType, RequestLocal parentAppRL) + { + super(resType, parentAppRL); + } + + public NavigationTreePortletEditor(RequestLocal application) + { + super(application); + } + + public void addWidgets() + { + super.addWidgets(); + + try + { + m_root = new SingleSelect(new BigDecimalParameter("navigation")); + m_root.addPrintListener(new CategoryPrintListener()); + } + catch (TooManyListenersException ex) + { + throw new UncheckedWrapperException("this cannot happen", ex); + } + + m_depth = new SingleSelect(new IntegerParameter("depth")); + m_depth.addOption(new Option("1", "1 Level")); + m_depth.addOption(new Option("2", "2 Levels")); + + add(new Label("Navigation:", Label.BOLD), ColumnPanel.RIGHT); + add(m_root); + + add(new Label("Depth:", Label.BOLD), ColumnPanel.RIGHT); + add(m_depth); + } + + public void initWidgets(PageState state, Portlet portlet) throws FormProcessException + { + super.initWidgets(state, portlet); + + if (portlet != null) + { + NavigationTreePortlet myportlet = (NavigationTreePortlet) portlet; + + m_root.setValue(state, myportlet.getNavigation().getID()); + m_depth.setValue(state, new Integer(myportlet.getDepth())); + } + } + + public void processWidgets(PageState state, Portlet portlet) throws FormProcessException + { + super.processWidgets(state, portlet); + + NavigationTreePortlet myportlet = (NavigationTreePortlet) portlet; + myportlet.setDepth(((Integer) m_depth.getValue(state)).intValue()); + + BigDecimal id = (BigDecimal) m_root.getValue(state); + try + { + Navigation root = (Navigation) DomainObjectFactory.newInstance(new OID(Navigation.BASE_DATA_OBJECT_TYPE, id)); + myportlet.setNavigation(root); + } + catch (DataObjectNotFoundException ex) + { + throw new UncheckedWrapperException("cannot find category", ex); + } + } + + protected String getUseContext() + { + TemplateContext ctx = Navigation.getContext().getTemplateContext(); + String context = (ctx == null ? null : ctx.getContext()); + return context; + } + + private class CategoryPrintListener implements PrintListener + { + public void prepare(PrintEvent e) + { + SingleSelect target = (SingleSelect) e.getTarget(); + + DomainCollection navigations = new DomainCollection(SessionManager.getSession().retrieve( + Navigation.BASE_DATA_OBJECT_TYPE)); + try + { + while (navigations.next()) + { + Navigation navigation = (Navigation) navigations.getDomainObject(); + target.addOption(new Option(navigation.getID().toString(), navigation.getPath())); + } + } + finally + { + navigations.close(); + } + } + } +} diff --git a/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/portlet/NavigationTreePortletRenderer.java b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/portlet/NavigationTreePortletRenderer.java new file mode 100644 index 000000000..a3a3855b2 --- /dev/null +++ b/ccm-ldn-navigation/src/com/arsdigita/london/navigation/ui/portlet/NavigationTreePortletRenderer.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2008 Permeance Technologies Pty Ltd. All Rights Reserved. + * + * This library 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 library 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 library; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +package com.arsdigita.london.navigation.ui.portlet; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeSet; + +import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.portal.AbstractPortletRenderer; +import com.arsdigita.categorization.Category; +import com.arsdigita.categorization.CategoryCollection; +import com.arsdigita.cms.TemplateContext; +import com.arsdigita.london.navigation.Navigation; +import com.arsdigita.london.navigation.portlet.NavigationTreePortlet; +// import com.arsdigita.london.portal.ui.PortalConstants; +import com.arsdigita.persistence.OID; +import com.arsdigita.web.ParameterMap; +import com.arsdigita.web.URL; +import com.arsdigita.web.Web; +import com.arsdigita.xml.Element; +import com.arsdigita.xml.XML; + +/** + * Renders a {@link NavigationTreePortlet}. + * + * @author terry_permeance + */ +public class NavigationTreePortletRenderer extends AbstractPortletRenderer +{ + // XXX quick hack: keep in Sync with com.arsdigita.london.portal.ui.PortalConstants! + private static final String PORTLET_XML_NS = "http://www.uk.arsdigita.com/portlet/1.0"; + private final NavigationTreePortlet m_portlet; + + /** + * + * @param portlet + */ + public NavigationTreePortletRenderer(NavigationTreePortlet portlet) + { + m_portlet = portlet; + } + + /** + * + * @param state + * @param parent + */ + public void generateBodyXML(PageState state, Element parent) + { + Element element = parent.newChildElement("portlet:contentDirectory", PORTLET_XML_NS); + element.addAttribute("id", getIdAttr()); + + TemplateContext ctx = Navigation.getContext().getTemplateContext(); + String context = (ctx == null ? null : ctx.getContext()); + Category root = Category.getRootForObject(m_portlet.getNavigation(), context); + if (root == null) + { + root = Category.getRootForObject(m_portlet.getNavigation()); + } + if (!root.isEnabled()) + { + return; + } + + CategoryCollection cats = root.getDescendants(); + cats.addEqualsFilter("parents.link.relationType", "child"); + cats.addPath("parents.link.sortKey"); + cats.addPath("parents.id"); + cats.addOrder("parents.link.sortKey"); + + Map children = new HashMap(); + while (cats.next()) + { + Category cat = cats.getCategory(); + BigDecimal parentID = (BigDecimal) cats.get("parents.id"); + + TreeSet childList = (TreeSet) children.get(parentID); + if (childList == null) + { + childList = new TreeSet(); + children.put(parentID, childList); + } + + childList.add(new CategorySortKeyPair(cat, (BigDecimal) cats.get("parents.link.sortKey"))); + } + + processChildren(element, root, children, 1, m_portlet.getDepth()); + } + + /** + * + * @param parent + * @param cat + * @param children + * @param depth + * @param maxDepth + */ + public void processChildren(Element parent, Category cat, Map children, int depth, int maxDepth) + { + if (depth <= maxDepth) + { + TreeSet c = (TreeSet) children.get(cat.getID()); + if (c != null) + { + Iterator i = c.iterator(); + while (i.hasNext()) + { + CategorySortKeyPair pair = (CategorySortKeyPair) i.next(); + Category child = pair.getCategory(); + BigDecimal childSortKey = pair.getSortKey(); + if (child.isEnabled()) + { + Element el = generateCategory(child, depth, childSortKey); + parent.addContent(el); + + processChildren(el, child, children, depth + 1, maxDepth); + } + } + } + } + } + + /** + * + * @param cat + * @param depth + * @param childSortKey + * @return + */ + public Element generateCategory(Category cat, int depth, BigDecimal childSortKey) + { + Element el = new Element(depth == 1 ? "portlet:contentDirectoryEntry" : "portlet:contentDirectorySubentry", + PORTLET_XML_NS); + + el.addAttribute("id", XML.format(cat.getID())); + el.addAttribute("name", cat.getName()); + el.addAttribute("description", cat.getDescription()); + el.addAttribute("isAbstract", cat.isAbstract() ? "1" : "0"); + el.addAttribute("url", redirectURL(cat.getOID())); + el.addAttribute("sortKey", XML.format(childSortKey)); + return el; + } + + /** + * + * @param oid + * @return + */ + public static String redirectURL(OID oid) + { + ParameterMap map = new ParameterMap(); + map.setParameter("oid", oid.toString()); + + URL here = Web.getContext().getRequestURL(); + + return (new URL(here.getScheme(), here.getServerName(), here.getServerPort(), "", "", "/redirect/", map)).toString(); + } + + /** + * + */ + private class CategorySortKeyPair implements Comparable + { + private Category m_category; + + private BigDecimal m_sortKey; + + public CategorySortKeyPair(Category category, BigDecimal sortKey) + { + m_category = category; + m_sortKey = sortKey; + } + + public Category getCategory() + { + return m_category; + } + + public BigDecimal getSortKey() + { + return m_sortKey; + } + + public int compareTo(Object o) + { + return m_sortKey.compareTo(((CategorySortKeyPair) o).m_sortKey); + } + } +}