From f2c36f8b746cc1b770b0033b81ae30d010e8b4ab Mon Sep 17 00:00:00 2001
From: ribeaudc <ribeaudc>
Date: Mon, 8 Dec 2008 09:59:47 +0000
Subject: [PATCH] [LMS-674] change: - Adapt 'InfoBox'. - Extend
 'AbstractAsyncCallback' functionality.

SVN: 9223
---
 .../application/AbstractAsyncCallback.java    |  92 +++++++++----
 .../client/application/ui/widget/InfoBox.java |  87 ++++++++++---
 .../GenericSampleBatchRegistrationForm.java   |   2 +
 .../sample/GenericSampleRegistrationForm.java | 123 +++++++++++-------
 .../client/testframework/RemoteConsole.java   |   4 +-
 5 files changed, 218 insertions(+), 90 deletions(-)

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java
index d05b540acc6..8208c2a0e9f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/AbstractAsyncCallback.java
@@ -34,29 +34,37 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.exception.InvalidSessi
  */
 public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
 {
-    private static final ICallbackListener DUMMY_LISTENER = new ICallbackListener()
+    private static final ICallbackListener DEFAULT_LISTENER = new ICallbackListener()
         {
-            public void onFailureOf(AsyncCallback<Object> callback, String failureMessage,
-                    Throwable throwable)
+
+            //
+            // ICallbackListener
+            //
+
+            public final void onFailureOf(final AsyncCallback<Object> callback,
+                    final String failureMessage, final Throwable throwable)
             {
                 MessageBox.alert("Error", failureMessage, null);
             }
 
-            public void finishOnSuccessOf(AsyncCallback<Object> callback, Object result)
+            public final void finishOnSuccessOf(final AsyncCallback<Object> callback,
+                    final Object result)
             {
             }
         };
 
     private static final String PREFIX = "exception_";
 
-    private static ICallbackListener callbackListener = DUMMY_LISTENER;
+    private static ICallbackListener staticCallbackListener = DEFAULT_LISTENER;
 
     private static final List<AbstractAsyncCallback<?>> callbackObjects =
             new ArrayList<AbstractAsyncCallback<?>>();
 
     /**
-     * Sets all callback objects silent. Note: THIS METHOD SHOULD NEVER BE USED. It is only used
-     * inside the testing framework.
+     * Sets all callback objects silent.
+     * <p>
+     * <b>Note</b>: THIS METHOD SHOULD NEVER BE USED. It is only used inside the testing framework.
+     * </p>
      */
     public static void setAllCallbackObjectsSilent()
     {
@@ -68,44 +76,75 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
     }
 
     /**
-     * Sets the global callback listener. Note: THIS METHOD SHOULD NEVER BE USED. It is only used
-     * inside the testing framework.
+     * Sets the global callback listener.
+     * <p>
+     * Note: THIS METHOD SHOULD NEVER BE USED. It is only used inside the testing framework.
+     * </p>
      */
-    public static void setCallbackListener(final ICallbackListener listenerOrNull)
+    public static void setStaticCallbackListener(final ICallbackListener listenerOrNull)
     {
-        callbackListener = listenerOrNull == null ? DUMMY_LISTENER : listenerOrNull;
+        staticCallbackListener = listenerOrNull == null ? DEFAULT_LISTENER : listenerOrNull;
     }
 
     protected final IViewContext<?> viewContext;
 
     private boolean silent;
 
+    private final ICallbackListener callbackListener;
+
     /**
      * Creates an instance for the specified view context.
      */
     public AbstractAsyncCallback(final IViewContext<?> viewContext)
+    {
+        this(viewContext, null);
+    }
+
+    /**
+     * Creates an instance for the specified view context.
+     */
+    public AbstractAsyncCallback(final IViewContext<?> viewContext,
+            final ICallbackListener callbackListenerOrNull)
     {
         this.viewContext = viewContext;
-        if (callbackListener != DUMMY_LISTENER)
+        if (staticCallbackListener != DEFAULT_LISTENER)
         {
             callbackObjects.add(this);
         }
+        if (callbackListenerOrNull != null)
+        {
+            callbackListener = callbackListenerOrNull;
+        } else
+        {
+            callbackListener = null;
+        }
     }
 
     @SuppressWarnings("unchecked")
-    private AsyncCallback<Object> getThis()
+    private final AsyncCallback<Object> getThis()
     {
         return (AsyncCallback<Object>) this;
     }
 
     /**
-     * Terminates {@link #onFailure(Throwable)}. Default behavior does nothing. Override this in
-     * subclasses.
+     * Terminates {@link #onFailure(Throwable)}.
+     * <p>
+     * Default behavior does nothing. Override this in subclasses.
+     * </p>
      */
     protected void finishOnFailure(final Throwable caught)
     {
     }
 
+    /**
+     * Processes the specified result of an asynchronous method invocation.
+     */
+    protected abstract void process(final T result);
+
+    //
+    // AsyncCallback
+    //
+
     public final void onFailure(final Throwable caught)
     {
         if (silent)
@@ -135,7 +174,14 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
                 msg = message;
             }
         }
-        callbackListener.onFailureOf(getThis(), msg, caught);
+        if (callbackListener != null)
+        {
+            callbackListener.onFailureOf(getThis(), msg, caught);
+        }
+        if (staticCallbackListener != DEFAULT_LISTENER || callbackListener == null)
+        {
+            staticCallbackListener.onFailureOf(getThis(), msg, caught);
+        }
         final IPageController pageController = viewContext.getPageController();
         if (caught instanceof InvalidSessionException)
         {
@@ -151,11 +197,13 @@ public abstract class AbstractAsyncCallback<T> implements AsyncCallback<T>
             return;
         }
         process(result);
-        callbackListener.finishOnSuccessOf(getThis(), result);
+        if (callbackListener != null)
+        {
+            callbackListener.finishOnSuccessOf(getThis(), result);
+        }
+        if (staticCallbackListener != DEFAULT_LISTENER || callbackListener == null)
+        {
+            staticCallbackListener.finishOnSuccessOf(getThis(), result);
+        }
     }
-
-    /**
-     * Processes the specified result of an asynchronous method invocation.
-     */
-    protected abstract void process(T result);
 }
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/widget/InfoBox.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/widget/InfoBox.java
index 1f60eee953a..496f12b3bb7 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/widget/InfoBox.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/widget/InfoBox.java
@@ -16,48 +16,101 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget;
 
-import com.extjs.gxt.ui.client.widget.form.LabelField;
+import com.extjs.gxt.ui.client.util.TextMetrics;
+import com.extjs.gxt.ui.client.widget.Html;
+import com.extjs.gxt.ui.client.widget.MessageBox;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.StringUtils;
 
 /**
+ * A {@link Html} extension that should be used as information panel.
+ * <p>
+ * It nicely informs the user about a certain action result. It should be used instead of a
+ * {@link MessageBox} in some cases.
+ * </p>
+ * 
  * @author Christian Ribeaud
  */
-public final class InfoBox extends LabelField
+public final class InfoBox extends Html
 {
 
     public InfoBox()
     {
-        setVisible(false);
         setStyleAttribute("textAlign", "center");
-        setPosition(-2, 0);
+        setStyleAttribute("borderStyle", "solid");
+        setStyleAttribute("borderWidth", "1px");
+        setHeight(computeHeight());
+        reset();
     }
 
-    private void setStrongStyle()
+    private final int computeHeight()
     {
-        setStyleAttribute("backgroundColor", "#feffbe");
-        setStyleAttribute("border", "1px solid #edee8b");
+        final TextMetrics textMetrics = TextMetrics.get();
+        textMetrics.bind(getElement());
+        return textMetrics.getHeight("X");
     }
 
-    private void setLightStyle()
+    /**
+     * Display given <var>text</var> as <i>error</i> text.
+     */
+    public final void displayError(final String text)
     {
-        setStyleAttribute("backgroundColor", "#feffdf");
-        setStyleAttribute("color", "gray");
-        setStyleAttribute("border", "1px solid #e7e7e7");
+        display(text, Type.ERROR);
     }
 
-    public void fade()
+    /**
+     * Display given <var>text</var> as <i>info</i> text.
+     */
+    public final void displayInfo(final String text)
     {
-        setLightStyle();
+        display(text, Type.INFO);
     }
 
-    public void display(final String text)
+    /**
+     * Displays given <var>text</var> of given <var>type</var>.
+     */
+    public final void display(final String text, final Type type)
     {
         if (StringUtils.isBlank(text) == false)
         {
-            setStrongStyle();
-            setVisible(true);
-            setText(text);
+            setStyleAttribute("backgroundColor", type.backgroundColor);
+            setStyleAttribute("borderColor", type.borderColor);
+            setHtml(text);
+        }
+    }
+
+    /**
+     * Resets the info box.
+     * <p>
+     * Background resp. border color are reset to <i>white</i>. And <i>HTML</i> text is reset to
+     * empty string.
+     * </p>
+     */
+    public final void reset()
+    {
+        setStyleAttribute("backgroundColor", "#ffffff");
+        setStyleAttribute("borderColor", "#ffffff");
+        setHtml("");
+    }
+
+    //
+    // Helper classes
+    //
+
+    private static enum Type
+    {
+
+        ERROR("#f6cece", "#f5a9a9"), INFO("#cef6ce", "#a9f5a9");
+
+        private final String backgroundColor;
+
+        private final String borderColor;
+
+        private Type(final String backgroundColor, final String borderColor)
+        {
+
+            this.backgroundColor = backgroundColor;
+            this.borderColor = borderColor;
         }
     }
 }
\ No newline at end of file
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleBatchRegistrationForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleBatchRegistrationForm.java
index 32cf560f15f..1a75b571a40 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleBatchRegistrationForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleBatchRegistrationForm.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.sa
 
 import com.extjs.gxt.ui.client.Events;
 import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
+import com.extjs.gxt.ui.client.Style.Scroll;
 import com.extjs.gxt.ui.client.event.ButtonEvent;
 import com.extjs.gxt.ui.client.event.FormEvent;
 import com.extjs.gxt.ui.client.event.Listener;
@@ -65,6 +66,7 @@ public final class GenericSampleBatchRegistrationForm extends LayoutContainer
             final IViewContext<IGenericClientServiceAsync> viewContext, final SampleType sampleType)
     {
         super(createLayout());
+        setScrollMode(Scroll.AUTO);
         this.viewContext = viewContext;
         add(createUI());
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleRegistrationForm.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleRegistrationForm.java
index 9f33955e946..f96996a571b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleRegistrationForm.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleRegistrationForm.java
@@ -22,11 +22,13 @@ import java.util.List;
 
 import com.extjs.gxt.ui.client.Events;
 import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
-import com.extjs.gxt.ui.client.event.BaseEvent;
-import com.extjs.gxt.ui.client.event.ComponentEvent;
+import com.extjs.gxt.ui.client.Style.Scroll;
+import com.extjs.gxt.ui.client.event.ButtonEvent;
+import com.extjs.gxt.ui.client.event.FieldEvent;
 import com.extjs.gxt.ui.client.event.Listener;
 import com.extjs.gxt.ui.client.event.SelectionListener;
 import com.extjs.gxt.ui.client.util.Format;
+import com.extjs.gxt.ui.client.widget.LayoutContainer;
 import com.extjs.gxt.ui.client.widget.button.Button;
 import com.extjs.gxt.ui.client.widget.form.AdapterField;
 import com.extjs.gxt.ui.client.widget.form.CheckBox;
@@ -36,11 +38,14 @@ import com.extjs.gxt.ui.client.widget.form.FormPanel;
 import com.extjs.gxt.ui.client.widget.form.MultiField;
 import com.extjs.gxt.ui.client.widget.form.TextField;
 import com.extjs.gxt.ui.client.widget.form.Validator;
+import com.extjs.gxt.ui.client.widget.layout.FlowLayout;
 import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.rpc.AsyncCallback;
 import com.google.gwt.user.client.ui.ListBox;
 
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.GenericConstants;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ICallbackListener;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.renderer.DateRenderer;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.GroupSelectionWidget;
@@ -60,7 +65,7 @@ import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.IGenericClientS
  * 
  * @author Izabela Adamczyk
  */
-public final class GenericSampleRegistrationForm extends FormPanel
+public final class GenericSampleRegistrationForm extends LayoutContainer
 {
     private static final String PREFIX = "generic-sample-registration_";
 
@@ -100,6 +105,8 @@ public final class GenericSampleRegistrationForm extends FormPanel
 
     private InfoBox infoBox;
 
+    private FormPanel formPanel;
+
     private static final String MANDATORY_LABEL_SEPARATOR = ": *";
 
     static final int LABEL_WIDTH = 100;
@@ -109,27 +116,34 @@ public final class GenericSampleRegistrationForm extends FormPanel
     public GenericSampleRegistrationForm(
             final IViewContext<IGenericClientServiceAsync> viewContext, final SampleType sampleType)
     {
+        setLayout(new FlowLayout(5));
         this.viewContext = viewContext;
         this.sampleType = sampleType;
-        configureForm();
-        createFormFields();
+        setScrollMode(Scroll.AUTO);
+        add(infoBox = createInfoBox());
+        add(formPanel = creatFormPanel());
+    }
+
+    private final static InfoBox createInfoBox()
+    {
+        final InfoBox infoBox = new InfoBox();
+        return infoBox;
     }
 
     private final void createFormFields()
     {
-        infoBox = new InfoBox();
         codeField = new CodeField(viewContext.getMessageProvider().getMessage("code"));
         codeField.setId(CODE_FIELD_ID);
-        codeField.addListener(Events.Focus, new Listener<BaseEvent>()
+        codeField.addListener(Events.Focus, new Listener<FieldEvent>()
             {
 
                 //
                 // Listener
                 //
 
-                public final void handleEvent(final BaseEvent be)
+                public final void handleEvent(final FieldEvent be)
                 {
-                    infoBox.fade();
+                    infoBox.reset();
                 }
             });
 
@@ -140,13 +154,13 @@ public final class GenericSampleRegistrationForm extends FormPanel
         sharedCheckbox.setId(SHARED_CHECKBOX_ID);
         sharedCheckbox.setBoxLabel("Shared");
         sharedCheckbox.setValue(SELECT_GROUP_BY_DEFAULT == false);
-        sharedCheckbox.addListener(Events.Change, new Listener<BaseEvent>()
+        sharedCheckbox.addListener(Events.Change, new Listener<FieldEvent>()
             {
                 //
                 // Listener
                 //
 
-                public final void handleEvent(final BaseEvent be)
+                public final void handleEvent(final FieldEvent be)
                 {
                     groupSelectionWidget
                             .setEnabled(sharedCheckbox.getValue().booleanValue() == false);
@@ -192,20 +206,21 @@ public final class GenericSampleRegistrationForm extends FormPanel
         }
     }
 
-    private final void configureForm()
+    private final FormPanel creatFormPanel()
     {
-        setHeaderVisible(false);
-        setBodyBorder(false);
-        setWidth(LABEL_WIDTH + FIELD_WIDTH + 40);
-
-        setLabelWidth(LABEL_WIDTH);
-        setFieldWidth(FIELD_WIDTH);
-        setButtonAlign(HorizontalAlignment.RIGHT);
+        final FormPanel panel = new FormPanel();
+        panel.setHeaderVisible(false);
+        panel.setBodyBorder(false);
+        panel.setWidth(LABEL_WIDTH + FIELD_WIDTH + 40);
+
+        panel.setLabelWidth(LABEL_WIDTH);
+        panel.setFieldWidth(FIELD_WIDTH);
+        panel.setButtonAlign(HorizontalAlignment.RIGHT);
         final Button saveButton =
                 new Button(viewContext.getMessageProvider().getMessage("button_save"));
         saveButton.setStyleAttribute("marginRight", "20px");
         saveButton.setId(SAVE_BUTTON_ID);
-        saveButton.addSelectionListener(new SelectionListener<ComponentEvent>()
+        saveButton.addSelectionListener(new SelectionListener<ButtonEvent>()
             {
 
                 //
@@ -213,14 +228,14 @@ public final class GenericSampleRegistrationForm extends FormPanel
                 //
 
                 @Override
-                public final void componentSelected(final ComponentEvent ce)
+                public final void componentSelected(final ButtonEvent ce)
                 {
                     submitForm();
                 }
             });
         final Button resetButton =
                 new Button(viewContext.getMessageProvider().getMessage("button_reset"));
-        resetButton.addSelectionListener(new SelectionListener<ComponentEvent>()
+        resetButton.addSelectionListener(new SelectionListener<ButtonEvent>()
             {
 
                 //
@@ -228,13 +243,14 @@ public final class GenericSampleRegistrationForm extends FormPanel
                 //
 
                 @Override
-                public final void componentSelected(final ComponentEvent ce)
+                public final void componentSelected(final ButtonEvent ce)
                 {
-                    reset();
+                    formPanel.reset();
                 }
             });
-        addButton(resetButton);
-        addButton(saveButton);
+        panel.addButton(resetButton);
+        panel.addButton(saveButton);
+        return panel;
     }
 
     private final String createSampleIdentifier()
@@ -281,7 +297,7 @@ public final class GenericSampleRegistrationForm extends FormPanel
 
     private final void submitForm()
     {
-        if (isValid())
+        if (formPanel.isValid())
         {
             final SampleToRegister sampleToRegister =
                     new SampleToRegister(createSampleIdentifier(), sampleType.getCode(),
@@ -302,25 +318,15 @@ public final class GenericSampleRegistrationForm extends FormPanel
         }
     }
 
-    private final void resetForm(final String info)
+    private final void addFormFields()
     {
-        createFormFields();
-        addFormFields();
-        infoBox.display(info);
-        layout();
-    }
-
-    public void addFormFields()
-    {
-        removeAll();
-        add(infoBox);
-        add(codeField);
-        add(groupMultiField);
-        add(parentGenerator);
-        add(parentContainer);
+        formPanel.add(codeField);
+        formPanel.add(groupMultiField);
+        formPanel.add(parentGenerator);
+        formPanel.add(parentContainer);
         for (final Field<?> propertyField : propertyFields)
         {
-            add(propertyField);
+            formPanel.add(propertyField);
         }
     }
 
@@ -369,6 +375,7 @@ public final class GenericSampleRegistrationForm extends FormPanel
     protected final void onRender(final Element target, final int index)
     {
         super.onRender(target, index);
+        createFormFields();
         addFormFields();
     }
 
@@ -380,7 +387,30 @@ public final class GenericSampleRegistrationForm extends FormPanel
     {
         RegisterSampleCallback(final IViewContext<?> viewContext)
         {
-            super(viewContext);
+            super(viewContext, new ICallbackListener()
+                {
+
+                    //
+                    // ICallbackListener
+                    //
+
+                    public final void finishOnSuccessOf(final AsyncCallback<Object> callback,
+                            final Object result)
+                    {
+                        final String message =
+                                createSuccessfullRegistrationInfo(sharedCheckbox.getValue(),
+                                        codeField.getValue(), groupSelectionWidget
+                                                .tryGetSelectedGroup());
+                        infoBox.displayInfo(message);
+                        formPanel.reset();
+                    }
+
+                    public final void onFailureOf(final AsyncCallback<Object> callback,
+                            final String failureMessage, final Throwable throwable)
+                    {
+                        infoBox.displayError(failureMessage);
+                    }
+                });
         }
 
         //
@@ -390,11 +420,6 @@ public final class GenericSampleRegistrationForm extends FormPanel
         @Override
         protected final void process(final Void result)
         {
-
-            final String message =
-                    createSuccessfullRegistrationInfo(sharedCheckbox.getValue(), codeField
-                            .getValue(), groupSelectionWidget.tryGetSelectedGroup());
-            resetForm(message);
         }
     }
 
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java
index 7031385c8eb..35675f1c7ea 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/client/web/client/testframework/RemoteConsole.java
@@ -56,7 +56,7 @@ public class RemoteConsole
     {
         this.testCase = testCase;
         commands = new ArrayList<ITestCommand>();
-        AbstractAsyncCallback.setCallbackListener(new ICallbackListener()
+        AbstractAsyncCallback.setStaticCallbackListener(new ICallbackListener()
             {
                 public void onFailureOf(AsyncCallback<Object> callback, String failureMessage,
                         Throwable throwable)
@@ -121,7 +121,7 @@ public class RemoteConsole
                 @Override
                 public void run()
                 {
-                    AbstractAsyncCallback.setCallbackListener(null);
+                    AbstractAsyncCallback.setStaticCallbackListener(null);
                     int numberOfUnexcutedCommands = commands.size() - entryIndex;
                     if (numberOfUnexcutedCommands > 0)
                     {
-- 
GitLab