Introduce tabbed area.
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 9 Oct 2020 09:56:35 +0000 (11:56 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 9 Oct 2020 09:56:35 +0000 (11:56 +0200)
13 files changed:
org.argeo.api/src/org/argeo/api/NodeConstants.java
org.argeo.api/src/org/argeo/api/RankingKey.java
org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java
org.argeo.cms.ui/src/org/argeo/cms/ui/CmsView.java
org.argeo.cms.ui/src/org/argeo/cms/ui/MvcProvider.java
org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsEvent.java [new file with mode: 0644]
org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java
org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/Section.java
org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/JcrComposite.java
org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/StyledControl.java
org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/TabbedArea.java [new file with mode: 0644]
org.argeo.cms.ui/src/org/argeo/cms/web/CmsWebEntryPoint.java
org.argeo.jcr/src/org/argeo/jcr/Jcr.java

index f561591685b4cfe0f3fe9c6ffd73bbd6d6d05f5e..c8fe962477a350f7a98e3032630080620992d9e8 100644 (file)
@@ -131,4 +131,9 @@ public interface NodeConstants {
         */
        String NODE_REPOS_FACTORY_PID = "org.argeo.api.repos";
        String NODE_USER_ADMIN_PID = "org.argeo.api.userAdmin";
+
+       /*
+        * ENTITIES
+        */
+       String DATA_TYPE = "argeo.data.type";
 }
index 90ba691e1d6c787c4ab6bfcfb62d5be82b95706b..c475c6733312096e5488629f8befde8afc394e00 100644 (file)
@@ -13,7 +13,7 @@ public class RankingKey implements Comparable<RankingKey> {
 
        private String pid;
        private Integer ranking = 0;
-       private Long id;
+       private Long id = 0l;
        private String dataType;
        private String dataPath;
 
@@ -32,6 +32,11 @@ public class RankingKey implements Comparable<RankingKey> {
                                ? Integer.parseInt(properties.get(SERVICE_RANKING).toString())
                                : 0;
                this.id = properties.containsKey(SERVICE_ID) ? (Long) properties.get(SERVICE_ID) : null;
+
+               // Argeo specific
+               this.dataType = properties.containsKey(NodeConstants.DATA_TYPE)
+                               ? properties.get(NodeConstants.DATA_TYPE).toString()
+                               : null;
        }
 
        @Override
@@ -41,6 +46,8 @@ public class RankingKey implements Comparable<RankingKey> {
                        result = +pid.hashCode();
                if (ranking != null)
                        result = +ranking;
+               if (dataType != null)
+                       result = +dataType.hashCode();
                return result;
        }
 
@@ -56,6 +63,8 @@ public class RankingKey implements Comparable<RankingKey> {
                        sb.append(pid);
                if (ranking != null && ranking != 0)
                        sb.append(' ').append(ranking);
+               if (dataType != null)
+                       sb.append(' ').append(dataType);
                return sb.toString();
        }
 
@@ -85,9 +94,22 @@ public class RankingKey implements Comparable<RankingKey> {
                        }
 
                } else {
-
+                       if (dataType != null && o.dataType != null) {
+                               if (dataType.equals(o.dataType)) {
+                                       // TODO factorise
+                                       if (ranking.equals(o.ranking))
+                                               if (id != null && o.id != null)
+                                                       return id.compareTo(o.id);
+                                               else
+                                                       return 0;
+                                       else
+                                               return ranking.compareTo(o.ranking);
+                               } else {
+                                       return dataPath.compareTo(o.dataType);
+                               }
+                       }
                }
-               return 0;
+               return -1;
        }
 
        public String getPid() {
@@ -118,6 +140,14 @@ public class RankingKey implements Comparable<RankingKey> {
                return new RankingKey(pid, Integer.MAX_VALUE, null, null, null);
        }
 
+       public static RankingKey minDataType(String dataType) {
+               return new RankingKey(null, Integer.MIN_VALUE, null, dataType, null);
+       }
+
+       public static RankingKey maxDataType(String dataType) {
+               return new RankingKey(null, Integer.MAX_VALUE, null, dataType, null);
+       }
+
        private static boolean equalsOrBothNull(Object o1, Object o2) {
                if (o1 == null && o2 == null)
                        return true;
index 6b1dde38a879cd22688265c2ef120e270b8fa8e0..00939e154ca2a5df106fb5b150f6dc33e6bc27ac 100644 (file)
@@ -3,7 +3,6 @@ package org.argeo.cms.ui;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
-import org.argeo.api.MvcProvider;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 
index 0e7e7268042a64650a9979acb5e03dba53dd5553..9f5e4f7973f9e35f29b37dca5199ca9b88814e2d 100644 (file)
@@ -1,5 +1,6 @@
 package org.argeo.cms.ui;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import javax.security.auth.login.LoginContext;
@@ -41,6 +42,16 @@ public interface CmsView {
 
        }
 
+       /**
+        * Convenience methods for when {@link #sendEvent(String, Map)} only requires
+        * one single parameter.
+        */
+       default void sendEvent(String topic, String param, Object value) {
+               Map<String, Object> properties = new HashMap<>();
+               properties.put(param, value);
+               sendEvent(topic, properties);
+       }
+
        static CmsView getCmsView(Composite parent) {
                // find parent shell
                Shell topShell = parent.getShell();
index 5d48873ab89e04bf6feb970919a6cf75ed6dc377..f29d6b76a3833f2e59345d00b931f124d9888cfb 100644 (file)
@@ -1,4 +1,4 @@
-package org.argeo.api;
+package org.argeo.cms.ui;
 
 import java.util.function.BiFunction;
 
diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsEvent.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsEvent.java
new file mode 100644 (file)
index 0000000..ca0797b
--- /dev/null
@@ -0,0 +1,21 @@
+package org.argeo.cms.ui.util;
+
+import org.argeo.cms.ui.CmsView;
+
+/**
+ * Can be applied to {@link Enum}s in order to define events used by
+ * {@link CmsView#sendEvent(String, java.util.Map)}.
+ */
+public interface CmsEvent {
+       String name();
+
+       default String topic() {
+               return getTopicBase() + "/" + name();
+       }
+
+       default         String getTopicBase() {
+               return "argeo/cms";
+       }
+
+
+}
index 65228aa5d559f7cb54a1e01418b8a94bd4d6d9ad..915b033365d8adab08ab6ab538e088fd946ca183 100644 (file)
@@ -178,6 +178,8 @@ public class CmsUiUtils implements CmsConstants {
 
        /** Style widget */
        public static <T extends Widget> T style(T widget, String style) {
+               if (style == null)
+                       return widget;// does nothing
                widget.setData(CmsConstants.STYLE, style);
                return widget;
        }
index 83ea5607614f1d727d5d76aec7276c0b37f9359f..6f870509981ccc180f2ef5b20625864e1a55f47b 100644 (file)
@@ -7,7 +7,6 @@ import java.util.Map;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
-import org.argeo.cms.CmsException;
 import org.argeo.cms.ui.util.CmsUiUtils;
 import org.argeo.cms.ui.widgets.JcrComposite;
 import org.eclipse.swt.SWT;
@@ -21,23 +20,27 @@ public class Section extends JcrComposite {
        private Composite sectionHeader;
        private final Integer relativeDepth;
 
-       public Section(Composite parent, int style, Node node) throws RepositoryException {
+       public Section(Composite parent, int style, Node node) {
                this(parent, findSection(parent), style, node);
        }
 
-       public Section(Section section, int style, Node node) throws RepositoryException {
+       public Section(Section section, int style, Node node) {
                this(section, section, style, node);
        }
 
-       protected Section(Composite parent, Section parentSection, int style, Node node) throws RepositoryException {
+       protected Section(Composite parent, Section parentSection, int style, Node node) {
                super(parent, style, node);
-               this.parentSection = parentSection;
-               if (parentSection != null) {
-                       relativeDepth = getNode().getDepth() - parentSection.getNode().getDepth();
-               } else {
-                       relativeDepth = 0;
+               try {
+                       this.parentSection = parentSection;
+                       if (parentSection != null) {
+                               relativeDepth = getNode().getDepth() - parentSection.getNode().getDepth();
+                       } else {
+                               relativeDepth = 0;
+                       }
+                       setLayout(CmsUiUtils.noSpaceGridLayout());
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException("Cannot create section from " + node, e);
                }
-               setLayout(CmsUiUtils.noSpaceGridLayout());
        }
 
        public Map<String, Section> getSubSections() throws RepositoryException {
@@ -65,15 +68,20 @@ public class Section extends JcrComposite {
                                collectDirectSubSections((Composite) child, subSections);
        }
 
-       public void createHeader() {
+       public Composite createHeader() {
+               return createHeader(this);
+       }
+
+       public Composite createHeader(Composite parent) {
                if (sectionHeader != null)
-                       throw new CmsException("Section header was already created");
+                       sectionHeader.dispose();
 
-               sectionHeader = new Composite(this, SWT.NONE);
+               sectionHeader = new Composite(parent, SWT.NONE);
                sectionHeader.setLayoutData(CmsUiUtils.fillWidth());
                sectionHeader.setLayout(CmsUiUtils.noSpaceGridLayout());
                // sectionHeader.moveAbove(null);
                // layout();
+               return sectionHeader;
        }
 
        public Composite getHeader() {
index d47aba792019d6382fbaae83e5fb228c8383dd29..a3cdb9827f31027c057b21350b9a503f1a8c1fd8 100644 (file)
@@ -15,7 +15,7 @@ import org.eclipse.swt.widgets.Composite;
 public class JcrComposite extends Composite {
        private static final long serialVersionUID = -1447009015451153367L;
 
-       private final Session session;
+       private Session session;
 
        private String nodeId;
        private String property = null;
@@ -28,37 +28,39 @@ public class JcrComposite extends Composite {
                nodeId = null;
        }
 
-       public JcrComposite(Composite parent, int style, Item item)
-                       throws RepositoryException {
+       public JcrComposite(Composite parent, int style, Item item) {
                this(parent, style, item, false);
        }
 
-       public JcrComposite(Composite parent, int style, Item item,
-                       boolean cacheImmediately) throws RepositoryException {
+       public JcrComposite(Composite parent, int style, Item item, boolean cacheImmediately) {
                super(parent, style);
-               this.session = item.getSession();
-               if (!cacheImmediately && (SWT.READ_ONLY == (style & SWT.READ_ONLY))) {
-                       // (useless?) optimization: we only save a pointer to the session,
-                       // not even a reference to the item
-                       this.nodeId = null;
-               } else {
-                       Node node;
-                       Property property = null;
-                       if (item instanceof Node) {
-                               node = (Node) item;
-                       } else {// Property
-                               property = (Property) item;
-                               if (property.isMultiple())// TODO manage property index
-                                       throw new CmsException(
-                                                       "Multiple properties not supported yet.");
-                               this.property = property.getName();
-                               node = property.getParent();
+               if (item != null)
+                       try {
+                               this.session = item.getSession();
+                               if (!cacheImmediately && (SWT.READ_ONLY == (style & SWT.READ_ONLY))) {
+                                       // (useless?) optimization: we only save a pointer to the session,
+                                       // not even a reference to the item
+                                       this.nodeId = null;
+                               } else {
+                                       Node node;
+                                       Property property = null;
+                                       if (item instanceof Node) {
+                                               node = (Node) item;
+                                       } else {// Property
+                                               property = (Property) item;
+                                               if (property.isMultiple())// TODO manage property index
+                                                       throw new CmsException("Multiple properties not supported yet.");
+                                               this.property = property.getName();
+                                               node = property.getParent();
+                                       }
+                                       this.nodeId = node.getIdentifier();
+                                       if (cacheImmediately)
+                                               this.cache = node;
+                               }
+                               setLayout(CmsUiUtils.noSpaceGridLayout());
+                       } catch (RepositoryException e) {
+                               throw new IllegalStateException("Cannot create composite from " + item, e);
                        }
-                       this.nodeId = node.getIdentifier();
-                       if (cacheImmediately)
-                               this.cache = node;
-               }
-               setLayout(CmsUiUtils.noSpaceGridLayout());
        }
 
        public synchronized Node getNode() {
@@ -89,12 +91,10 @@ public class JcrComposite extends Composite {
                                throw new CmsException("Item is not a Property");
                        Node node = getNodeInternal();
                        if (!node.hasProperty(property))
-                               throw new CmsException("Property " + property
-                                               + " is not set on " + node);
+                               throw new CmsException("Property " + property + " is not set on " + node);
                        return node.getProperty(property);
                } catch (RepositoryException e) {
-                       throw new CmsException("Cannot get property " + property
-                                       + " from node " + nodeId, e);
+                       throw new CmsException("Cannot get property " + property + " from node " + nodeId, e);
                }
        }
 
@@ -103,7 +103,7 @@ public class JcrComposite extends Composite {
        }
 
        /** Set/update the cache or change the node */
-       public synchronized void setNode(Node node) throws RepositoryException {
+       public synchronized void setNode(Node node) {
                if (!itemIsNode())
                        throw new CmsException("Cannot set a Node on a Property");
 
@@ -112,21 +112,25 @@ public class JcrComposite extends Composite {
                        return;
                }
 
-               if (session == null || session != node.getSession())// check session
-                       throw new CmsException("Uncompatible session");
-
-               if (nodeId == null || !nodeId.equals(node.getIdentifier())) {
-                       nodeId = node.getIdentifier();
-                       cache = node;
-                       itemUpdated();
-               } else {
-                       cache = node;// set/update cache
+               try {
+//                     if (session != null || session != node.getSession())// check session
+//                             throw new IllegalArgumentException("Uncompatible session");
+//                     if (session == null)
+                               session = node.getSession();
+                       if (nodeId == null || !nodeId.equals(node.getIdentifier())) {
+                               nodeId = node.getIdentifier();
+                               cache = node;
+                               itemUpdated();
+                       } else {
+                               cache = node;// set/update cache
+                       }
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException(e);
                }
        }
 
        /** Set/update the cache or change the property */
-       public synchronized void setProperty(Property prop)
-                       throws RepositoryException {
+       public synchronized void setProperty(Property prop) {
                if (itemIsNode())
                        throw new CmsException("Cannot set a Property on a Node");
 
@@ -135,18 +139,21 @@ public class JcrComposite extends Composite {
                        return;
                }
 
-               if (session == null || session != prop.getSession())// check session
-                       throw new CmsException("Uncompatible session");
-
-               Node node = prop.getNode();
-               if (nodeId == null || !nodeId.equals(node.getIdentifier())
-                               || !property.equals(prop.getName())) {
-                       nodeId = node.getIdentifier();
-                       property = prop.getName();
-                       cache = node;
-                       itemUpdated();
-               } else {
-                       cache = node;// set/update cache
+               try {
+                       if (session == null || session != prop.getSession())// check session
+                               throw new IllegalArgumentException("Uncompatible session");
+
+                       Node node = prop.getNode();
+                       if (nodeId == null || !nodeId.equals(node.getIdentifier()) || !property.equals(prop.getName())) {
+                               nodeId = node.getIdentifier();
+                               property = prop.getName();
+                               cache = node;
+                               itemUpdated();
+                       } else {
+                               cache = node;// set/update cache
+                       }
+               } catch (RepositoryException e) {
+                       throw new IllegalStateException(e);
                }
        }
 
@@ -155,8 +162,7 @@ public class JcrComposite extends Composite {
        }
 
        /** Change the node, does nothing if same. */
-       public synchronized void setNodeId(String nodeId)
-                       throws RepositoryException {
+       public synchronized void setNodeId(String nodeId) throws RepositoryException {
                if (this.nodeId != null && this.nodeId.equals(nodeId))
                        return;
                this.nodeId = nodeId;
index b085fdf9ce770ddceded5c63650b61d86ce0d8a8..9d7037c25a9ef315427eb0e0624d474c17fc1f01 100644 (file)
@@ -29,11 +29,11 @@ public abstract class StyledControl extends JcrComposite implements CmsConstants
                setLayout(CmsUiUtils.noSpaceGridLayout());
        }
 
-       public StyledControl(Composite parent, int style, Item item) throws RepositoryException {
+       public StyledControl(Composite parent, int style, Item item) {
                super(parent, style, item);
        }
 
-       public StyledControl(Composite parent, int style, Item item, boolean cacheImmediately) throws RepositoryException {
+       public StyledControl(Composite parent, int style, Item item, boolean cacheImmediately) {
                super(parent, style, item, cacheImmediately);
        }
 
diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/TabbedArea.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/TabbedArea.java
new file mode 100644 (file)
index 0000000..ba1e2f6
--- /dev/null
@@ -0,0 +1,215 @@
+package org.argeo.cms.ui.widgets;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.cms.ui.CmsUiProvider;
+import org.argeo.cms.ui.util.CmsUiUtils;
+import org.argeo.cms.ui.viewers.Section;
+import org.argeo.eclipse.ui.Selected;
+import org.argeo.jcr.Jcr;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FormLayout;
+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;
+
+public class TabbedArea extends Composite {
+       private static final long serialVersionUID = 8659669229482033444L;
+
+       private Composite headers;
+       private Composite body;
+
+       private List<Section> sections = new ArrayList<>();
+
+       private Node previousNode;
+       private CmsUiProvider previousUiProvider;
+       private CmsUiProvider currentUiProvider;
+
+       private String tabStyle;
+       private String tabSelectedStyle;
+       private Image closeIcon;
+
+       private long openingTimer = 500;
+
+       public TabbedArea(Composite parent, int style) {
+               super(parent, style);
+
+               setLayout(CmsUiUtils.noSpaceGridLayout());
+
+               // TODO manage tabs at bottom or sides
+               headers = new Composite(this, SWT.NONE);
+               headers.setLayoutData(CmsUiUtils.fillWidth());
+               body = new Composite(this, SWT.NONE);
+               body.setLayoutData(CmsUiUtils.fillAll());
+
+               body.setLayout(new FormLayout());
+               emptyState();
+       }
+
+       protected void refreshTabHeaders() {
+               int tabCount = sections.size() > 0 ? sections.size() : 1;
+               for (Control tab : headers.getChildren())
+                       tab.dispose();
+               headers.setLayout(CmsUiUtils.noSpaceGridLayout(new GridLayout(tabCount, true)));
+
+               if (sections.size() == 0) {
+                       Composite emptyHeader = new Composite(headers, SWT.NONE);
+                       emptyHeader.setLayoutData(CmsUiUtils.fillAll());
+                       emptyHeader.setLayout(new GridLayout());
+                       Label lbl = new Label(emptyHeader, SWT.NONE);
+                       lbl.setText("-");
+                       lbl.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, false));
+
+               }
+
+               Section currentSection = getCurrentSection();
+               for (Section section : sections) {
+                       boolean selected = section == currentSection;
+                       Composite sectionHeader = section.createHeader(headers);
+                       CmsUiUtils.style(sectionHeader, selected ? tabSelectedStyle : tabStyle);
+                       int headerColumns = 2;
+                       sectionHeader.setLayout(new GridLayout(headerColumns, false));
+                       Button title = new Button(sectionHeader, SWT.FLAT);
+                       CmsUiUtils.style(title, selected ? tabSelectedStyle : tabStyle);
+                       title.setLayoutData(CmsUiUtils.fillWidth());
+                       title.addSelectionListener((Selected) (e) -> section.moveAbove(null));
+                       Node node = section.getNode();
+                       title.setText(Jcr.getTitle(node));
+                       ToolBar toolBar = new ToolBar(sectionHeader, SWT.NONE);
+                       CmsUiUtils.style(toolBar, selected ? tabSelectedStyle : tabStyle);
+                       ToolItem closeItem = new ToolItem(toolBar, SWT.FLAT);
+                       if (closeIcon != null)
+                               closeItem.setImage(closeIcon);
+                       else
+                               closeItem.setText("X");
+                       closeItem.addSelectionListener((Selected) (e) -> closeTab(section));
+               }
+       }
+
+       public void view(CmsUiProvider uiProvider, Node context) {
+               int index = tabIndex(context);
+               if (index >= 0) {
+                       showTab(index);
+                       previousNode = context;
+                       previousUiProvider = uiProvider;
+                       return;
+               }
+               Section section = (Section) body.getChildren()[0];
+               previousNode = section.getNode();
+               if (previousNode == null) {// empty state
+                       previousNode = context;
+                       previousUiProvider = uiProvider;
+               } else {
+                       previousUiProvider = currentUiProvider;
+               }
+               currentUiProvider = uiProvider;
+               section.setNode(context);
+               section.setLayoutData(CmsUiUtils.coversAll());
+               for (Control child : section.getChildren())
+                       child.dispose();
+               uiProvider.createUiPart(section, context);
+               if (sections.size() == 0)
+                       sections.add(section);
+               refreshTabHeaders();
+               layout(true, true);
+       }
+
+       public void open(CmsUiProvider uiProvider, Node context) {
+               try {
+                       if (openingTimer > 0)
+                               Thread.sleep(openingTimer);
+               } catch (InterruptedException e) {
+                       // silent
+               }
+
+               // int index = tabIndex(context);
+               if (previousNode != null && Jcr.getIdentifier(previousNode).equals(Jcr.getIdentifier(context))) {
+                       // does nothing
+                       return;
+               }
+               if (sections.size() == 0)
+                       CmsUiUtils.clear(body);
+               Section currentSection = getCurrentSection();
+               int currentIndex = sections.indexOf(currentSection);
+               Section nextCurrentSection = new Section(body, SWT.NONE, context);
+               nextCurrentSection.setLayoutData(CmsUiUtils.coversAll());
+               sections.remove(currentSection);
+               sections.add(currentIndex, nextCurrentSection);
+               sections.add(currentSection);
+               nextCurrentSection.moveAbove(null);
+               if (previousNode != null) {
+                       view(previousUiProvider, previousNode);
+               }
+               refreshTabHeaders();
+               layout(true, true);
+       }
+
+       public void showTab(int index) {
+               Section sectionToShow = sections.get(index);
+               sectionToShow.moveAbove(null);
+               layout(true, true);
+       }
+
+       private int tabIndex(Node node) {
+               for (int i = 0; i < sections.size(); i++) {
+                       Section section = sections.get(i);
+                       if (Jcr.getIdentifier(section.getNode()).equals(Jcr.getIdentifier(node)))
+                               return i;
+               }
+               return -1;
+       }
+
+       public void closeTab(Section 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);
+       }
+
+       protected void emptyState() {
+               new Section(body, SWT.NONE, null);
+               refreshTabHeaders();
+       }
+
+       public Composite getCurrent() {
+               return getCurrentSection();
+       }
+
+       protected Section getCurrentSection() {
+               return (Section) body.getChildren()[0];
+       }
+
+       public void setTabStyle(String tabStyle) {
+               this.tabStyle = tabStyle;
+       }
+
+       public void setTabSelectedStyle(String tabSelectedStyle) {
+               this.tabSelectedStyle = tabSelectedStyle;
+       }
+
+       public void setCloseIcon(Image closeIcon) {
+               this.closeIcon = closeIcon;
+       }
+
+       public void setOpeningTimer(long openingTimer) {
+               this.openingTimer = openingTimer;
+       }
+
+}
index 186c988b1d1cacff17718800b32bad617ee20200..2961eead9c386951f21b2156d62f909a77f6b90b 100644 (file)
@@ -3,6 +3,7 @@ package org.argeo.cms.web;
 import static org.eclipse.rap.rwt.internal.service.ContextProvider.getApplicationContext;
 
 import java.security.PrivilegedAction;
+import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 
@@ -213,6 +214,8 @@ public class CmsWebEntryPoint implements EntryPoint, CmsView, BrowserNavigationL
 
        @Override
        public void sendEvent(String topic, Map<String, Object> properties) {
+               if (properties == null)
+                       properties = new HashMap<>();
                if (properties.containsKey(CMS_VIEW_UID_PROPERTY) && !properties.get(CMS_VIEW_UID_PROPERTY).equals(uid))
                        throw new IllegalArgumentException("Property " + CMS_VIEW_UID_PROPERTY + " is set to another CMS view uid ("
                                        + properties.get(CMS_VIEW_UID_PROPERTY) + ") then " + uid);
index 624b92b5bef4d5bf7ea792048618e53337ed7dbf..c3db4b604c71b1e8a955b45b2b5019de7a13dd14 100644 (file)
@@ -131,6 +131,17 @@ public class Jcr {
                }
        }
 
+       /**
+        * If node has mixin {@link NodeType#MIX_TITLE}, return
+        * {@link Property#JCR_TITLE}, otherwise return {@link #getName(Node)}.
+        */
+       public static String getTitle(Node node) {
+               if (Jcr.isNodeType(node, NodeType.MIX_TITLE))
+                       return get(node, Property.JCR_TITLE);
+               else
+                       return Jcr.getName(node);
+       }
+
        /** Accesses a {@link NodeIterator} as an {@link Iterable}. */
        @SuppressWarnings("unchecked")
        public static Iterable<Node> iterate(NodeIterator nodeIterator) {