diff --git a/ccm-portalworkspace/src/com/arsdigita/portalworkspace/ui/admin/CategoryComponent.java b/ccm-portalworkspace/src/com/arsdigita/portalworkspace/ui/admin/CategoryComponent.java index 010381f09..e2bedece5 100755 --- a/ccm-portalworkspace/src/com/arsdigita/portalworkspace/ui/admin/CategoryComponent.java +++ b/ccm-portalworkspace/src/com/arsdigita/portalworkspace/ui/admin/CategoryComponent.java @@ -22,12 +22,14 @@ import org.apache.log4j.Logger; import com.arsdigita.bebop.Label; import com.arsdigita.bebop.PageState; +import com.arsdigita.bebop.RequestLocal; import com.arsdigita.bebop.SimpleContainer; import com.arsdigita.bebop.Tree; import com.arsdigita.bebop.event.ActionEvent; import com.arsdigita.bebop.event.ActionListener; import com.arsdigita.bebop.tree.TreeModel; import com.arsdigita.bebop.tree.TreeModelBuilder; +import com.arsdigita.bebop.tree.TreeNode; import com.arsdigita.categorization.Category; import com.arsdigita.categorization.CategoryTreeModelLite; import com.arsdigita.domain.DomainObjectFactory; @@ -41,16 +43,16 @@ import com.arsdigita.util.Assert; import com.arsdigita.util.LockableImpl; import com.arsdigita.web.Application; import com.arsdigita.web.Web; +import java.util.Iterator; -/** +/** * CategoryComponent. - * + * * @version $Id: CategoryComponent.java 1174 2006-06-14 14:14:15Z fabrice $ */ public class CategoryComponent extends SimpleContainer { - private static final Logger s_log = Logger - .getLogger(CategoryComponent.class); + private static final Logger s_log = Logger.getLogger(CategoryComponent.class); private ACSObjectSelectionModel m_catModel; private CategoryTree m_tree; private ApplicationSelectionModel m_appModel; @@ -59,34 +61,27 @@ public class CategoryComponent extends SimpleContainer { private static final Category m_root = Category.getRootForObject(m_app); /** - * - * @param appModel + * + * @param appModel */ public CategoryComponent(ApplicationSelectionModel appModel) { - // this model means that the server needs a restart - // if you want to map a category to this personal portal - // AND vice versa - if you remove a domain mapping you need to - // restart the server otherwise you will get an exception next time - // this Component is viewed. - if (m_root != null) { - setNamespace(WorkspacePage.PORTAL_XML_NS); - setTag("portal:categoryPanel"); + setNamespace(WorkspacePage.PORTAL_XML_NS); + setTag("portal:categoryPanel"); - m_appModel = appModel; + m_appModel = appModel; - m_catModel = new ACSObjectSelectionModel("category"); - m_tree = new CategoryTree(m_catModel); + m_catModel = new ACSObjectSelectionModel("category"); + m_tree = new CategoryTree(m_catModel); - add(m_tree); - add(new CategoryTable(appModel, m_catModel)); + add(m_tree); + add(new CategoryTable(appModel, m_catModel)); - m_error = new Label(""); - add(m_error); - } + m_error = new Label(""); + add(m_error); } /** - * + * */ private class CategoryTree extends Tree { @@ -99,7 +94,7 @@ public class CategoryComponent extends SimpleContainer { } /** - * + * */ private class CategoryTreeActionListener implements ActionListener { @@ -115,11 +110,11 @@ public class CategoryComponent extends SimpleContainer { s_log.debug("action performed"); if (m_catModel.isSelected(state)) { Category category = (Category) m_catModel - .getSelectedObject(state); + .getSelectedObject(state); // Make sure that other workspaces aren't already categorized DataCollection workspaces = SessionManager.getSession() - .retrieve(Workspace.BASE_DATA_OBJECT_TYPE); + .retrieve(Workspace.BASE_DATA_OBJECT_TYPE); Filter f = workspaces.addInSubqueryFilter("id", "com.arsdigita.categorization.immediateChildObjectIDs"); @@ -129,16 +124,16 @@ public class CategoryComponent extends SimpleContainer { s_log.debug("About to categorize"); Workspace workspace = (Workspace) m_appModel - .getSelectedObject(state); + .getSelectedObject(state); category.addChild(workspace); category.save(); } else { // print an error while (workspaces.next()) { Workspace wk = (Workspace) DomainObjectFactory - .newInstance(workspaces.getDataObject()); + .newInstance(workspaces.getDataObject()); m_error.setLabel( - "This category already has a workspace " + "This category already has a workspace " + wk.getTitle(), state); } } @@ -150,23 +145,115 @@ public class CategoryComponent extends SimpleContainer { /** * A TreeModelBuilder that loads the tree from the current category */ - private static class SectionTreeModelBuilder extends LockableImpl implements - TreeModelBuilder { + private static class SectionTreeModelBuilder extends LockableImpl implements TreeModelBuilder { + + /** + * A RequestLocal wrapper for the model. It is necessary to wrap the model into a + * {@link RequestLocal} wrapper because the contents of the model may change. Before this + * was introduced the system had be restarted if a new category system was mapped to + * a PortalWorkspace. + */ + final RequestLocal treeModel = new TreeModelRequestLocal(); public SectionTreeModelBuilder() { super(); } + @Override public TreeModel makeModel(Tree t, PageState s) { + return (TreeModel) treeModel.get(s); + + } + + } + + /** + * The RequestLocal used by the {@link SectionTreeModelBuilder}. + */ + private static class TreeModelRequestLocal extends RequestLocal { + + public TreeModelRequestLocal() { + //Nothing + } + + /** + * Provides the initial value for this {@code {RequestLocal}. If a category system + * is mapped to the current PortalWorkspace (the current Application instance), the method + * returns a {@link CategoryTreeModelLite} instance. The {link CategoryTreeModelLite} is + * created using the root category of the mapped category system. + * If there is no mapping the method returns an instance of {@link EmptyTreeModel}. + * + * @param state + * @return + */ + @Override + protected Object initialValue(final PageState state) { Application app = Web.getWebContext().getApplication(); Category root = null; while (app != null && root == null) { root = Category.getRootForObject(app); app = (Application) app.getParentResource(); } - Assert.exists(root, Category.class); - return new CategoryTreeModelLite(root); + + if (root == null) { + return new EmptyTreeModel(); + + } else { + Assert.exists(root, Category.class); + return new CategoryTreeModelLite(root); + } + } } + + /** + * A simple helper class representing an empty tree. + */ + private static class EmptyTreeModel implements TreeModel { + + public EmptyTreeModel() { + //Nothing + } + + @Override + public TreeNode getRoot(final PageState data) { + return new EmptyTreeRootNode(); + } + + @Override + public boolean hasChildren(final TreeNode node, + final PageState state) { + return false; + } + + @Override + public Iterator getChildren(final TreeNode node, + final PageState data) { + return null; + } + + } + + /** + * The root node of an empty tree. + */ + private static class EmptyTreeRootNode implements TreeNode { + + public EmptyTreeRootNode() { + //Nothing + } + + @Override + public Object getKey() { + return "empty"; + } + + @Override + public Object getElement() { + return ""; + } + + } + } diff --git a/ccm-sci-bundle/bundles/devel/cfg/project.xml b/ccm-sci-bundle/bundles/devel/cfg/project.xml index 4be7ec591..f2f4d838c 100644 --- a/ccm-sci-bundle/bundles/devel/cfg/project.xml +++ b/ccm-sci-bundle/bundles/devel/cfg/project.xml @@ -9,7 +9,7 @@ name="ScientificCMS" prettyName="Scientific CMS" version="2.3.0" - release="devel-SNAPSHOT-r2691" + release="devel-SNAPSHOT-r2707" webxml="sci-web.xml" portletxml="sci-portlet.xml" webapp="libreccm"