anmolbabu has uploaded a new change for review.

Change subject: webadmin : DateTimeBox Widget
......................................................................

webadmin : DateTimeBox Widget

This patch adds DateTimeBox Widget

Change-Id: Ifc3834e66280a4812733b68d207b65f041bd3431
Signed-off-by: Anmol Babu <anb...@redhat.com>
---
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/DateTimeBox.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/EntityModelDateTimeBox.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/EntityModelDateTimeBoxEditor.java
A 
frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/ObservableOrderedSet.java
M 
frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/webadmin/public/WebAdmin.css
5 files changed, 560 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/84/39984/1

diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/DateTimeBox.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/DateTimeBox.java
new file mode 100644
index 0000000..34ac4de
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/DateTimeBox.java
@@ -0,0 +1,308 @@
+package org.ovirt.engine.ui.common.widget.editor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import org.ovirt.engine.ui.common.widget.renderer.StringRenderer;
+import org.ovirt.engine.ui.uicompat.ConstantsManager;
+import org.ovirt.engine.ui.uicompat.UIConstants;
+
+import com.google.gwt.core.client.JsDate;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.user.client.TakesValue;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HasValue;
+import com.google.gwt.user.client.ui.ValueListBox;
+import com.google.gwt.user.datepicker.client.DateBox;
+
+/**
+ * The DateTimeBox allows the user to select a date and a time.<br>
+ * It currently utilises the gwt DateBox for the date component and has the 
following 3 dropdowns<br>
+ * 1. Hours component of time.<br>
+ * 2. Minutes component of time.<br>
+ * 3. Am/Pm (This widget hence assumes 12hr format on display to user and 24 
hour format while returning the selected
+ * date object)<br>
+ */
+
+public class DateTimeBox extends Composite implements TakesValue<Date>, 
HasValue<Date> {
+
+    private static UIConstants constants = 
ConstantsManager.getInstance().getConstants();
+
+    private static final int HOUR_CONSTANT = 24;
+    private static final int MINUTE_MAX = 59;
+    private static final int constantRowIndex = 0;
+
+    private DateTimeFormat dateFormat;
+
+    private FlowPanel wrapperPanel = new FlowPanel();
+    FlexTable containerTable = new FlexTable();
+
+    private DateBox dateBox;
+    private ValueListBox<Integer> hoursBox;
+    private ValueListBox<Integer> minutesBox;
+
+    private int minuteSteps = 5;
+    private int hours = 1;
+    private int minutes = 0;
+    private int hourSteps = 1;
+
+    private Date selectedDate = new Date();
+
+    private int currentColumnMax = 0;
+
+    private boolean timeRequired;
+    private boolean dateRequired;
+
+    /**
+     * Use this if both date and time components of the widget are required. 
And the default date format of dd-MMM-yyyy
+     * is required.
+     */
+    public DateTimeBox() {
+        this(true, true, DateTimeFormat.getFormat("dd-MMM-yyyy"));//$NON-NLS-1$
+    }
+
+    /**
+     * Use if any/both of the components are required.(Date and time). If only 
one of the components is required, then
+     * the other component would be assumed to be the value as returned by the 
new Date object which is the browser's
+     * value.
+     */
+    public DateTimeBox(boolean dateRequired, boolean timeRequired) {
+        this(dateRequired, timeRequired, 
DateTimeFormat.getFormat("dd-MMM-yyyy"));//$NON-NLS-1$
+    }
+
+    /**
+     * Use if date is required but not in default format of dd-MMM-yyyy
+     */
+    public DateTimeBox(boolean timeRequired, DateTimeFormat dateFormat) {
+        this(true, timeRequired, dateFormat);
+    }
+
+    private DateTimeBox(boolean dateRequired, boolean timeRequired, 
DateTimeFormat dateFormat) {
+        this.dateRequired = dateRequired;
+        this.timeRequired = timeRequired;
+        this.dateFormat = dateFormat;
+        showDateTimeBox(dateRequired, timeRequired);
+        initWidget(wrapperPanel);
+    }
+
+    /**
+     * Set the required date and time in accordance with the date passed as 
the parameter. This is invoked in 2 cases : <br>
+     * 1. If user invokes setSelectedItem from the mapped ListModel<br>
+     * 2. UiCommonEditorVisitor on "ItemsChanged" for default first item 
selection.<br>
+     * Just In case if this is invoked with no checkboxes present, it will 
create one and set it selected (Possible if
+     * the setSelectedItem of the mapped ListModel is invoked before setItems).
+     */
+    @Override
+    public void setValue(Date value, boolean fireEvents) {
+        dateBox.setValue(value);
+
+        JsDate tDate = JsDate.create(value.getTime());
+        hours = tDate.getHours();
+        minutes = tDate.getMinutes();
+        selectedDate = new Date((long) tDate.getTime());
+
+        hoursBox.setValue(hours);
+        minutesBox.setValue(getClosestMinuteInBox(minutes));
+
+        if (!selectedDate.equals(value)) {
+            setSelectedDate();
+        }
+        if (fireEvents) {
+            ValueChangeEvent.fire(this, value);
+        }
+    }
+
+    private Integer getClosestMinuteInBox(int minutes) {
+        int minuteDistance = minutes % minuteSteps;
+        int nthNeighbour = minutes / minuteSteps;
+        if (minuteDistance > 2) {
+            nthNeighbour += 1;
+        }
+        return minuteSteps * nthNeighbour == 60 ? 0 : minuteSteps * 
nthNeighbour;
+    }
+
+    @Override
+    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Date> 
handler) {
+        return addHandler(handler, ValueChangeEvent.getType());
+    }
+
+    /**
+     * Select the required date in accordance with the date passed. This is 
invoked through EntityModel when setEntity
+     * is done using the EntityModel bound to this widget.
+     */
+    @Override
+    public void setValue(Date value) {
+        setValue(value, false);
+    }
+
+    /**
+     * Used to get the date selected in the widget<br>
+     * Date object is returned and hence, if the api user decides to use only 
the time component of the widget,<br>
+     * the returned value will contain the time component as selected in the 
widget but/and with the date component
+     * equal to that of the browser's date.
+     */
+    @Override
+    public Date getValue() {
+        return selectedDate;
+    }
+
+    private void showDateTimeBox(boolean dateRequired, boolean timeRequired) {
+        initDateBox();
+        placeDateBox();
+
+        initTimeBoxes();
+        placeTimeBoxes();
+
+        setComponentVisibilities();
+
+        wrapperPanel.add(containerTable);
+    }
+
+    private void placeDateBox() {
+        containerTable.setWidget(constantRowIndex, currentColumnMax, dateBox);
+        containerTable.getColumnFormatter().setStyleName(currentColumnMax,
+                dateRequired ? "dateBoxColumnWidth" : 
"dateBoxShrink");//$NON-NLS-1$//$NON-NLS-2$
+        currentColumnMax++;
+    }
+
+    private void initDateBox() {
+        dateBox = new DateBox();
+        dateBox.getDatePicker().addStyleName("dateBoxPopup");//$NON-NLS-1$
+        dateBox.setStyleName(dateRequired ? "dateBoxWidth" : 
"dateBoxShrink");//$NON-NLS-1$//$NON-NLS-2$
+        dateBox.setFormat(new DateBox.DefaultFormat(dateFormat));
+        dateBox.addValueChangeHandler(new ValueChangeHandler<Date>() {
+            @Override
+            public void onValueChange(ValueChangeEvent<Date> event) {
+                selectedDate = event.getValue();
+                setSelectedDate();
+            }
+        });
+    }
+
+    private void setComponentVisibilities() {
+        dateBox.setVisible(dateRequired);
+
+        hoursBox.setVisible(timeRequired);
+        minutesBox.setVisible(timeRequired);
+    }
+
+    private void placeTimeBoxes() {
+        containerTable.setWidget(constantRowIndex, currentColumnMax, hoursBox);
+        containerTable.getCellFormatter().getElement(constantRowIndex, 
currentColumnMax).addClassName("timeComponentWidth");//$NON-NLS-1$
+        hoursBox.setValue(HOUR_CONSTANT);
+        currentColumnMax++;
+
+        containerTable.setWidget(constantRowIndex, currentColumnMax, 
minutesBox);
+        containerTable.getCellFormatter().getElement(constantRowIndex, 
currentColumnMax).addClassName("timeComponentWidth");//$NON-NLS-1$
+        minutesBox.setValue(0);
+        currentColumnMax++;
+
+    }
+
+    private void initTimeBoxes() {
+        hoursBox = initIntegerValueBox(formStepValues(hourSteps, 1, 
HOUR_CONSTANT));
+        addHourSelectionListener();
+
+        minutesBox = initIntegerValueBox(formStepValues(minuteSteps, 0, 
MINUTE_MAX));
+        addMinuteSelectionListener();
+
+    }
+
+    private ValueListBox<String> initStringValueBox(ArrayList<String> items) {
+        ValueListBox<String> valueBox = new ValueListBox<String>(new 
StringRenderer<String>());
+        for (String item : items) {
+            valueBox.setValue(item, false);
+        }
+        return valueBox;
+    }
+
+    private ValueListBox<Integer> initIntegerValueBox(Collection<Integer> 
acceptableValues) {
+        ValueListBox<Integer> valueBox = new ValueListBox<>(new 
StringRenderer<Integer>());
+        for (Integer item : acceptableValues) {
+            valueBox.setValue(item, false);
+        }
+        return valueBox;
+    }
+
+    private void addHourSelectionListener() {
+        hoursBox.addValueChangeHandler(new ValueChangeHandler<Integer>() {
+            @Override
+            public void onValueChange(ValueChangeEvent<Integer> event) {
+                setSelectedDate();
+            }
+        });
+    }
+
+    private void addMinuteSelectionListener() {
+        minutesBox.addValueChangeHandler(new ValueChangeHandler<Integer>() {
+            @Override
+            public void onValueChange(ValueChangeEvent<Integer> event) {
+                minutes = event.getValue();
+                setSelectedDate();
+            }
+        });
+    }
+
+    private Collection<Integer> formStepValues(int step, int min, int max) {
+        ArrayList<Integer> items = new ArrayList<>();
+        for (int i = min; i <= max; i += step) {
+            items.add(i);
+        }
+        return items;
+    }
+
+    private void setSelectedDate() {
+        JsDate tDate = JsDate.create(selectedDate.getTime());
+        tDate.setHours(hours);
+        tDate.setMinutes(minutes);
+        selectedDate = new Date((long) tDate.getTime());
+        ValueChangeEvent.fire(this, selectedDate);
+    }
+
+    /**
+     * The default minutes step is 5. But this method can be used to alter 
this step.
+     */
+    public void setMinuteSteps(int minuteSteps) {
+        this.minuteSteps = minuteSteps;
+        minutesBox.setAcceptableValues(formStepValues(minuteSteps, 0, 
MINUTE_MAX));
+    }
+
+    /**
+     * Used to dynamically hide or display the time component.
+     */
+    public void setTimeRequired(boolean timeRequired) {
+        this.timeRequired = timeRequired;
+        setComponentVisibilities();
+    }
+
+    /**
+     * Used to dynamically hide or display the date component.
+     */
+    public void setDateRequired(boolean dateRequired) {
+        this.dateRequired = dateRequired;
+        dateBox.setStyleName(dateRequired ? "dateBoxWidth" : 
"dateBoxShrink");//$NON-NLS-1$//$NON-NLS-2$
+        containerTable.getColumnFormatter().setStyleName(currentColumnMax,
+                dateRequired ? "dateBoxColumnWidth" : 
"dateBoxShrink");//$NON-NLS-1$//$NON-NLS-2$
+        setComponentVisibilities();
+    }
+
+    /**
+     * Used to programatically check if the date component is hidden/visible.
+     */
+    public boolean isDateRequired() {
+        return dateRequired;
+    }
+
+    /**
+     * The default hours step is 1. But this method can be used to alter this 
step.
+     */
+    public void setHourSteps(int hourSteps) {
+        this.hourSteps = hourSteps;
+    }
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/EntityModelDateTimeBox.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/EntityModelDateTimeBox.java
new file mode 100644
index 0000000..64e4ae9
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/EntityModelDateTimeBox.java
@@ -0,0 +1,86 @@
+package org.ovirt.engine.ui.common.widget.editor;
+
+import java.util.Collection;
+import java.util.Date;
+
+import com.google.gwt.editor.client.adapters.TakesValueEditor;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.dom.client.KeyPressHandler;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.HasConstrainedValue;
+
+/**
+ * EntityModel bound DateTimeBox that uses {@link DateTimeBox}.
+ */
+public class EntityModelDateTimeBox extends DateTimeBox implements 
EditorWidget<Date, TakesValueEditor<Date>>, HasConstrainedValue<Date>{
+
+    private TakesConstrainedValueEditor<Date> editor;
+    private int tabIndex;
+
+    private boolean enabled;
+    public EntityModelDateTimeBox(boolean dateRequired, boolean timeRequired) {
+        super(dateRequired, timeRequired);
+    }
+
+    @Override
+    public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) {
+        return addDomHandler(handler, KeyUpEvent.getType());
+    }
+
+    @Override
+    public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
+        return addDomHandler(handler, KeyDownEvent.getType());
+    }
+
+    @Override
+    public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
+        return addDomHandler(handler, KeyPressEvent.getType());
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    @Override
+    public int getTabIndex() {
+        return tabIndex;
+    }
+
+    @Override
+    public void setAccessKey(char key) {
+
+    }
+
+    @Override
+    public void setFocus(boolean focused) {
+    }
+
+    @Override
+    public void setTabIndex(int index) {
+        this.tabIndex = index;
+    }
+
+    @Override
+    public TakesValueEditor<Date> asEditor() {
+        if (editor == null) {
+            editor = TakesConstrainedValueEditor.of(this, this, this);
+        }
+        return editor;
+    }
+
+    @Override
+    public void setAcceptableValues(Collection<Date> values) {
+        // Keeping this mute as of now because this can take up any date
+    }
+
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/EntityModelDateTimeBoxEditor.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/EntityModelDateTimeBoxEditor.java
new file mode 100644
index 0000000..c1d6e8c
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/EntityModelDateTimeBoxEditor.java
@@ -0,0 +1,48 @@
+package org.ovirt.engine.ui.common.widget.editor;
+
+import java.util.Date;
+import java.util.List;
+
+import org.ovirt.engine.ui.common.widget.AbstractValidatedWidgetWithLabel;
+
+import com.google.gwt.dom.client.Style.BorderStyle;
+import com.google.gwt.editor.client.IsEditor;
+
+/**
+ * EntityModel bound composite editor that uses {@link EntityModelDateTimeBox}.
+ */
+public class EntityModelDateTimeBoxEditor extends 
AbstractValidatedWidgetWithLabel<Date, EntityModelDateTimeBox> implements 
IsEditor<WidgetWithLabelEditor<Date, EntityModelDateTimeBoxEditor>>{
+
+    private final WidgetWithLabelEditor<Date, EntityModelDateTimeBoxEditor> 
editor;
+
+    public EntityModelDateTimeBoxEditor() {
+        this(true, true);
+    }
+
+    public EntityModelDateTimeBoxEditor(boolean dateRequired, boolean 
timeRequired) {
+        super(new EntityModelDateTimeBox(dateRequired, timeRequired));
+        this.editor = WidgetWithLabelEditor.of(getContentWidget().asEditor(), 
this);
+    }
+
+    public DateTimeBox asDateBox() {
+        return getContentWidget();
+    }
+
+    @Override
+    public WidgetWithLabelEditor<Date, EntityModelDateTimeBoxEditor> 
asEditor() {
+        return editor;
+    }
+
+    @Override
+    public void markAsValid() {
+        super.markAsValid();
+        getValidatedWidgetStyle().setBorderStyle(BorderStyle.NONE);
+    }
+
+    @Override
+    public void markAsInvalid(List<String> validationHints) {
+        super.markAsInvalid(validationHints);
+        getValidatedWidgetStyle().setBorderStyle(BorderStyle.SOLID);
+    }
+
+}
diff --git 
a/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/ObservableOrderedSet.java
 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/ObservableOrderedSet.java
new file mode 100644
index 0000000..4351e0c
--- /dev/null
+++ 
b/frontend/webadmin/modules/gwt-common/src/main/java/org/ovirt/engine/ui/common/widget/editor/ObservableOrderedSet.java
@@ -0,0 +1,73 @@
+package org.ovirt.engine.ui.common.widget.editor;
+
+import java.util.Collection;
+import java.util.LinkedHashSet;
+
+/**
+ * This provides a watchable {@link LinkedHashSet}.
+ */
+
+public abstract class ObservableOrderedSet<T> extends LinkedHashSet<T> {
+
+    private static final long serialVersionUID = 1L;
+
+    public abstract void onAdd(T item);
+
+    public abstract void onRemove(T item);
+
+    public abstract void onRemoveAll(Collection<T> items);
+
+    public abstract void onAddAll(Collection<T> items);
+
+    public abstract void onRemoveAll();
+
+    public void postProcess() {
+
+    }
+
+    @Override
+    public void clear() {
+        super.clear();
+        onRemoveAll();
+        postProcess();
+    }
+
+    @Override
+    public boolean add(T e) {
+        boolean addSuccess = super.add(e);
+        if (addSuccess) {
+            onAdd(e);
+        }
+        postProcess();
+        return addSuccess;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean remove(Object o) {
+        boolean removeSuccess = super.remove(o);
+        if (removeSuccess) {
+            onRemove((T) o);
+        }
+        postProcess();
+        return removeSuccess;
+    }
+
+    public boolean shrinkMe(Collection<T> c) {
+        boolean removeAllSucess = super.removeAll(c);
+        if (removeAllSucess) {
+            onRemoveAll(c);
+        }
+        postProcess();
+        return removeAllSucess;
+    }
+
+    public boolean expandMe(Collection<T> c) {
+        boolean addAllSuccess = super.addAll(c);
+        if (addAllSuccess) {
+            onAddAll(c);
+        }
+        postProcess();
+        return addAllSuccess;
+    }
+}
diff --git 
a/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/webadmin/public/WebAdmin.css
 
b/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/webadmin/public/WebAdmin.css
index 2be8468..ed6163f 100644
--- 
a/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/webadmin/public/WebAdmin.css
+++ 
b/frontend/webadmin/modules/webadmin/src/main/resources/org/ovirt/engine/ui/webadmin/public/WebAdmin.css
@@ -115,3 +115,48 @@
 .gwt-MenuBar .gwt-MenuItem {
     padding: 0 10px !important;
 }
+
+.selectedFlexTableCell {
+       background-color : #E6E6FA;
+       width: 25px;
+}
+
+.normalFlexTableCell {
+       background-color: white;
+       width: 25px;
+}
+
+.daysSelectorWrapperPanel {
+       width: 190px;
+}
+
+.timeComponentWidth {
+       width: 50px;
+}
+
+.dateBoxPopup {
+       position: relative;
+       top: 0px;
+       z-index: 5;
+}
+
+.dateBoxWidth {
+       width: 90px;
+}
+
+.checkBox {
+       width: 30px;
+       margin-right: 30px;
+}
+
+.dateBoxColumnWidth {
+       width: 100px;
+}
+
+.dateBoxShrink {
+       width: 0px;
+}
+
+.daysOfMonthWidget {
+       border-width: 2px;
+}


-- 
To view, visit https://gerrit.ovirt.org/39984
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ifc3834e66280a4812733b68d207b65f041bd3431
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.5-gluster
Gerrit-Owner: anmolbabu <anb...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to