Change package of non-JCR SWT components.
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 23 Jun 2022 10:41:27 +0000 (12:41 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 23 Jun 2022 10:41:27 +0000 (12:41 +0200)
18 files changed:
eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/EditablePart.java [new file with mode: 0644]
eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/ContextOverlay.java [new file with mode: 0644]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsEditionEvent.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableLink.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditableMultiStringProperty.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyDate.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/forms/FormPageViewer.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/AbstractPageViewer.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/EditablePart.java [deleted file]
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/JcrVersionCmsEditable.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/Section.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/SectionPart.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java [deleted file]
org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsEditable.java
org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsEditionEvent.java [new file with mode: 0644]
org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsEditionListener.java [new file with mode: 0644]
org.argeo.cms.ux/src/org/argeo/cms/ux/AbstractCmsEditable.java [new file with mode: 0644]

diff --git a/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/EditablePart.java b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/EditablePart.java
new file mode 100644 (file)
index 0000000..90c1677
--- /dev/null
@@ -0,0 +1,12 @@
+package org.argeo.cms.swt;
+
+import org.eclipse.swt.widgets.Control;
+
+/** Manages whether an editable or non editable control is shown. */
+public interface EditablePart {
+       public void startEditing();
+
+       public void stopEditing();
+
+       public Control getControl();
+}
diff --git a/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/ContextOverlay.java b/eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/widgets/ContextOverlay.java
new file mode 100644 (file)
index 0000000..f7b6443
--- /dev/null
@@ -0,0 +1,113 @@
+package org.argeo.cms.swt.widgets;
+
+import org.argeo.cms.swt.CmsSwtUtils;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Manages a lightweight shell which is related to a {@link Control}, typically
+ * in order to reproduce a dropdown semantic, but with more flexibility.
+ */
+public class ContextOverlay extends ScrolledPage {
+       private static final long serialVersionUID = 6702077429573324009L;
+
+//     private Shell shell;
+       private Control control;
+
+       private int maxHeight = 400;
+
+       public ContextOverlay(Control control, int style) {
+               super(createShell(control, style), SWT.NONE);
+               Shell shell = getShell();
+               setLayoutData(CmsSwtUtils.fillAll());
+               // TODO make autohide configurable?
+               //shell.addShellListener(new AutoHideShellListener());
+               this.control = control;
+               control.addDisposeListener((e) -> {
+                       dispose();
+                       shell.dispose();
+               });
+       }
+
+       private static Composite createShell(Control control, int style) {
+               if (control == null)
+                       throw new IllegalArgumentException("Control cannot be null");
+               if (control.isDisposed())
+                       throw new IllegalArgumentException("Control is disposed");
+               Shell shell = new Shell(control.getShell(), SWT.NO_TRIM);
+               shell.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               Composite placeholder = new Composite(shell, SWT.BORDER);
+               placeholder.setLayoutData(CmsSwtUtils.fillAll());
+               placeholder.setLayout(CmsSwtUtils.noSpaceGridLayout());
+               return placeholder;
+       }
+
+       public void show() {
+               Point relativeControlLocation = control.getLocation();
+               Point controlLocation = control.toDisplay(relativeControlLocation.x, relativeControlLocation.y);
+
+               int controlWidth = control.getBounds().width;
+
+               Shell shell = getShell();
+
+               layout(true, true);
+               shell.pack();
+               shell.layout(true, true);
+               int targetShellWidth = shell.getSize().x < controlWidth ? controlWidth : shell.getSize().x;
+               if (shell.getSize().y > maxHeight) {
+                       shell.setSize(targetShellWidth, maxHeight);
+               } else {
+                       shell.setSize(targetShellWidth, shell.getSize().y);
+               }
+
+               int shellHeight = shell.getSize().y;
+               int controlHeight = control.getBounds().height;
+               Point shellLocation = new Point(controlLocation.x, controlLocation.y + controlHeight);
+               int displayHeight = shell.getDisplay().getBounds().height;
+               if (shellLocation.y + shellHeight > displayHeight) {// bottom of page
+                       shellLocation = new Point(controlLocation.x, controlLocation.y - shellHeight);
+               }
+               shell.setLocation(shellLocation);
+
+               if (getChildren().length != 0)
+                       shell.open();
+               if (!control.isDisposed())
+                       control.setFocus();
+       }
+
+       public void hide() {
+               getShell().setVisible(false);
+               onHide();
+       }
+
+       public boolean isShellVisible() {
+               if (isDisposed())
+                       return false;
+               return getShell().isVisible();
+       }
+
+       /** to be overridden */
+       protected void onHide() {
+               // does nothing by default.
+       }
+
+       private class AutoHideShellListener extends ShellAdapter {
+               private static final long serialVersionUID = 7743287433907938099L;
+
+               @Override
+               public void shellDeactivated(ShellEvent e) {
+                       try {
+                               Thread.sleep(1000);
+                       } catch (InterruptedException e1) {
+                               // silent
+                       }
+                       if (!control.isDisposed() && !control.isFocusControl())
+                               hide();
+               }
+       }
+}
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsEditionEvent.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsEditionEvent.java
deleted file mode 100644 (file)
index 872142b..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.argeo.cms.ui;
-
-import java.util.EventObject;
-
-/** Notify of the edition lifecycle */
-public class CmsEditionEvent extends EventObject {
-       private static final long serialVersionUID = 950914736016693110L;
-
-       public final static Integer START_EDITING = 0;
-       public final static Integer STOP_EDITING = 1;
-
-       private final Integer type;
-
-       public CmsEditionEvent(Object source, Integer type) {
-               super(source);
-               this.type = type;
-       }
-
-       public Integer getType() {
-               return type;
-       }
-
-}
index e74de5ee8a40eb4381d8cb9c486ed5f8e8cfa69f..689fca3167708cca632d7d1637ffbf811f792f23 100644 (file)
@@ -3,7 +3,7 @@ package org.argeo.cms.ui.forms;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
-import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.swt.EditablePart;
 import org.argeo.eclipse.ui.EclipseUiUtils;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
index fd3f48e3a9cfa3b97c46ff22fa866e3b5e0429f1..a04537ef475de74cb4ea26cb2c84e868d710af25 100644 (file)
@@ -6,7 +6,7 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
 import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.swt.EditablePart;
 import org.argeo.cms.ui.widgets.StyledControl;
 import org.argeo.eclipse.ui.EclipseUiUtils;
 import org.eclipse.jface.dialogs.MessageDialog;
index 8591a925f1a2ef1be55adcd79b41846ba9d785bc..0f80ca78cfb480e41814a54affc56cd43faf2287 100644 (file)
@@ -8,7 +8,7 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
 import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.swt.EditablePart;
 import org.argeo.cms.ui.widgets.StyledControl;
 import org.argeo.eclipse.ui.EclipseUiUtils;
 import org.eclipse.swt.SWT;
index 09200935524f6072a5c957016e6f29e8a2d4face..ffe7e36f76e5fcd6391d588a8cb1649bd69a3dca 100644 (file)
@@ -7,7 +7,7 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
 import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.ui.viewers.EditablePart;
+import org.argeo.cms.swt.EditablePart;
 import org.argeo.cms.ui.widgets.EditableText;
 import org.argeo.eclipse.ui.EclipseUiUtils;
 import org.eclipse.swt.widgets.Composite;
index 3b1daf0aa60a53440aead8ec740795efd231cbad..e10dd4556f5d1c0355d862ed3a72b2f80f36f02b 100644 (file)
@@ -19,8 +19,8 @@ import org.argeo.api.cms.ux.Cms2DSize;
 import org.argeo.api.cms.ux.CmsEditable;
 import org.argeo.api.cms.ux.CmsImageManager;
 import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.EditablePart;
 import org.argeo.cms.ui.viewers.AbstractPageViewer;
-import org.argeo.cms.ui.viewers.EditablePart;
 import org.argeo.cms.ui.viewers.Section;
 import org.argeo.cms.ui.viewers.SectionPart;
 import org.argeo.cms.ui.widgets.EditableImage;
index 22e933f4545ea7772f9a8777974c9ad19a791c29..a247313e1ad17ab1609775c3b9786681d509bf7c 100644 (file)
@@ -13,6 +13,7 @@ import javax.security.auth.Subject;
 
 import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.ux.CmsEditable;
+import org.argeo.cms.swt.EditablePart;
 import org.argeo.cms.swt.widgets.ScrolledPage;
 import org.argeo.jcr.JcrException;
 import org.eclipse.jface.viewers.ContentViewer;
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/EditablePart.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/viewers/EditablePart.java
deleted file mode 100644 (file)
index 3967c97..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.argeo.cms.ui.viewers;
-
-import org.eclipse.swt.widgets.Control;
-
-/** Manages whether an editable or non editable control is shown. */
-public interface EditablePart {
-       public void startEditing();
-
-       public void stopEditing();
-
-       public Control getControl();
-}
index 07724f4b11c51a1f00e05c6a068929d9d5c8dfe8..298fbdea9b6d3dd2b58fc6e01d50a5cb954c58b8 100644 (file)
@@ -1,16 +1,14 @@
 package org.argeo.cms.ui.viewers;
 
-import java.util.Observable;
-
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.nodetype.NodeType;
 import javax.jcr.version.VersionManager;
 
-import org.argeo.api.cms.ux.CmsEditable;
-import org.argeo.cms.CmsException;
-import org.argeo.cms.ui.CmsEditionEvent;
+import org.argeo.api.cms.ux.CmsEditionEvent;
+import org.argeo.cms.ux.AbstractCmsEditable;
+import org.argeo.jcr.JcrException;
 import org.eclipse.rap.rwt.RWT;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Display;
@@ -18,23 +16,21 @@ import org.eclipse.swt.widgets.Event;
 import org.eclipse.swt.widgets.Listener;
 
 /** Provides the CmsEditable semantic based on JCR versioning. */
-public class JcrVersionCmsEditable extends Observable implements CmsEditable {
+public class JcrVersionCmsEditable extends AbstractCmsEditable {
        private final String nodePath;// cache
        private final VersionManager versionManager;
        private final Boolean canEdit;
 
        public JcrVersionCmsEditable(Node node) throws RepositoryException {
                this.nodePath = node.getPath();
-               if (node.getSession().hasPermission(node.getPath(),
-                               Session.ACTION_SET_PROPERTY)) {
+               if (node.getSession().hasPermission(node.getPath(), Session.ACTION_SET_PROPERTY)) {
                        // was Session.ACTION_ADD_NODE
                        canEdit = true;
                        if (!node.isNodeType(NodeType.MIX_VERSIONABLE)) {
                                node.addMixin(NodeType.MIX_VERSIONABLE);
                                node.getSession().save();
                        }
-                       versionManager = node.getSession().getWorkspace()
-                                       .getVersionManager();
+                       versionManager = node.getSession().getWorkspace().getVersionManager();
                } else {
                        canEdit = false;
                        versionManager = null;
@@ -43,8 +39,7 @@ public class JcrVersionCmsEditable extends Observable implements CmsEditable {
                // bind keys
                if (canEdit) {
                        Display display = Display.getCurrent();
-                       display.setData(RWT.ACTIVE_KEYS, new String[] { "CTRL+RETURN",
-                                       "CTRL+E" });
+                       display.setData(RWT.ACTIVE_KEYS, new String[] { "CTRL+RETURN", "CTRL+E" });
                        display.addFilter(SWT.KeyDown, new Listener() {
                                private static final long serialVersionUID = -4378653870463187318L;
 
@@ -70,8 +65,7 @@ public class JcrVersionCmsEditable extends Observable implements CmsEditable {
                                return false;
                        return versionManager.isCheckedOut(nodePath);
                } catch (RepositoryException e) {
-                       throw new CmsException("Cannot check whether " + nodePath
-                                       + " is editing", e);
+                       throw new JcrException("Cannot check whether " + nodePath + " is editing", e);
                }
        }
 
@@ -79,23 +73,22 @@ public class JcrVersionCmsEditable extends Observable implements CmsEditable {
        public void startEditing() {
                try {
                        versionManager.checkout(nodePath);
-                       setChanged();
+//                     setChanged();
                } catch (RepositoryException e1) {
-                       throw new CmsException("Cannot publish " + nodePath);
+                       throw new JcrException("Cannot publish " + nodePath, e1);
                }
-               notifyObservers(new CmsEditionEvent(nodePath,
-                               CmsEditionEvent.START_EDITING));
+               notifyListeners(new CmsEditionEvent(nodePath, CmsEditionEvent.START_EDITING, this));
        }
 
        @Override
        public void stopEditing() {
                try {
                        versionManager.checkin(nodePath);
-                       setChanged();
+//                     setChanged();
                } catch (RepositoryException e1) {
-                       throw new CmsException("Cannot publish " + nodePath, e1);
+                       throw new JcrException("Cannot publish " + nodePath, e1);
                }
-               notifyObservers(new CmsEditionEvent(nodePath,
-                               CmsEditionEvent.STOP_EDITING));
+               notifyListeners(new CmsEditionEvent(nodePath, CmsEditionEvent.STOP_EDITING, this));
        }
+
 }
index d282eebbe72b5789aa7d31b634dbe81be198850a..0e489e05f6f7b63039a0ebe4ca8825f40ce6a605 100644 (file)
@@ -8,6 +8,7 @@ import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
 import org.argeo.cms.swt.CmsSwtUtils;
+import org.argeo.cms.swt.EditablePart;
 import org.argeo.cms.ui.widgets.JcrComposite;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.widgets.Composite;
index f0b367f5ac542ac1cb3e2d84d1fec8663fd08bc4..df3c734c21c6412a07ab041cdb5bad513c746f60 100644 (file)
@@ -1,5 +1,6 @@
 package org.argeo.cms.ui.viewers;
 
+import org.argeo.cms.swt.EditablePart;
 
 /** An editable part dynamically related to a Section */
 public interface SectionPart extends EditablePart, NodePart {
diff --git a/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java b/jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java
deleted file mode 100644 (file)
index d14eadc..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-package org.argeo.cms.ui.widgets;
-
-import org.argeo.cms.swt.CmsSwtUtils;
-import org.argeo.cms.swt.widgets.ScrolledPage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ShellAdapter;
-import org.eclipse.swt.events.ShellEvent;
-import org.eclipse.swt.graphics.Point;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Shell;
-
-/**
- * Manages a lightweight shell which is related to a {@link Control}, typically
- * in order to reproduce a dropdown semantic, but with more flexibility.
- */
-public class ContextOverlay extends ScrolledPage {
-       private static final long serialVersionUID = 6702077429573324009L;
-
-//     private Shell shell;
-       private Control control;
-
-       private int maxHeight = 400;
-
-       public ContextOverlay(Control control, int style) {
-               super(createShell(control, style), SWT.NONE);
-               Shell shell = getShell();
-               setLayoutData(CmsSwtUtils.fillAll());
-               // TODO make autohide configurable?
-               //shell.addShellListener(new AutoHideShellListener());
-               this.control = control;
-               control.addDisposeListener((e) -> {
-                       dispose();
-                       shell.dispose();
-               });
-       }
-
-       private static Composite createShell(Control control, int style) {
-               if (control == null)
-                       throw new IllegalArgumentException("Control cannot be null");
-               if (control.isDisposed())
-                       throw new IllegalArgumentException("Control is disposed");
-               Shell shell = new Shell(control.getShell(), SWT.NO_TRIM);
-               shell.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               Composite placeholder = new Composite(shell, SWT.BORDER);
-               placeholder.setLayoutData(CmsSwtUtils.fillAll());
-               placeholder.setLayout(CmsSwtUtils.noSpaceGridLayout());
-               return placeholder;
-       }
-
-       public void show() {
-               Point relativeControlLocation = control.getLocation();
-               Point controlLocation = control.toDisplay(relativeControlLocation.x, relativeControlLocation.y);
-
-               int controlWidth = control.getBounds().width;
-
-               Shell shell = getShell();
-
-               layout(true, true);
-               shell.pack();
-               shell.layout(true, true);
-               int targetShellWidth = shell.getSize().x < controlWidth ? controlWidth : shell.getSize().x;
-               if (shell.getSize().y > maxHeight) {
-                       shell.setSize(targetShellWidth, maxHeight);
-               } else {
-                       shell.setSize(targetShellWidth, shell.getSize().y);
-               }
-
-               int shellHeight = shell.getSize().y;
-               int controlHeight = control.getBounds().height;
-               Point shellLocation = new Point(controlLocation.x, controlLocation.y + controlHeight);
-               int displayHeight = shell.getDisplay().getBounds().height;
-               if (shellLocation.y + shellHeight > displayHeight) {// bottom of page
-                       shellLocation = new Point(controlLocation.x, controlLocation.y - shellHeight);
-               }
-               shell.setLocation(shellLocation);
-
-               if (getChildren().length != 0)
-                       shell.open();
-               if (!control.isDisposed())
-                       control.setFocus();
-       }
-
-       public void hide() {
-               getShell().setVisible(false);
-               onHide();
-       }
-
-       public boolean isShellVisible() {
-               if (isDisposed())
-                       return false;
-               return getShell().isVisible();
-       }
-
-       /** to be overridden */
-       protected void onHide() {
-               // does nothing by default.
-       }
-
-       private class AutoHideShellListener extends ShellAdapter {
-               private static final long serialVersionUID = 7743287433907938099L;
-
-               @Override
-               public void shellDeactivated(ShellEvent e) {
-                       try {
-                               Thread.sleep(1000);
-                       } catch (InterruptedException e1) {
-                               // silent
-                       }
-                       if (!control.isDisposed() && !control.isFocusControl())
-                               hide();
-               }
-       }
-}
index 9047004ba44a210865761cdfef7ce2dee075c462..94ed24eb528661e35dac83f13c4a8b179f5cb61d 100644 (file)
@@ -4,15 +4,19 @@ package org.argeo.api.cms.ux;
 public interface CmsEditable {
 
        /** Whether the calling thread can edit, the value is immutable */
-       public Boolean canEdit();
+       Boolean canEdit();
 
-       public Boolean isEditing();
+       Boolean isEditing();
 
-       public void startEditing();
+       void startEditing();
 
-       public void stopEditing();
+       void stopEditing();
 
-       public static CmsEditable NON_EDITABLE = new CmsEditable() {
+       void addCmsEditionListener(CmsEditionListener listener);
+
+       void removeCmsEditionListener(CmsEditionListener listener);
+
+       static CmsEditable NON_EDITABLE = new CmsEditable() {
 
                @Override
                public void stopEditing() {
@@ -31,9 +35,18 @@ public interface CmsEditable {
                public Boolean canEdit() {
                        return false;
                }
+
+               @Override
+               public void addCmsEditionListener(CmsEditionListener listener) {
+               }
+
+               @Override
+               public void removeCmsEditionListener(CmsEditionListener listener) {
+               }
+
        };
 
-       public static CmsEditable ALWAYS_EDITING = new CmsEditable() {
+       static CmsEditable ALWAYS_EDITING = new CmsEditable() {
 
                @Override
                public void stopEditing() {
@@ -52,6 +65,15 @@ public interface CmsEditable {
                public Boolean canEdit() {
                        return true;
                }
+
+               @Override
+               public void addCmsEditionListener(CmsEditionListener listener) {
+               }
+
+               @Override
+               public void removeCmsEditionListener(CmsEditionListener listener) {
+               }
+
        };
 
 }
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsEditionEvent.java b/org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsEditionEvent.java
new file mode 100644 (file)
index 0000000..e1765ab
--- /dev/null
@@ -0,0 +1,29 @@
+package org.argeo.api.cms.ux;
+
+import java.util.EventObject;
+
+/** Notify of the edition lifecycle */
+public class CmsEditionEvent extends EventObject {
+       private static final long serialVersionUID = 950914736016693110L;
+
+       public final static Integer START_EDITING = 0;
+       public final static Integer STOP_EDITING = 1;
+
+       private final Integer type;
+       private final CmsEditable cmsEditable;
+
+       public CmsEditionEvent(Object source, Integer type, CmsEditable cmsEditable) {
+               super(source);
+               this.type = type;
+               this.cmsEditable = cmsEditable;
+       }
+
+       public Integer getType() {
+               return type;
+       }
+
+       public CmsEditable getCmsEditable() {
+               return cmsEditable;
+       }
+
+}
diff --git a/org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsEditionListener.java b/org.argeo.api.cms/src/org/argeo/api/cms/ux/CmsEditionListener.java
new file mode 100644 (file)
index 0000000..e05c168
--- /dev/null
@@ -0,0 +1,7 @@
+package org.argeo.api.cms.ux;
+
+public interface CmsEditionListener {
+       void editionStarted(CmsEditionEvent e);
+
+       void editionStopped(CmsEditionEvent e);
+}
diff --git a/org.argeo.cms.ux/src/org/argeo/cms/ux/AbstractCmsEditable.java b/org.argeo.cms.ux/src/org/argeo/cms/ux/AbstractCmsEditable.java
new file mode 100644 (file)
index 0000000..a1cd3d9
--- /dev/null
@@ -0,0 +1,34 @@
+package org.argeo.cms.ux;
+
+import java.util.IdentityHashMap;
+
+import org.argeo.api.cms.ux.CmsEditable;
+import org.argeo.api.cms.ux.CmsEditionEvent;
+import org.argeo.api.cms.ux.CmsEditionListener;
+
+public abstract class AbstractCmsEditable implements CmsEditable {
+       private IdentityHashMap<CmsEditionListener, Object> listeners = new IdentityHashMap<>();
+
+       protected void notifyListeners(CmsEditionEvent e) {
+               if (CmsEditionEvent.START_EDITING == e.getType()) {
+                       for (CmsEditionListener listener : listeners.keySet())
+                               listener.editionStarted(e);
+               } else if (CmsEditionEvent.STOP_EDITING == e.getType()) {
+                       for (CmsEditionListener listener : listeners.keySet())
+                               listener.editionStopped(e);
+               } else {
+                       throw new IllegalArgumentException("Unkown edition event type " + e.getType());
+               }
+       }
+
+       @Override
+       public void addCmsEditionListener(CmsEditionListener listener) {
+               listeners.put(listener, new Object());
+       }
+
+       @Override
+       public void removeCmsEditionListener(CmsEditionListener listener) {
+               listeners.remove(listener, new Object());
+       }
+
+}