Fix bug 611973 - Sorting Order of Reminders / Alarms. r=philipp
authorRoman Käppeler <rkaeppeler@web.de>
Mon, 16 May 2011 12:53:09 +0200
changeset 7783 ad5f8b0ed1c3aa1114deac05081ed4fec12c199c
parent 7782 434e600f3b8657bde8b94e6c44a797a89e59a974
child 7784 90c3929c5b5d13d2e677fff21e64cf0831f55e79
push idunknown
push userunknown
push dateunknown
reviewersphilipp
bugs611973
Fix bug 611973 - Sorting Order of Reminders / Alarms. r=philipp
calendar/base/content/dialogs/calendar-alarm-dialog.js
calendar/base/src/calUtils.js
--- a/calendar/base/content/dialogs/calendar-alarm-dialog.js
+++ b/calendar/base/content/dialogs/calendar-alarm-dialog.js
@@ -16,16 +16,17 @@
  * The Initial Developer of the Original Code is Oracle Corporation
  * Portions created by the Initial Developer are Copyright (C) 2005
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Stuart Parmenter <stuart.parmenter@oracle.com>
  *   Philipp Kewisch <mozilla@kewis.ch>
  *   Daniel Boelzle <daniel.boelzle@sun.com>
+ *   Roman Kaeppeler <rkaeppeler@web.de>
  *
  * 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
@@ -202,38 +203,61 @@ function setupTitle() {
     let alarmRichlist = document.getElementById("alarm-richlist");
     let reminders = alarmRichlist.childNodes.length;
 
     let title = PluralForm.get(reminders, calGetString("calendar", "alarmWindowTitle.label"));
     document.title = title.replace("#1", reminders);
 }
 
 /**
+ * Comparison function for the start date of a calendar item and
+ * the start date of a calendar-alarm-widget.
+ *
+ * @param aItem                 A calendar item for the comparison of the start date property
+ * @param calAlarmWidget        A calendar-alarm-widget for the start date comparison with the given calendar item
+ * @return                      1 - if the calendar item starts before the calendar-alarm-widget
+ *                             -1 - if the calendar-alarm-widget starts before the calendar item
+ *                              0 - otherwise
+ */
+function widgetAlarmComptor(aItem, calAlarmWidget) {
+
+    if (aItem == null || calAlarmWidget == null || calAlarmWidget.item == null) return -1;
+
+    // Get the dates to compare
+    let aDate = aItem[calGetStartDateProp(aItem)];
+    let bDate = calAlarmWidget.item[calGetStartDateProp(calAlarmWidget.item)];
+
+    return aDate.compare(bDate);
+}
+
+/**
  * Add an alarm widget for the passed alarm and item.
  *
  * @param aItem       The calendar item to add a widget for.
  * @param aAlarm      The alarm to add a widget for.
  */
 function addWidgetFor(aItem, aAlarm) {
     let widget = document.createElement("calendar-alarm-widget");
     let alarmRichlist = document.getElementById("alarm-richlist");
-    alarmRichlist.appendChild(widget);
+
+    // Add widgets sorted by start date ascending
+    binaryInsertNode(alarmRichlist, widget, aItem, widgetAlarmComptor, false);
 
     widget.item = aItem;
     widget.alarm = aAlarm;
     widget.addEventListener("snooze", onSnoozeAlarm, false);
     widget.addEventListener("dismiss", onDismissAlarm, false);
     widget.addEventListener("itemdetails", onItemDetails, false);
 
     setupTitle();
 
-    if (alarmRichlist.selectedIndex < 0) {
-        // Set the selected element if there is none yet. Since the onselect
-        // event causes scrolling, we don't want to process the event when
-        // adding widgets.
+    if (!alarmRichlist.userSelectedWidget) {
+        // Always select first widget of the list.
+        // Since the onselect event causes scrolling,
+        // we don't want to process the event when adding widgets.
         alarmRichlist.suppressOnSelect = true;
         alarmRichlist.selectedIndex = 0;
         alarmRichlist.suppressOnSelect = false;
     }
 
     window.focus();
     window.getAttention();
 }
@@ -287,10 +311,11 @@ function removeWidgetFor(aItem, aAlarm) 
  * Handler function called when an alarm entry in the richlistbox is selected
  *
  * @param event         The DOM event from the click action
  */
 function onSelectAlarm(event) {
     let richList = document.getElementById("alarm-richlist")
     if (richList == event.target) {
         richList.ensureElementIsVisible(richList.getSelectedItem(0));
+        richList.userSelectedWidget = true;
     }
 }
--- a/calendar/base/src/calUtils.js
+++ b/calendar/base/src/calUtils.js
@@ -17,16 +17,17 @@
  *   Joey Minta <jminta@gmail.com>
  * Portions created by the Initial Developer are Copyright (C) 2006
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Philipp Kewisch <mozilla@kewis.ch>
  *   Daniel Boelzle <daniel.boelzle@sun.com>
  *   Berend Cornelius <berend.cornelius@sun.com>
+ *   Roman Kaeppeler <rkaeppeler@web.de>
  *
  * 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
@@ -1808,16 +1809,47 @@ function binarySearch(itemArray, newItem
         comptor = function defaultComptor(a,b) {
             return a > b;
         }
     }
     return binarySearchInternal(0, itemArray.length - 1);
 }
 
 /**
+ * Insert a new node underneath the given parentNode, using binary search. See binarySearch
+ * for a note on how the comptor works.
+ *
+ * @param parentNode           The parent node underneath the new node should be inserted.
+ * @param inserNode            The node to insert
+ * @param aItem                The calendar item to add a widget for.
+ * @param comptor              A comparison function that can compare two nodes.
+ * @param discardDuplicates    Use the comptor function to check if the item in
+ *                               question is already in the array. If so, the
+ *                               new item is not inserted.
+ */
+function binaryInsertNode(parentNode, insertNode, aItem, comptor, discardDuplicates) {
+
+    // Get the index of the node before which the inserNode will be inserted
+    var newIndex = binarySearch(parentNode.childNodes, aItem, comptor);
+
+    if (newIndex < 0) {
+        parentNode.appendChild(insertNode);
+        newIndex = 0;
+    } else if (!discardDuplicates ||
+        comptor(parentNode.childNodes[Math.min(newIndex, parentNode.childNodes.length - 1)], insertNode) >= 0) {
+
+        // Only add the node if duplicates should not be discarded, or if
+        // they should and the childNode[newIndex] == node.
+        let node = parentNode.childNodes[newIndex];
+        parentNode.insertBefore(insertNode, node);
+    }
+    return newIndex;
+}
+
+/**
  * Insert an item into the given array, using binary search. See binarySearch
  * for a note on how the comptor works.
  *
  * @param itemArray             The array to insert into.
  * @param item                  The item to insert into the array.
  * @param comptor               A comparation function that can compare two items.
  * @param discardDuplicates     Use the comptor function to check if the item in
  *                                question is already in the array. If so, the