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