From: Mathieu Baudier Date: Thu, 16 Jun 2022 07:29:03 +0000 (+0200) Subject: Refactor to use ACR instead of JCR. X-Git-Tag: v2.3.10~185 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=fdf44255df56ae179b904e4ab326bf595674800e;p=lgpl%2Fargeo-commons.git Refactor to use ACR instead of JCR. --- diff --git a/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtUtils.java b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtUtils.java index 3ff747949..784d03173 100644 --- a/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtUtils.java +++ b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/CmsSwtUtils.java @@ -1,7 +1,10 @@ package org.argeo.cms.swt; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; +import java.util.StringTokenizer; import org.argeo.api.cms.CmsStyle; import org.argeo.api.cms.CmsTheme; @@ -272,4 +275,18 @@ public class CmsSwtUtils { for (Control child : composite.getChildren()) child.dispose(); } + + /** Clean reserved URL characters for use in HTTP links. */ + public static String cleanPathForUrl(String path) { + StringTokenizer st = new StringTokenizer(path, "/"); + StringBuilder sb = new StringBuilder(); + while (st.hasMoreElements()) { + sb.append('/'); + String encoded = URLEncoder.encode(st.nextToken(), StandardCharsets.UTF_8); + encoded = encoded.replace("+", "%20"); + sb.append(encoded); + + } + return sb.toString(); + } } diff --git a/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/ContentComposite.java b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/ContentComposite.java new file mode 100644 index 000000000..951889eee --- /dev/null +++ b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/ContentComposite.java @@ -0,0 +1,41 @@ +package org.argeo.cms.swt.acr; + +import org.argeo.api.acr.Content; +import org.argeo.api.acr.spi.ProvidedContent; +import org.eclipse.swt.widgets.Composite; + +/** A composite which can (optionally) manage a content. */ +public class ContentComposite extends Composite { + private static final long serialVersionUID = -1447009015451153367L; + + public ContentComposite(Composite parent, int style, Content item) { + super(parent, style); + setData(item); + } + + public Content getContent() { + return (Content) getData(); + } + + @Deprecated + public Content getNode() { + return getContent(); + } + + protected ProvidedContent getProvidedContent() { + return (ProvidedContent) getContent(); + } + + public String getSessionLocalId() { + return getProvidedContent().getSessionLocalId(); + } + + protected void itemUpdated() { + layout(); + } + + public void setContent(Content content) { + setData(content); + itemUpdated(); + } +} diff --git a/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtSection.java b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtSection.java new file mode 100644 index 000000000..5562bcf4e --- /dev/null +++ b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtSection.java @@ -0,0 +1,159 @@ +package org.argeo.cms.swt.widgets; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.argeo.api.acr.Content; +import org.argeo.cms.swt.CmsSwtUtils; +import org.argeo.cms.swt.acr.ContentComposite; +import org.argeo.cms.ux.widgets.EditablePart; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +/** A structured UI related to a JCR context. */ +public class SwtSection extends ContentComposite { + private static final long serialVersionUID = -5933796173755739207L; + + private final SwtSection parentSection; + private Composite sectionHeader; + private final Integer relativeDepth; + + public SwtSection(Composite parent, int style, Content node) { + this(parent, findSection(parent), style, node); + } + + public SwtSection(SwtSection section, int style, Content node) { + this(section, section, style, node); + } + + protected SwtSection(Composite parent, SwtSection parentSection, int style, Content node) { + super(parent, style, node); + this.parentSection = parentSection; + if (parentSection != null) { + relativeDepth = getProvidedContent().getDepth() - parentSection.getProvidedContent().getDepth(); + } else { + relativeDepth = 0; + } + setLayout(CmsSwtUtils.noSpaceGridLayout()); + } + + public Map getSubSections() { + LinkedHashMap result = new LinkedHashMap(); + for (Control child : getChildren()) { + if (child instanceof Composite) { + collectDirectSubSections((Composite) child, result); + } + } + return Collections.unmodifiableMap(result); + } + + private void collectDirectSubSections(Composite composite, LinkedHashMap subSections) { + if (composite == sectionHeader || composite instanceof EditablePart) + return; + if (composite instanceof SwtSection) { + SwtSection section = (SwtSection) composite; + subSections.put(section.getProvidedContent().getSessionLocalId(), section); + return; + } + + for (Control child : composite.getChildren()) + if (child instanceof Composite) + collectDirectSubSections((Composite) child, subSections); + } + + public Composite createHeader() { + return createHeader(this); + } + + public Composite createHeader(Composite parent) { + if (sectionHeader != null) + sectionHeader.dispose(); + + sectionHeader = new Composite(parent, SWT.NONE); + sectionHeader.setLayoutData(CmsSwtUtils.fillWidth()); + sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout()); + // sectionHeader.moveAbove(null); + // layout(); + return sectionHeader; + } + + public Composite getHeader() { + if (sectionHeader != null && sectionHeader.isDisposed()) + sectionHeader = null; + return sectionHeader; + } + + // SECTION PARTS + public SwtSectionPart getSectionPart(String partId) { + for (Control child : getChildren()) { + if (child instanceof SwtSectionPart) { + SwtSectionPart sectionPart = (SwtSectionPart) child; + if (sectionPart.getPartId().equals(partId)) + return sectionPart; + } + } + return null; + } + + public SwtSectionPart nextSectionPart(SwtSectionPart sectionPart) { + Control[] children = getChildren(); + for (int i = 0; i < children.length; i++) { + if (sectionPart == children[i]) { + for (int j = i + 1; j < children.length; j++) { + if (children[i + 1] instanceof SwtSectionPart) { + return (SwtSectionPart) children[i + 1]; + } + } + +// if (i + 1 < children.length) { +// Composite next = (Composite) children[i + 1]; +// return (SectionPart) next; +// } else { +// // next section +// } + } + } + return null; + } + + public SwtSectionPart previousSectionPart(SwtSectionPart sectionPart) { + Control[] children = getChildren(); + for (int i = 0; i < children.length; i++) { + if (sectionPart == children[i]) + if (i != 0) { + Composite previous = (Composite) children[i - 1]; + return (SwtSectionPart) previous; + } else { + // previous section + } + } + return null; + } + + @Override + public String toString() { + if (parentSection == null) + return "Main section " + getContent(); + return "Section " + getContent(); + } + + public SwtSection getParentSection() { + return parentSection; + } + + public Integer getRelativeDepth() { + return relativeDepth; + } + + /** Recursively finds the related section in the parents (can be itself) */ + public static SwtSection findSection(Control control) { + if (control == null) + return null; + if (control instanceof SwtSection) + return (SwtSection) control; + else + return findSection(control.getParent()); + } +} diff --git a/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtSectionPart.java b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtSectionPart.java new file mode 100644 index 000000000..e0578609e --- /dev/null +++ b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtSectionPart.java @@ -0,0 +1,11 @@ +package org.argeo.cms.swt.widgets; + +import org.argeo.cms.ux.widgets.ContentPart; +import org.argeo.cms.ux.widgets.EditablePart; + +/** An editable part dynamically related to a Section */ +public interface SwtSectionPart extends EditablePart, ContentPart { + public String getPartId(); + + public SwtSection getSection(); +} diff --git a/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtTabbedArea.java b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtTabbedArea.java new file mode 100644 index 000000000..a2f7671c0 --- /dev/null +++ b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/SwtTabbedArea.java @@ -0,0 +1,259 @@ +package org.argeo.cms.swt.widgets; + +import java.util.ArrayList; +import java.util.List; + +import org.argeo.api.acr.Content; +import org.argeo.api.acr.spi.ProvidedContent; +import org.argeo.cms.swt.CmsSwtUtils; +import org.argeo.cms.swt.Selected; +import org.argeo.cms.swt.acr.SwtUiProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StackLayout; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; + +/** Manages {@link SwtSection} in a tab-like structure. */ +public class SwtTabbedArea extends Composite { + private static final long serialVersionUID = 8659669229482033444L; + + private Composite headers; + private Composite body; + + private List sections = new ArrayList<>(); + + private ProvidedContent previousNode; + private SwtUiProvider previousUiProvider; + private SwtUiProvider currentUiProvider; + + private String tabStyle; + private String tabSelectedStyle; + private String bodyStyle; + private Image closeIcon; + + private StackLayout stackLayout; + + private boolean singleTab = false; + + public SwtTabbedArea(Composite parent, int style) { + super(parent, SWT.NONE); + CmsSwtUtils.style(parent, bodyStyle); + + setLayout(CmsSwtUtils.noSpaceGridLayout()); + + // TODO manage tabs at bottom or sides + headers = new Composite(this, SWT.NONE); + headers.setLayoutData(CmsSwtUtils.fillWidth()); + body = new Composite(this, SWT.NONE); + body.setLayoutData(CmsSwtUtils.fillAll()); + // body.setLayout(new FormLayout()); + stackLayout = new StackLayout(); + body.setLayout(stackLayout); + emptyState(); + } + + protected void refreshTabHeaders() { + int tabCount = sections.size() > 0 ? sections.size() : 1; + for (Control tab : headers.getChildren()) + tab.dispose(); + + headers.setLayout(CmsSwtUtils.noSpaceGridLayout(new GridLayout(tabCount, true))); + + if (sections.size() == 0) { + Composite emptyHeader = new Composite(headers, SWT.NONE); + emptyHeader.setLayoutData(CmsSwtUtils.fillAll()); + emptyHeader.setLayout(new GridLayout()); + Label lbl = new Label(emptyHeader, SWT.NONE); + lbl.setText(""); + lbl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false)); + + } + + SwtSection currentSection = getCurrentSection(); + for (SwtSection section : sections) { + boolean selected = section == currentSection; + Composite sectionHeader = section.createHeader(headers); + CmsSwtUtils.style(sectionHeader, selected ? tabSelectedStyle : tabStyle); + int headerColumns = singleTab ? 1 : 2; + sectionHeader.setLayout(new GridLayout(headerColumns, false)); + sectionHeader.setLayout(CmsSwtUtils.noSpaceGridLayout(headerColumns)); + Button title = new Button(sectionHeader, SWT.FLAT); + CmsSwtUtils.style(title, selected ? tabSelectedStyle : tabStyle); + title.setLayoutData(CmsSwtUtils.fillWidth()); + title.addSelectionListener((Selected) (e) -> showTab(tabIndex(section.getNode()))); + Content node = section.getContent(); + + // FIXME find a standard way to display titles + String titleStr = node.getName().getLocalPart(); + + // TODO internationalize + title.setText(titleStr); + if (!singleTab) { + ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE); + ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT); + if (closeIcon != null) + closeItem.setImage(closeIcon); + else + closeItem.setText("X"); + CmsSwtUtils.style(closeItem, selected ? tabSelectedStyle : tabStyle); + closeItem.addSelectionListener((Selected) (e) -> closeTab(section)); + } + } + + } + + public void view(SwtUiProvider uiProvider, Content context) { + if (body.isDisposed()) + return; + int index = tabIndex(context); + if (index >= 0) { + showTab(index); + previousNode = (ProvidedContent) context; + previousUiProvider = uiProvider; + return; + } + SwtSection section = (SwtSection) body.getChildren()[0]; + previousNode = (ProvidedContent) section.getNode(); + if (previousNode == null) {// empty state + previousNode = (ProvidedContent) context; + previousUiProvider = uiProvider; + } else { + previousUiProvider = currentUiProvider; + } + currentUiProvider = uiProvider; + section.setContent(context); + // section.setLayoutData(CmsUiUtils.coverAll()); + build(section, uiProvider, context); + if (sections.size() == 0) + sections.add(section); + refreshTabHeaders(); + index = tabIndex(context); + showTab(index); + layout(true, true); + } + + public void open(SwtUiProvider uiProvider, Content context) { + if (singleTab) + throw new UnsupportedOperationException("Open is not supported in single tab mode."); + + if (previousNode != null + && previousNode.getSessionLocalId().equals(((ProvidedContent) context).getSessionLocalId())) { + // does nothing + return; + } + if (sections.size() == 0) + CmsSwtUtils.clear(body); + SwtSection currentSection = getCurrentSection(); + int currentIndex = sections.indexOf(currentSection); + SwtSection previousSection = new SwtSection(body, SWT.NONE, context); + build(previousSection, previousUiProvider, previousNode); + // previousSection.setLayoutData(CmsUiUtils.coverAll()); + int newIndex = currentIndex + 1; + sections.add(currentIndex, previousSection); +// sections.add(newIndex, previousSection); + showTab(newIndex); + refreshTabHeaders(); + layout(true, true); + } + + public void showTab(int index) { + SwtSection sectionToShow = sections.get(index); + // sectionToShow.moveAbove(null); + stackLayout.topControl = sectionToShow; + refreshTabHeaders(); + layout(true, true); + } + + protected void build(SwtSection section, SwtUiProvider uiProvider, Content context) { + for (Control child : section.getChildren()) + child.dispose(); + CmsSwtUtils.style(section, bodyStyle); + section.setContent(context); + uiProvider.createUiPart(section, context); + + } + + private int tabIndex(Content context) { + for (int i = 0; i < sections.size(); i++) { + SwtSection section = sections.get(i); + if (section.getSessionLocalId().equals(((ProvidedContent) context).getSessionLocalId())) + return i; + } + return -1; + } + + public void closeTab(SwtSection section) { + int currentIndex = sections.indexOf(section); + int nextIndex = currentIndex == 0 ? 0 : currentIndex - 1; + sections.remove(section); + section.dispose(); + if (sections.size() == 0) { + emptyState(); + refreshTabHeaders(); + layout(true, true); + return; + } + refreshTabHeaders(); + showTab(nextIndex); + } + + public void closeAllTabs() { + for (SwtSection section : sections) { + section.dispose(); + } + sections.clear(); + emptyState(); + refreshTabHeaders(); + layout(true, true); + } + + protected void emptyState() { + new SwtSection(body, SWT.NONE, null); + refreshTabHeaders(); + } + + public Composite getCurrent() { + return getCurrentSection(); + } + + protected SwtSection getCurrentSection() { + return (SwtSection) stackLayout.topControl; + } + + public Content getCurrentContext() { + SwtSection section = getCurrentSection(); + if (section != null) { + return section.getNode(); + } else { + return null; + } + } + + public void setTabStyle(String tabStyle) { + this.tabStyle = tabStyle; + } + + public void setTabSelectedStyle(String tabSelectedStyle) { + this.tabSelectedStyle = tabSelectedStyle; + } + + public void setBodyStyle(String bodyStyle) { + this.bodyStyle = bodyStyle; + } + + public void setCloseIcon(Image closeIcon) { + this.closeIcon = closeIcon; + } + + public void setSingleTab(boolean singleTab) { + this.singleTab = singleTab; + } + +} diff --git a/jcr/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java b/jcr/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java index b32ae3020..63bf8dfff 100644 --- a/jcr/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java +++ b/jcr/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java @@ -180,6 +180,8 @@ public class JcrContent extends AbstractContent { @Override public Content getParent() { + if (Jcr.isRoot(getJcrNode())) // root + return null; return new JcrContent(session, provider, jcrWorkspace, Jcr.getParentPath(getJcrNode())); } @@ -223,6 +225,7 @@ public class JcrContent extends AbstractContent { /* * ADAPTERS */ + @SuppressWarnings("unchecked") public A adapt(Class clss) { if (Source.class.isAssignableFrom(clss)) { // try { @@ -246,6 +249,7 @@ public class JcrContent extends AbstractContent { return super.adapt(clss); } + @SuppressWarnings("unchecked") @Override public C open(Class clss) throws IOException, IllegalArgumentException { if (InputStream.class.isAssignableFrom(clss)) { @@ -271,6 +275,15 @@ public class JcrContent extends AbstractContent { return provider; } + @Override + public String getSessionLocalId() { + try { + return getJcrNode().getIdentifier(); + } catch (RepositoryException e) { + throw new JcrException("Cannot get identifier for " + getJcrNode(), e); + } + } + /* * STATIC UTLITIES */ diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java index 08b100efa..4473498c1 100644 --- a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java +++ b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java @@ -31,6 +31,8 @@ public interface CmsUiProvider extends SwtUiProvider { @Override default Control createUiPart(Composite parent, Content context) { + if (context == null) + return createUiPart(parent, (Node) null); if (context instanceof JcrContent) { Node node = ((JcrContent) context).getJcrNode(); return createUiPart(parent, node); diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java index 8b384799f..73c545d0d 100644 --- a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java +++ b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java @@ -4,9 +4,6 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.StringTokenizer; import javax.jcr.Node; import javax.jcr.RepositoryException; @@ -83,21 +80,7 @@ public class CmsUiUtils { /** Clean reserved URL characters for use in HTTP links. */ public static String getDataPathForUrl(Node node) { - return cleanPathForUrl(getDataPath(node)); - } - - /** Clean reserved URL characters for use in HTTP links. */ - public static String cleanPathForUrl(String path) { - StringTokenizer st = new StringTokenizer(path, "/"); - StringBuilder sb = new StringBuilder(); - while (st.hasMoreElements()) { - sb.append('/'); - String encoded = URLEncoder.encode(st.nextToken(), StandardCharsets.UTF_8); - encoded = encoded.replace("+", "%20"); - sb.append(encoded); - - } - return sb.toString(); + return CmsSwtUtils.cleanPathForUrl(getDataPath(node)); } /** @deprecated Use rowData16px() instead. GridData should not be reused. */ diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java index 5d3576f27..6b54c0a7b 100644 --- a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java +++ b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java @@ -207,7 +207,7 @@ public class JcrComposite extends Composite { layout(); } - public Session getSession() { - return session; - } +// public Session getSession() { +// return session; +// } } diff --git a/org.argeo.api.acr/src/org/argeo/api/acr/spi/ProvidedContent.java b/org.argeo.api.acr/src/org/argeo/api/acr/spi/ProvidedContent.java index d2509a49d..d9f378329 100644 --- a/org.argeo.api.acr/src/org/argeo/api/acr/spi/ProvidedContent.java +++ b/org.argeo.api.acr/src/org/argeo/api/acr/spi/ProvidedContent.java @@ -8,6 +8,14 @@ public interface ProvidedContent extends Content { ContentProvider getProvider(); + int getDepth(); + + /** + * An opaque ID which is guaranteed to uniquely identify this content within the + * session return by {@link #getSession()}. Typically used for UI. + */ + String getSessionLocalId(); + default ProvidedContent getMountPoint(String relativePath) { throw new UnsupportedOperationException("This content doe not support mount"); } diff --git a/org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java b/org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java index 9e23ff663..1b2b0e940 100644 --- a/org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java +++ b/org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java @@ -1,5 +1,6 @@ package org.argeo.cms.ux; +import org.argeo.api.acr.Content; import org.argeo.api.acr.ContentRepository; import org.argeo.api.acr.ContentSession; import org.argeo.api.cms.CmsView; @@ -10,6 +11,10 @@ public class CmsUxUtils { return CurrentUser.callAs(cmsView.getCmsSession().getSubject(), () -> contentRepository.get()); } + public static String getTitle(Content content) { + return content.getName().getLocalPart(); + } + /** singleton */ private CmsUxUtils() { diff --git a/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/ContentPart.java b/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/ContentPart.java new file mode 100644 index 000000000..5e91f5c79 --- /dev/null +++ b/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/ContentPart.java @@ -0,0 +1,12 @@ +package org.argeo.cms.ux.widgets; + +import org.argeo.api.acr.Content; + +/** A part displaying or editing a content. */ +public interface ContentPart { + Content getContent(); + + @Deprecated + Content getNode(); + +} diff --git a/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/EditablePart.java b/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/EditablePart.java new file mode 100644 index 000000000..1257cfc92 --- /dev/null +++ b/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/EditablePart.java @@ -0,0 +1,8 @@ +package org.argeo.cms.ux.widgets; + +/** Manages whether an editable or non editable control is shown. */ +public interface EditablePart { + public void startEditing(); + + public void stopEditing(); +} diff --git a/org.argeo.cms/src/org/argeo/cms/acr/AbstractContent.java b/org.argeo.cms/src/org/argeo/cms/acr/AbstractContent.java index b614a14cb..fa8062f7c 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/AbstractContent.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/AbstractContent.java @@ -100,6 +100,18 @@ public abstract class AbstractContent extends AbstractMap impleme collectAncestors(ancestors, content.getParent()); } + @Override + public int getDepth() { + List ancestors = new ArrayList<>(); + collectAncestors(ancestors, this); + return ancestors.size(); + } + + @Override + public String getSessionLocalId() { + return getPath(); + } + /* * UTILITIES */