Fix bug 366139 - Wrong end time set on multi-day events. r=philipp
authorDecathlon <bv1578@gmail.com>
Mon, 13 Dec 2010 16:01:27 +0100
changeset 6824 75c93fbd10fe705c58a2e284ad81117cac93f039
parent 6823 6036661e9d7b41ee56022cd7c9b319835f530958
child 6825 1afa1ca536e6f71d431d3cd8fdec4a6251de6b9a
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-attendees.js
calendar/base/content/dialogs/calendar-event-dialog.js
calendar/base/content/dialogs/calendar-event-dialog.xul
calendar/base/jar.mn
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-attendees.js
+++ b/calendar/base/content/dialogs/calendar-event-dialog-attendees.js
@@ -15,16 +15,17 @@
  *
  * The Initial Developer of the Original Code is Sun Microsystems.
  * Portions created by the Initial Developer are Copyright (C) 2006
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Michael Buettner <michael.buettner@sun.com>
  *   Philipp Kewisch <mozilla@kewis.ch>
+ *   Gianfranco Balza <bv1578@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -452,17 +453,17 @@ function updateEndTime() {
             var promptService =
                 Components.classes[
                     "@mozilla.org/embedcomp/prompt-service;1"]
                     .getService(
                         Components.interfaces.nsIPromptService);
             promptService.alert(
                 null,
                 document.title,
-                calGetString("calendar", "warningNegativeDuration"));
+                calGetString("calendar", "warningEndBeforeStart"));
         }
         setTimeout(callback, 1);
     }
 }
 
 /**
  * Prompts the user to pick a new timezone for the starttime. The dialog is
  * opened modally.
--- a/calendar/base/content/dialogs/calendar-event-dialog.js
+++ b/calendar/base/content/dialogs/calendar-event-dialog.js
@@ -19,16 +19,17 @@
  *
  * Contributor(s):
  *   Michael Buettner <michael.buettner@sun.com>
  *   Philipp Kewisch <mozilla@kewis.ch>
  *   Martin Schroeder <mschroeder@mozilla.x-home.org>
  *   Fred Jendrzejewski <fred.jen@web.de>
  *   Daniel Boelzle <daniel.boelzle@sun.com>
  *   Markus Adrario <Mozilla@Adrario.de>
+ *   Gianfranco Balza <bv1578@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -502,35 +503,48 @@ function loadDateTime(item) {
             endTime = endTime.getInTimezone(kDefaultTimezone);
         } else {
             gEndTimezone = kDefaultTimezone;
         }
         if (hasEntryDate && hasDueDate) {
             duration = endTime.subtractDate(startTime);
         }
         setElementValue("cmd_attendees", !(hasEntryDate && hasDueDate), "disabled");
+        setBooleanAttribute("keepduration-button", "disabled", !(hasEntryDate && hasDueDate));
         gStartTime = startTime;
         gEndTime = endTime;
         gItemDuration = duration;
     }
 }
 
+/**
+ * Toggles the "keep" attribute every time the keepduration-button is pressed.
+ */
+function toggleKeepDuration() {
+    let kdb = document.getElementById("keepduration-button");
+    // 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");
+}
 
 /**
  * Handler function to be used when the start time or end time of the event have
- * changed. If aKeepDuration is true then the end time will be modified so that
- * the total duration of the item stays the same.
+ * 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.
  *
- * @param aKeepDuration   If true, the duration will be kept constant.
+ * @param aDatepickerId   The datepicker's Id
  */
-function dateTimeControls2State(aKeepDuration) {
+function dateTimeControls2State(aDatepickerId) {
     if (gIgnoreUpdate) {
         return;
     }
 
+    let keepDuration = document.getElementById("keepduration-button")
+                           .getAttribute("keep") == "true";
     var startWidgetId;
     var endWidgetId;
     if (isEvent(window.calendarItem)) {
         startWidgetId = "event-starttime";
         endWidgetId = "event-endtime";
     } else {
         if (!getElementValue("todo-has-entrydate", "checked")) {
             gItemDuration = null;
@@ -552,43 +566,52 @@ function dateTimeControls2State(aKeepDur
         // object from the jsDate representation and simply set the new
         // timezone instead of converting.
         gStartTime = jsDateToDateTime(
             getElementValue(startWidgetId),
             (menuItem.getAttribute('checked') == 'true') ? gStartTimezone : kDefaultTimezone);
     }
 
     if (gEndTime) {
-        if (aKeepDuration) {
-            gEndTime = gStartTime.clone();
-            if (gItemDuration) {
-                gEndTime.addDuration(gItemDuration);
-                gEndTime = gEndTime.getInTimezone(gEndTimezone);
+        let timezone = gEndTimezone;
+        if (timezone.isUTC) {
+            if (gStartTime && !compareObjects(gStartTimezone, gEndTimezone)) {
+                timezone = gStartTimezone;
             }
-        } else {
-            var timezone = gEndTimezone;
-            if (timezone.isUTC) {
-                if (gStartTime && !compareObjects(gStartTimezone, gEndTimezone)) {
-                    timezone = gStartTimezone;
+        }
+        gEndTime = jsDateToDateTime(
+            getElementValue(endWidgetId),
+            (menuItem.getAttribute('checked') == 'true') ? timezone : kDefaultTimezone);
+        if (keepDuration) {
+            if (aDatepickerId == endWidgetId) {
+                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);
                 }
             }
-            gEndTime = jsDateToDateTime(
-                getElementValue(endWidgetId),
-                (menuItem.getAttribute('checked') == 'true') ? timezone : kDefaultTimezone);
         }
     }
 
     if (getElementValue("event-all-day", "checked")) {
         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 (!aKeepDuration && gStartTime && gEndTime) {
+    if (!keepDuration && gStartTime && gEndTime) {
         if (gEndTime.compare(gStartTime) >= 0) {
             gItemDuration = gEndTime.subtractDate(gStartTime);
         } else {
             gStartTime = saveStartTime;
             gEndTime = saveEndTime;
             warning = true;
         }
     }
@@ -598,17 +621,19 @@ function dateTimeControls2State(aKeepDur
 
     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", "warningNegativeDuration"));
+                calGetString("calendar",
+                             (aDatepickerId == endWidgetId) ? "warningEndBeforeStart"
+                                                            : "warningStartAfterEnd"));
         }
         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.
@@ -683,16 +708,17 @@ function updateDateCheckboxes(aDatePicke
     if (hasEntryDate && hasDueDate) {
         var start = jsDateToDateTime(getElementValue("todo-entrydate"));
         var end = jsDateToDateTime(getElementValue("todo-duedate"));
         gItemDuration = end.subtractDate(start);
     } else {
         gItemDuration = null;
     }
     setElementValue("cmd_attendees", !(hasEntryDate && hasDueDate), "disabled");
+    setBooleanAttribute("keepduration-button", "disabled", !(hasEntryDate && hasDueDate));
     updateDateTime();
     updateTimezone();
 }
 
 /**
  * Update the dialog controls to display the item's recurrence information
  * nicely.
  *
@@ -1166,24 +1192,25 @@ function onUpdateAllDay() {
     if (gIgnoreUpdate) {
         return;
     }
 
     if (!isEvent(window.calendarItem)) {
         return;
     }
 
-    var allDay = getElementValue("event-all-day", "checked");
+    let allDay = getElementValue("event-all-day", "checked");
     setElementValue("event-starttime", allDay, "timepickerdisabled");
     setElementValue("event-endtime", allDay, "timepickerdisabled");
 
     setShowTimeAs(allDay);
 
     gStartTime.isDate = allDay;
     gEndTime.isDate = allDay;
+    gItemDuration = gEndTime.subtractDate(gStartTime);
 
     updateDateTime();
     updateRepeatDetails();
     updateAccept();
 }
 
 /**
  * Use the window arguments to cause the opener to create a new event on the
@@ -2832,18 +2859,18 @@ function updateRepeatDetails() {
         // we don't have any strings prepared for.
         let repeatDetails = document.getElementById("repeat-details");
         repeatDetails.setAttribute("collapsed", "true");
 
         // Try to create a descriptive string from the rule(s).
         let kDefaultTimezone = calendarDefaultTimezone();
         let event = cal.isEvent(item);
 
-        let startDate =  getElementValue( event ? "event-starttime" : "todo-entrydate");
-        let endDate =  getElementValue( event ? "event-endtime" : "todo-duedate");
+        let startDate = getElementValue(event ? "event-starttime" : "todo-entrydate");
+        let endDate = getElementValue(event ? "event-endtime" : "todo-duedate");
         startDate = jsDateToDateTime(startDate, kDefaultTimezone);
         endDate = jsDateToDateTime(endDate, kDefaultTimezone);
 
         let allDay = getElementValue("event-all-day", "checked");
         let detailsString = recurrenceRule2String(
             recurrenceInfo, startDate, endDate, allDay);
 
         // Now display the string...
--- a/calendar/base/content/dialogs/calendar-event-dialog.xul
+++ b/calendar/base/content/dialogs/calendar-event-dialog.xul
@@ -19,16 +19,17 @@
    - the Initial Developer. All Rights Reserved.
    -
    - Contributor(s):
    -   Michael Buettner <michael.buettner@sun.com>
    -   Philipp Kewisch <mozilla@kewis.ch>
    -   Stefan Sitter <ssitter@gmail.com>
    -   Fred Jendrzejewski <fred.jen@web.de>
    -   Markus Adrario <Mozilla@Adrario.de>
+   -   Gianfranco Balza <bv1578@gmail.com>
    -
    - Alternatively, the contents of this file may be used under the terms of
    - either the GNU General Public License Version 2 or later (the "GPL"), or
    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    - in which case the provisions of the GPL or the LGPL are applicable instead
    - of those above. If you wish to allow use of your version of this file only
    - under the terms of either the GPL or the LGPL, and not to allow others to
    - use your version of this file under the terms of the MPL, indicate your
@@ -729,52 +730,64 @@
                           class="event-only"
                           disable-on-readonly="true"
                           label="&event.alldayevent.label;"
                           accesskey="&event.alldayevent.accesskey;"
                           oncommand="onUpdateAllDay();"/>
             </row>
 
             <!-- StartDate -->
-            <row id="event-grid-startdate-row" align="center">
+            <row id="event-grid-startdate-row">
                 <hbox id="event-grid-startdate-label-box"
                       align="center">
                     <label value="&event.from.label;"
                            accesskey="&event.from.accesskey;"
                            control="event-starttime"
                            class="event-only"
                            disable-on-readonly="true"/>
                     <label value="&task.from.label;"
                            accesskey="&task.from.accesskey;"
                            control="todo-has-entrydate"
                            class="todo-only"
                            disable-on-readonly="true"/>
                 </hbox>
-                <hbox id="event-grid-startdate-picker-box"
-                      align="center">
+                <hbox id="event-grid-startdate-picker-box">
                     <datetimepicker id="event-starttime"
                                     class="event-only"
                                     disable-on-readonly="true"
-                                    onchange="dateTimeControls2State(true);"/>
+                                    onchange="dateTimeControls2State(this.id);"/>
                     <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(false);"/>
-                    <label id="timezone-starttime"
-                           class="text-link"
-                           collapsed="true"
-                           crop="right"
-                           disable-on-readonly="true"
-                           flex="1"
-                           hyperlink="true"
-                           onclick="editStartTimezone()"/>
+                                    onchange="dateTimeControls2State(this.id);"/>
+                    <vbox>
+                        <hbox>
+                            <image id="link-image-top" class="keepduration-link-image"/>
+                        </hbox>
+                        <spacer flex="1"/>
+                        <toolbarbutton id="keepduration-button"
+                                       oncommand="toggleKeepDuration();"
+                                       persist="keep"
+                                       keep="true"
+                                       tooltiptext="&event.dialog.keepDurationButton.tooltip;"/>
+                    </vbox>
+                    <hbox align="center">
+                        <label id="timezone-starttime"
+                               class="text-link"
+                               collapsed="true"
+                               crop="end"
+                               disable-on-readonly="true"
+                               flex="1"
+                               hyperlink="true"
+                               onclick="editStartTimezone()"/>
+                    </hbox>
                 </hbox>
             </row>
 
             <!-- EndDate -->
             <row id="event-grid-enddate-row">
                 <hbox id="event-grid-enddate-label-box"
                       align="center">
                     <label value="&event.to.label;"
@@ -784,38 +797,42 @@
                            disable-on-readonly="true"/>
                     <label value="&task.to.label;"
                            accesskey="&task.to.accesskey;"
                            control="todo-has-duedate"
                            class="todo-only"
                            disable-on-readonly="true"/>
                 </hbox>
                 <vbox>
-                    <hbox id="event-grid-enddate-picker-box"
-                          align="center">
+                    <hbox id="event-grid-enddate-picker-box">
                         <datetimepicker id="event-endtime"
                                         class="event-only"
                                         disable-on-readonly="true"
-                                        onchange="dateTimeControls2State(false);"/>
+                                        onchange="dateTimeControls2State(this.id);"/>
                         <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(false);"/>
-                        <label id="timezone-endtime"
-                               class="text-link"
-                               collapsed="true"
-                               crop="right"
-                               disable-on-readonly="true"
-                               flex="1"
-                               hyperlink="true"
-                               onclick="editEndTimezone()"/>
+                                        onchange="dateTimeControls2State(this.id);"/>
+                        <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"
+                                   disable-on-readonly="true"
+                                   flex="1"
+                                   hyperlink="true"
+                                   onclick="editEndTimezone()"/>
+                        </hbox>
                     </hbox>
                 </vbox>
             </row>
 
             <row id="event-grid-todo-status-row"
                  class="todo-only"
                  align="center">
                 <label id="todo-status-label"
--- a/calendar/base/jar.mn
+++ b/calendar/base/jar.mn
@@ -116,16 +116,17 @@ calendar.jar:
     skin/calendar/calendar-providerUninstall-dialog.css    (themes/common/calendar-providerUninstall-dialog.css)
     skin/calendar/calendar-overlay.png                     (themes/common/images/calendar-overlay.png)
     skin/calendar/category-overlay.png                     (themes/common/images/category-overlay.png)
     skin/calendar/calendar-printing.css                    (themes/common/calendar-printing.css)
     skin/calendar/calendar-status.png                      (themes/common/images/calendar-status.png)
     skin/calendar/calendar-task-tree.css                   (themes/common/calendar-task-tree.css)
     skin/calendar/daypicker-background.png                 (themes/common/images/daypicker-background.png)
     skin/calendar/day-box-item-image.png                   (themes/common/images/day-box-item-image.png)
+    skin/calendar/event-dialog-keepduration-button.png     (themes/common/images/event-dialog-keepduration-button.png)
     skin/calendar/event-grippy-bottom.png                  (themes/common/images/event-grippy-bottom.png)
     skin/calendar/event-grippy-left.png                    (themes/common/images/event-grippy-left.png)
     skin/calendar/event-grippy-right.png                   (themes/common/images/event-grippy-right.png)
     skin/calendar/event-grippy-top.png                     (themes/common/images/event-grippy-top.png)
     skin/calendar/gradient-overlay.png                     (themes/common/images/gradient-overlay.png)
     skin/calendar/mini-day-background.png                  (themes/common/images/mini-day-background.png)
     skin/calendar/unifinder-images.png                     (themes/common/images/unifinder-images.png)
     skin/calendar/timezone_map.png                         (themes/common/images/timezone_map.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7e070a02a2449e440d3206f443f148b71fa1f4ae
GIT binary patch
literal 1752
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
--- a/calendar/base/themes/pinstripe/dialogs/calendar-event-dialog.css
+++ b/calendar/base/themes/pinstripe/dialogs/calendar-event-dialog.css
@@ -15,16 +15,17 @@
  *
  * The Initial Developer of the Original Code is Sun Microsystems.
  * Portions created by the Initial Developer are Copyright (C) 2006
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Michael Buettner <michael.buettner@sun.com>
  *   Markus Adrario <Mozilla@Adrario.de>
+ *   Gianfranco Balza <bv1578@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -49,16 +50,66 @@ label.label {
 #item-categories,
 #item-repeat,
 #item-alarm,
 .datepicker-text-class {
     min-width: 12em;
 }
 
 /*--------------------------------------------------------------------
+ *   Event dialog keep duration button
+ *-------------------------------------------------------------------*/
+
+#keepduration-button {
+    list-style-image: url(chrome://calendar/skin/event-dialog-keepduration-button.png);
+    -moz-image-region: rect(0px 14px 24px 7px);
+    padding: 3px;
+    -moz-padding-start: 6px;
+    -moz-padding-end: 6px;
+    -moz-margin-start: -3px;
+    margin-bottom: -15px;
+    position: relative;
+    -moz-user-focus: normal;
+}
+
+#keepduration-button[keep="true"] {
+    -moz-image-region: rect(0px 7px 24px 0px);
+}
+
+#keepduration-button[disabled="true"] {
+    -moz-image-region: rect(24px 14px 48px 7px);
+}
+
+#keepduration-button[keep="true"][disabled="true"] {
+    -moz-image-region: rect(24px 7px 48px 0px);
+}
+
+#keepduration-button > label {
+    display: none;
+}
+
+.keepduration-link-image {
+    list-style-image: url(chrome://calendar/skin/event-dialog-keepduration-button.png);
+}
+
+#link-image-top {
+    -moz-image-region: rect(0px 23px 6px 15px);
+    margin-top: 0.6em;
+}
+
+#link-image-bottom {
+    -moz-image-region: rect(18px 23px 24px 15px);
+    margin-bottom: 0.6em;
+}
+
+#timezone-endtime {
+    -moz-margin-start: 15px;
+}
+
+/*--------------------------------------------------------------------
  *   Event dialog toolbar buttons
  *-------------------------------------------------------------------*/
 
 .cal-toolbarbutton-2 {
     -moz-box-orient: vertical;
     min-width: 0px;
     list-style-image: url("chrome://calendar/skin/calendar-event-dialog-toolbar.png");
 }
--- a/calendar/base/themes/winstripe/dialogs/calendar-event-dialog.css
+++ b/calendar/base/themes/winstripe/dialogs/calendar-event-dialog.css
@@ -15,16 +15,17 @@
  *
  * The Initial Developer of the Original Code is Sun Microsystems.
  * Portions created by the Initial Developer are Copyright (C) 2006
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Michael Buettner <michael.buettner@sun.com>
  *   Markus Adrario <Mozilla@Adrario.de>
+ *   Gianfranco Balza <bv1578@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -49,16 +50,66 @@ label.label {
 #item-categories,
 #item-repeat,
 #item-alarm,
 .datepicker-text-class {
     min-width: 12em;
 }
 
 /*--------------------------------------------------------------------
+ *   Event dialog keep duration button
+ *-------------------------------------------------------------------*/
+
+#keepduration-button {
+    list-style-image: url(chrome://calendar/skin/event-dialog-keepduration-button.png);
+    -moz-image-region: rect(0px 14px 24px 7px);
+    padding: 3px;
+    -moz-padding-start: 6px;
+    -moz-padding-end: 6px;
+    -moz-margin-start: -3px;
+    margin-bottom: -15px;
+    position: relative;
+    -moz-user-focus: normal;
+}
+
+#keepduration-button[keep="true"] {
+    -moz-image-region: rect(0px 7px 24px 0px);
+}
+
+#keepduration-button[disabled="true"] {
+    -moz-image-region: rect(24px 14px 48px 7px);
+}
+
+#keepduration-button[keep="true"][disabled="true"] {
+    -moz-image-region: rect(24px 7px 48px 0px);
+}
+
+#keepduration-button > label {
+    display: none;
+}
+
+.keepduration-link-image {
+    list-style-image: url(chrome://calendar/skin/event-dialog-keepduration-button.png);
+}
+
+#link-image-top {
+    -moz-image-region: rect(0px 23px 6px 15px);
+    margin-top: 0.6em;
+}
+
+#link-image-bottom {
+    -moz-image-region: rect(18px 23px 24px 15px);
+    margin-bottom: 0.6em;
+}
+
+#timezone-endtime {
+    -moz-margin-start: 15px;
+}
+
+/*--------------------------------------------------------------------
  *   Event dialog toolbar buttons
  *-------------------------------------------------------------------*/
 
 .cal-toolbarbutton-2 {
     -moz-box-orient: vertical;
     min-width: 0px;
     list-style-image: url("chrome://calendar/skin/calendar-event-dialog-toolbar.png");
 }
--- a/calendar/locales/en-US/chrome/calendar/calendar-event-dialog.dtd
+++ b/calendar/locales/en-US/chrome/calendar/calendar-event-dialog.dtd
@@ -22,16 +22,17 @@
    -   C├ędric Corazza <cedric.corazza@wanadoo.fr>
    -   Michael Buettner <michael.buettner@sun.com>
    -   Philipp Kewisch <mozilla@kewis.ch>
    -   Stefan Sitter <ssitter@gmail.com>
    -   Martin Schroeder <mschroeder@mozilla.x-home.org>
    -   Hubert Gajewski <hubert@hubertgajewski.com>, Aviary.pl
    -   Fred Jendrzejewski <fred.jen@web.de>
    -   Simon Vaillancourt <simon.at.orcl@gmail.com>   
+   -   Gianfranco Balza <bv1578@gmail.com>
    -
    - Alternatively, the contents of this file may be used under the terms of
    - either the GNU General Public License Version 2 or later (the "GPL"), or
    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
    - in which case the provisions of the GPL or the LGPL are applicable instead
    - of those above. If you wish to allow use of your version of this file only
    - under the terms of either the GPL or the LGPL, and not to allow others to
    - use your version of this file under the terms of the MPL, indicate your
@@ -39,16 +40,17 @@
    - 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 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
@@ -20,16 +20,17 @@
 #
 # Contributor(s): ArentJan Banck <ajbanck@planet.nl>
 #                 Eric Belhaire <belhaire@ief.u-psud.fr>
 #                 Philipp Kewisch <mozilla@kewis.ch>
 #                 Berend Cornelius <berend.cornelius@sun.com>
 #                 Diego Mira David <diegomd86@gmail.com>
 #                 Eduardo Teruo Katayama <eduardo@ime.usp.br>
 #                 Glaucus Augustus Grecco Cardoso <glaucus@ime.usp.br>
+#                 Gianfranco Balza <bv1578@gmail.com>
 #
 # Alternatively, the contents of this file may be used under the terms of
 # either the GNU General Public License Version 2 or later (the "GPL"), or
 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 # in which case the provisions of the GPL or the LGPL are applicable instead
 # of those above. If you wish to allow use of your version of this file only
 # under the terms of either the GPL or the LGPL, and not to allow others to
 # use your version of this file under the terms of the MPL, indicate your
@@ -58,17 +59,18 @@ 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
-warningNegativeDuration=The end date you entered occurs before the start date
+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