Fix bug 366139 - Wrong end time set on multi-day events. r=philipp
authorDecathlon <bv1578@gmail.com>
Mon, 10 Jan 2011 09:40:00 +0100
changeset 6946 a2582159d2954a54de9aaf4aff1bbfabe2a92de0
parent 6945 180063a9fe4df473c2ce0fd2424acdceee81cb45
child 6947 23f94e99d83fba305bd100d5e2bb1192ae684f2e
push idunknown
push userunknown
push dateunknown
reviewersphilipp
bugs366139
Fix bug 366139 - Wrong end time set on multi-day events. r=philipp
calendar/base/content/dialogs/calendar-event-dialog.js
calendar/base/content/dialogs/calendar-event-dialog.xul
calendar/base/themes/common/images/event-dialog-keepduration-button.png
calendar/base/themes/pinstripe/dialogs/calendar-event-dialog.css
calendar/base/themes/winstripe/dialogs/calendar-event-dialog.css
calendar/locales/en-US/chrome/calendar/calendar-event-dialog.dtd
calendar/locales/en-US/chrome/calendar/calendar.properties
--- a/calendar/base/content/dialogs/calendar-event-dialog.js
+++ b/calendar/base/content/dialogs/calendar-event-dialog.js
@@ -420,16 +420,20 @@ function loadDialog(item) {
     loadRepeat(item);
 
     // load reminder details
     loadReminders(item.getAlarms({}));
 
     // hide rows based on if this is an event or todo
     updateStyle();
 
+    // Synchronize link-top-image with keep-duration-button status
+    let keepAttribute = document.getElementById("keepduration-button").getAttribute("keep") == "true";
+    setBooleanAttribute("link-image-top", "keep", keepAttribute);
+
     updateDateTime();
 
     updateCalendar();
 
     // figure out what the title of the dialog should be and set it
     updateTitle();
 
     let notifyCheckbox = document.getElementById("notify-attendees-checkbox");
@@ -515,36 +519,42 @@ function loadDateTime(item) {
     }
 }
 
 /**
  * Toggles the "keep" attribute every time the keepduration-button is pressed.
  */
 function toggleKeepDuration() {
     let kdb = document.getElementById("keepduration-button");
+    let keepAttribute = kdb.getAttribute("keep") == "true";
     // To make the "keep" attribute persistent, it mustn't be removed when in
     // false state (bug 15232).
-    kdb.setAttribute("keep", kdb.getAttribute("keep") == "true" ? "false" : "true");
+    kdb.setAttribute("keep", keepAttribute ? "false" : "true");
+    setBooleanAttribute("link-image-top", "keep", !keepAttribute);
 }
 
 /**
- * Handler function to be used when the start time or end time of the event have
- * changed. According to the state of the button "keepduration-button", it's
- * possible to change separately the start date from the end date or keep them
- * "linked" so that the total duration of the item can change or stay the same.
+ * Handler function to be used when the Start time or End time of the event have
+ * changed.
+ * When changing the Start date, the End date changes automatically so the
+ * event/task's duration stays the same. Instead the End date is not linked
+ * to the Start date unless the the keepDurationButton has the "keep" attribute
+ * set to true. In this case modifying the End date changes the Start date in
+ * order to keep the same duration.
  *
- * @param aDatepickerId   The datepicker's Id
+ * @param aStartDatepicker     If true the Start or Entry datepicker has changed,
+ *                             otherwise the End or Due datepicker has changed.
  */
-function dateTimeControls2State(aDatepickerId) {
+function dateTimeControls2State(aStartDatepicker) {
     if (gIgnoreUpdate) {
         return;
     }
-
-    let keepDuration = document.getElementById("keepduration-button")
-                           .getAttribute("keep") == "true";
+    let keepAttribute = document.getElementById("keepduration-button")
+                                .getAttribute("keep") == "true";
+    let allDay = getElementValue("event-all-day", "checked");
     var startWidgetId;
     var endWidgetId;
     if (isEvent(window.calendarItem)) {
         startWidgetId = "event-starttime";
         endWidgetId = "event-endtime";
     } else {
         if (!getElementValue("todo-has-entrydate", "checked")) {
             gItemDuration = null;
@@ -562,56 +572,60 @@ function dateTimeControls2State(aDatepic
 
     var menuItem = document.getElementById('options-timezone-menuitem');
     if (gStartTime) {
         // jsDate is always in OS timezone, thus we create a calIDateTime
         // object from the jsDate representation and simply set the new
         // timezone instead of converting.
         gStartTime = jsDateToDateTime(
             getElementValue(startWidgetId),
-            (menuItem.getAttribute('checked') == 'true') ? gStartTimezone : kDefaultTimezone);
+            (menuItem.getAttribute('checked') == 'true' || allDay) ? gStartTimezone : kDefaultTimezone);
+        gStartTime.isDate = allDay;
     }
-
     if (gEndTime) {
-        let timezone = gEndTimezone;
-        if (timezone.isUTC) {
-            if (gStartTime && !compareObjects(gStartTimezone, gEndTimezone)) {
-                timezone = gStartTimezone;
+        if (aStartDatepicker) {
+            // Change the End date in order to keep the duration.
+            gEndTime = gStartTime.clone();
+            if (gItemDuration) {
+                gEndTime.addDuration(gItemDuration);
+                gEndTime = gEndTime.getInTimezone(gEndTimezone);
             }
-        }
-        gEndTime = jsDateToDateTime(
-            getElementValue(endWidgetId),
-            (menuItem.getAttribute('checked') == 'true') ? timezone : kDefaultTimezone);
-        if (keepDuration) {
-            if (aDatepickerId == endWidgetId) {
+        } else {
+            let timezone = gEndTimezone;
+            if (timezone.isUTC) {
+                if (gStartTime && !compareObjects(gStartTimezone, gEndTimezone)) {
+                    timezone = gStartTimezone;
+                }
+            }
+            gEndTime = jsDateToDateTime(
+                getElementValue(endWidgetId),
+                (menuItem.getAttribute('checked') == 'true' || allDay) ? timezone : kDefaultTimezone);
+            gEndTime.isDate = allDay;
+            if (keepAttribute) {
+                // Keepduration button links the the Start date to the End date
+                // -> change the Start date in order to keep the duration.
                 let fduration = gItemDuration.clone();
                 fduration.isNegative = true;
                 gStartTime = gEndTime.clone();
                 gStartTime.addDuration(fduration);
                 gStartTime = gStartTime.getInTimezone(gStartTimezone);
-            } else {
-                gEndTime = gStartTime.clone();
-                if (gItemDuration) {
-                    gEndTime.addDuration(gItemDuration);
-                    gEndTime = gEndTime.getInTimezone(gEndTimezone);
-                }
             }
         }
     }
 
-    if (getElementValue("event-all-day", "checked")) {
+    if (allDay) {
         gStartTime.isDate = true;
         gEndTime.isDate = true;
         gItemDuration = gEndTime.subtractDate(gStartTime);
     }
 
     // calculate the new duration of start/end-time.
     // don't allow for negative durations.
     var warning = false;
-    if (!keepDuration && gStartTime && gEndTime) {
+    if (!aStartDatepicker && gStartTime && gEndTime) {
         if (gEndTime.compare(gStartTime) >= 0) {
             gItemDuration = gEndTime.subtractDate(gStartTime);
         } else {
             gStartTime = saveStartTime;
             gEndTime = saveEndTime;
             warning = true;
         }
     }
@@ -621,19 +635,17 @@ function dateTimeControls2State(aDatepic
 
     if (warning) {
         var callback = function func() {
             var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
                                 .getService(Components.interfaces.nsIPromptService);
             promptService.alert(
                 null,
                 document.title,
-                calGetString("calendar",
-                             (aDatepickerId == endWidgetId) ? "warningEndBeforeStart"
-                                                            : "warningStartAfterEnd"));
+                calGetString("calendar", "warningEndBeforeStart"));
         }
         setTimeout(callback, 1);
     }
 }
 
 /**
  * Updates the entry date checkboxes, used for example when choosing an alarm:
  * the entry date needs to be checked in that case.
--- a/calendar/base/content/dialogs/calendar-event-dialog.xul
+++ b/calendar/base/content/dialogs/calendar-event-dialog.xul
@@ -748,34 +748,35 @@
                            control="todo-has-entrydate"
                            class="todo-only"
                            disable-on-readonly="true"/>
                 </hbox>
                 <hbox id="event-grid-startdate-picker-box">
                     <datetimepicker id="event-starttime"
                                     class="event-only"
                                     disable-on-readonly="true"
-                                    onchange="dateTimeControls2State(this.id);"/>
+                                    onchange="dateTimeControls2State(true);"/>
                     <checkbox id="todo-has-entrydate"
                               class="todo-only checkbox-no-label"
                               disable-on-readonly="true"
                               oncommand="updateEntryDate();"/>
                     <datetimepicker id="todo-entrydate"
                                     class="todo-only"
                                     disable-on-readonly="true"
-                                    onchange="dateTimeControls2State(this.id);"/>
+                                    onchange="dateTimeControls2State(true);"/>
                     <vbox>
                         <hbox>
-                            <image id="link-image-top" class="keepduration-link-image"/>
+                            <image id="link-image-top" class="keepduration-link-image" keep="true"/>
                         </hbox>
                         <spacer flex="1"/>
                         <toolbarbutton id="keepduration-button"
+                                       accesskey="&event.dialog.keepDurationButton.accesskey;"
                                        oncommand="toggleKeepDuration();"
                                        persist="keep"
-                                       keep="true"
+                                       keep="false"
                                        tooltiptext="&event.dialog.keepDurationButton.tooltip;"/>
                     </vbox>
                     <hbox align="center">
                         <label id="timezone-starttime"
                                class="text-link"
                                collapsed="true"
                                crop="end"
                                disable-on-readonly="true"
@@ -801,25 +802,25 @@
                            class="todo-only"
                            disable-on-readonly="true"/>
                 </hbox>
                 <vbox>
                     <hbox id="event-grid-enddate-picker-box">
                         <datetimepicker id="event-endtime"
                                         class="event-only"
                                         disable-on-readonly="true"
-                                        onchange="dateTimeControls2State(this.id);"/>
+                                        onchange="dateTimeControls2State(false);"/>
                         <checkbox id="todo-has-duedate"
                                   class="todo-only checkbox-no-label"
                                   disable-on-readonly="true"
                                   oncommand="updateDueDate();"/>
                         <datetimepicker id="todo-duedate"
                                         class="todo-only"
                                         disable-on-readonly="true"
-                                        onchange="dateTimeControls2State(this.id);"/>
+                                        onchange="dateTimeControls2State(false);"/>
                         <vbox pack="end">
                             <image id="link-image-bottom" class="keepduration-link-image"/>
                         </vbox>
                         <hbox align="center">
                             <label id="timezone-endtime"
                                    class="text-link"
                                    collapsed="true"
                                    crop="end"
index 7e070a02a2449e440d3206f443f148b71fa1f4ae..8559c1c1b40fd50ea83e6a5b9fb6c260bf65beb3
GIT binary patch
literal 1949
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
--- a/calendar/base/themes/pinstripe/dialogs/calendar-event-dialog.css
+++ b/calendar/base/themes/pinstripe/dialogs/calendar-event-dialog.css
@@ -83,25 +83,30 @@ label.label {
 }
 
 #keepduration-button > label {
     display: none;
 }
 
 .keepduration-link-image {
     list-style-image: url(chrome://calendar/skin/event-dialog-keepduration-button.png);
+    -moz-margin-start: -1px;
 }
 
 #link-image-top {
-    -moz-image-region: rect(0px 23px 6px 15px);
+    -moz-image-region: rect(7px 23px 14px 14px);
     margin-top: 0.6em;
 }
 
+#link-image-top[keep="true"]{
+    -moz-image-region: rect(0px 23px 7px 14px);
+}
+
 #link-image-bottom {
-    -moz-image-region: rect(18px 23px 24px 15px);
+    -moz-image-region: rect(21px 23px 28px 14px);
     margin-bottom: 0.6em;
 }
 
 #timezone-endtime {
     -moz-margin-start: 15px;
 }
 
 /*--------------------------------------------------------------------
--- a/calendar/base/themes/winstripe/dialogs/calendar-event-dialog.css
+++ b/calendar/base/themes/winstripe/dialogs/calendar-event-dialog.css
@@ -83,25 +83,30 @@ label.label {
 }
 
 #keepduration-button > label {
     display: none;
 }
 
 .keepduration-link-image {
     list-style-image: url(chrome://calendar/skin/event-dialog-keepduration-button.png);
+    -moz-margin-start: -1px;
 }
 
 #link-image-top {
-    -moz-image-region: rect(0px 23px 6px 15px);
+    -moz-image-region: rect(7px 23px 14px 14px);
     margin-top: 0.6em;
 }
 
+#link-image-top[keep="true"]{
+    -moz-image-region: rect(0px 23px 7px 14px);
+}
+
 #link-image-bottom {
-    -moz-image-region: rect(18px 23px 24px 15px);
+    -moz-image-region: rect(21px 23px 28px 14px);
     margin-bottom: 0.6em;
 }
 
 #timezone-endtime {
     -moz-margin-start: 15px;
 }
 
 /*--------------------------------------------------------------------
--- a/calendar/locales/en-US/chrome/calendar/calendar-event-dialog.dtd
+++ b/calendar/locales/en-US/chrome/calendar/calendar-event-dialog.dtd
@@ -40,17 +40,18 @@
    - and other provisions required by the LGPL or the GPL. If you do not delete
    - the provisions above, a recipient may use your version of this file under
    - the terms of any one of the MPL, the GPL or the LGPL.
    -
    - ***** END LICENSE BLOCK ***** -->
 
 <!ENTITY event.title.label                  "Edit Item" >
 
-<!ENTITY event.dialog.keepDurationButton.tooltip  "">
+<!ENTITY event.dialog.keepDurationButton.tooltip   "Keep the duration when changing the End date">
+<!ENTITY event.dialog.keepDurationButton.accesskey "k">
 
 <!ENTITY newevent.from.label                "From" >
 <!ENTITY newevent.to.label                  "To" >
 <!ENTITY newevent.attendees.notify.label    "Notify attendees">
 
 <!ENTITY newevent.status.label                    "Status" >
 <!ENTITY newevent.status.accesskey                "S" >
 <!ENTITY newevent.eventStatus.none.label          "Not specified" >
--- a/calendar/locales/en-US/chrome/calendar/calendar.properties
+++ b/calendar/locales/en-US/chrome/calendar/calendar.properties
@@ -60,17 +60,16 @@ editTaskDialog=Edit Task
 # Do you want to save changes?
 askSaveTitleEvent=Save Event
 askSaveTitleTask=Save Task
 askSaveMessageEvent=Event has not been saved. Do you want to save the event?
 askSaveMessageTask=Task has not been saved. Do you want to save the task?
 
 # Event Dialog Warnings
 warningEndBeforeStart=The end date you entered occurs before the start date
-warningStartAfterEnd=The start date you entered occurs after the end date
 warningUntilBeforeStart=The until date you entered occurs before the start date
 
 # The name of the calendar provided with the application by default
 homeCalendarName=Home
 
 # The name given to a calendar if an opened calendar has an empty filename
 untitledCalendarName=Untitled Calendar