Introduce context overlay.
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 21 Jan 2021 13:52:51 +0000 (14:52 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 21 Jan 2021 13:52:51 +0000 (14:52 +0100)
org.argeo.cms.ui/src/org/argeo/cms/ui/forms/EditablePropertyString.java
org.argeo.cms.ui/src/org/argeo/cms/ui/util/CmsUiUtils.java
org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java [new file with mode: 0644]
org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/EditableText.java
org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/StyledControl.java
org.argeo.eclipse.ui/src/org/argeo/eclipse/ui/MouseDoubleClick.java [new file with mode: 0644]

index 52bb596ee1fc44fe4fd222516adc9905ec638dec..c170e8c2f9e5361a9f7306cb9db8d6e11ab7860d 100644 (file)
@@ -29,7 +29,7 @@ public class EditablePropertyString extends EditableText implements EditablePart
        public EditablePropertyString(Composite parent, int style, Node node, String propertyName, String message)
                        throws RepositoryException {
                super(parent, style, node, true);
-
+               //setUseTextAsLabel(true);
                this.propertyName = propertyName;
                this.message = message;
 
index 6b411cc302eb994676423a873003e22141dc3dce..6db26296375b1a31b3b92c9ef5832bcfd2957ddf 100644 (file)
@@ -156,6 +156,9 @@ public class CmsUiUtils implements CmsConstants {
                return new GridData(horizontalAlignment, horizontalAlignment, false, true);
        }
 
+       /*
+        * ROW LAYOUT
+        */
        public static RowData rowData16px() {
                return new RowData(16, 16);
        }
diff --git a/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java b/org.argeo.cms.ui/src/org/argeo/cms/ui/widgets/ContextOverlay.java
new file mode 100644 (file)
index 0000000..f8ca531
--- /dev/null
@@ -0,0 +1,113 @@
+package org.argeo.cms.ui.widgets;
+
+import org.argeo.cms.ui.util.CmsUiUtils;
+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(CmsUiUtils.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(CmsUiUtils.noSpaceGridLayout());
+               Composite placeholder = new Composite(shell, SWT.BORDER);
+               placeholder.setLayoutData(CmsUiUtils.fillAll());
+               placeholder.setLayout(CmsUiUtils.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 5fadbc07ba436b0a0a867f4c602e3b68d3ba51df..27b7c9b105ed4ad5e66790bd9f8cfe2fad0f0679 100644 (file)
@@ -21,6 +21,8 @@ public class EditableText extends StyledControl {
        private Color highlightColor;
        private Composite highlight;
 
+       private boolean useTextAsLabel = false;
+
        public EditableText(Composite parent, int style) {
                super(parent, style);
                editable = !(SWT.READ_ONLY == (style & SWT.READ_ONLY));
@@ -42,8 +44,11 @@ public class EditableText extends StyledControl {
                if (isEditing() && getEditable()) {
                        return createText(box, style, true);
                } else {
-//                     return createText(box, style, false);
-                       return createLabel(box, style);
+                       if (useTextAsLabel) {
+                               return createTextLabel(box, style);
+                       } else {
+                               return createLabel(box, style);
+                       }
                }
        }
 
@@ -58,6 +63,18 @@ public class EditableText extends StyledControl {
                return lbl;
        }
 
+       protected Text createTextLabel(Composite box, String style) {
+               Text lbl = new Text(box, getStyle() | SWT.MULTI);
+               lbl.setEditable(false);
+               lbl.setLayoutData(CmsUiUtils.fillWidth());
+               if (style != null)
+                       CmsUiUtils.style(lbl, style);
+               CmsUiUtils.markup(lbl);
+               if (mouseListener != null)
+                       lbl.addMouseListener(mouseListener);
+               return lbl;
+       }
+
        protected Text createText(Composite box, String style, boolean editable) {
                highlight = new Composite(box, SWT.NONE);
                highlight.setBackground(highlightColor);
@@ -111,8 +128,18 @@ public class EditableText extends StyledControl {
                        throw new IllegalStateException("Unsupported control " + child.getClass());
        }
 
+       /** @deprecated Use {@link #isEditable()} instead. */
+       @Deprecated
        public boolean getEditable() {
+               return isEditable();
+       }
+
+       public boolean isEditable() {
                return editable;
        }
 
+       public void setUseTextAsLabel(boolean useTextAsLabel) {
+               this.useTextAsLabel = useTextAsLabel;
+       }
+
 }
index 1814131f4b39d5f8bc32dc73a572512ec2d405fb..5dde1f63708e161a26428521d8749924341f52e1 100644 (file)
@@ -47,10 +47,10 @@ public abstract class StyledControl extends JcrComposite implements CmsConstants
        }
 
        protected Composite createContainer() {
-               Composite box = new Composite(this, SWT.INHERIT_DEFAULT);
-               setContainerLayoutData(box);
-               box.setLayout(CmsUiUtils.noSpaceGridLayout());
-               return box;
+               Composite container = new Composite(this, SWT.INHERIT_DEFAULT);
+               setContainerLayoutData(container);
+               container.setLayout(CmsUiUtils.noSpaceGridLayout());
+               return container;
        }
 
        public Control getControl() {
@@ -67,8 +67,7 @@ public abstract class StyledControl extends JcrComposite implements CmsConstants
                // int height = control.getSize().y;
                String style = (String) EclipseUiSpecificUtils.getStyleData(control);
                clear(false);
-               control = createControl(box, style);
-               setControlLayoutData(control);
+               refreshControl(style);
 
                // add the focus listener to the newly created edition control
                if (focusListener != null)
@@ -80,8 +79,13 @@ public abstract class StyledControl extends JcrComposite implements CmsConstants
                editing = false;
                String style = (String) EclipseUiSpecificUtils.getStyleData(control);
                clear(false);
+               refreshControl(style);
+       }
+       
+       protected void refreshControl(String style) {
                control = createControl(box, style);
                setControlLayoutData(control);
+               getParent().layout(true, true);
        }
 
        public void setStyle(String style) {
@@ -91,11 +95,8 @@ public abstract class StyledControl extends JcrComposite implements CmsConstants
                if (currentStyle != null && currentStyle.equals(style))
                        return;
 
-               // Integer preferredHeight = control != null ? control.getSize().y :
-               // null;
                clear(true);
-               control = createControl(box, style);
-               setControlLayoutData(control);
+               refreshControl(style);
 
                if (style != null) {
                        CmsUiUtils.style(box, style + "_box");
diff --git a/org.argeo.eclipse.ui/src/org/argeo/eclipse/ui/MouseDoubleClick.java b/org.argeo.eclipse.ui/src/org/argeo/eclipse/ui/MouseDoubleClick.java
new file mode 100644 (file)
index 0000000..49d11e5
--- /dev/null
@@ -0,0 +1,26 @@
+package org.argeo.eclipse.ui;
+
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+
+/**
+ * {@link MouseListener#mouseDoubleClick(MouseEvent)} as a functional interface
+ * in order to use as a short lambda expression in UI code.
+ * {@link MouseListener#mouseDownouseEvent)} and
+ * {@link MouseListener#mouseUp(MouseEvent)} do nothing by default.
+ */
+@FunctionalInterface
+public interface MouseDoubleClick extends MouseListener {
+       @Override
+       void mouseDoubleClick(MouseEvent e);
+
+       @Override
+       default void mouseDown(MouseEvent e) {
+               // does nothing
+       }
+
+       @Override
+       default void mouseUp(MouseEvent e) {
+               // does nothing
+       }
+}