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);
+ }
+ }
+}