Bug 1436557 - Move calOperationGroup to calDataUtils.jsm. r=MakeMyDay
authorPhilipp Kewisch <mozilla@kewis.ch>
Wed, 07 Feb 2018 23:23:34 +0100
changeset 31103 38e20522425aa554091b8204c62a5402099035ab
parent 31102 79de47fa45edc4bb9dc0de474dc6bdb8e7cf2d6f
child 31104 f1a768d1bbedee48bffeb53c11f0fa4273874941
push id383
push userclokep@gmail.com
push dateMon, 07 May 2018 21:52:48 +0000
reviewersMakeMyDay
bugs1436557
Bug 1436557 - Move calOperationGroup to calDataUtils.jsm. r=MakeMyDay MozReview-Commit-ID: BkVndYLfrOw
calendar/base/modules/calDataUtils.jsm
calendar/base/src/calCalendarSearchService.js
calendar/base/src/calFreeBusyService.js
calendar/base/src/calUtils.js
calendar/providers/composite/calCompositeCalendar.js
calendar/test/unit/test_utils.js
--- a/calendar/base/modules/calDataUtils.jsm
+++ b/calendar/base/modules/calDataUtils.jsm
@@ -86,20 +86,97 @@ class ObserverSet extends ListenerSet {
             for (let i = this.mBatchCount; i; i--) {
                 item.onStartBatch();
             }
         }
         super.add(item);
     }
 }
 
+/**
+ * This object implements calIOperation and could group multiple sub
+ * operations into one. You can pass a cancel function which is called once
+ * the operation group is cancelled.
+ * Users must call notifyCompleted() once all sub operations have been
+ * successful, else the operation group will stay pending.
+ * The reason for the latter is that providers currently should (but need
+ * not) implement (and return) calIOperation handles, thus there may be pending
+ * calendar operations (without handle).
+ */
+class OperationGroup {
+    static nextGroupId() {
+        if (typeof OperationGroup.mOpGroupId == "undefined") {
+            OperationGroup.mOpGroupId = 0;
+        }
+
+        return OperationGroup.mOpGroupId++;
+    }
+
+    constructor(aCancelFunc) {
+        this.mId = cal.getUUID() + "-" + OperationGroup.nextGroupId();
+        this.mIsPending = true;
+
+        this.mCancelFunc = aCancelFunc;
+        this.mSubOperations = [];
+        this.mStatus = Components.results.NS_OK;
+    }
+
+    get id() { return this.mId; }
+    get isPending() { return this.mIsPending; }
+    get status() { return this.mStatus; }
+    get isEmpty() { return this.mSubOperations.length == 0; }
+
+    add(aOperation) {
+        if (aOperation && aOperation.isPending) {
+            this.mSubOperations.push(aOperation);
+        }
+    }
+
+    remove(aOperation) {
+        if (aOperation) {
+            this.mSubOperations = this.mSubOperations.filter(operation => aOperation.id != operation.id);
+        }
+    }
+
+    notifyCompleted(aStatus) {
+        cal.ASSERT(this.isPending, "[OperationGroup_notifyCompleted] this.isPending");
+        if (this.isPending) {
+            this.mIsPending = false;
+            if (aStatus) {
+                this.mStatus = aStatus;
+            }
+        }
+    }
+
+    cancel(aStatus=Components.interfaces.calIErrors.OPERATION_CANCELLED) {
+        if (this.isPending) {
+            this.notifyCompleted(aStatus);
+            let cancelFunc = this.mCancelFunc;
+            if (cancelFunc) {
+                this.mCancelFunc = null;
+                cancelFunc();
+            }
+            let subOperations = this.mSubOperations;
+            this.mSubOperations = [];
+            for (let operation of subOperations) {
+                operation.cancel(Components.interfaces.calIErrors.OPERATION_CANCELLED);
+            }
+        }
+    }
+
+    toString() {
+        return `[OperationGroup id=${this.id}]`;
+    }
+}
+
 var caldata = {
     ListenerSet: ListenerSet,
     ObserverSet: ObserverSet,
     PropertyMap: PropertyMap,
+    OperationGroup: OperationGroup,
 
     /**
      * Use the binary search algorithm to search for an item in an array.
      * function.
      *
      * The comptor function may look as follows for calIDateTime objects.
      *     function comptor(a, b) {
      *         return a.compare(b);
--- a/calendar/base/src/calCalendarSearchService.js
+++ b/calendar/base/src/calCalendarSearchService.js
@@ -4,17 +4,17 @@
 
 ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 
 function calCalendarSearchListener(numOperations, finalListener) {
     this.mFinalListener = finalListener;
     this.mNumOperations = numOperations;
     this.mResults = [];
 
-    this.opGroup = new cal.calOperationGroup(() => {
+    this.opGroup = new cal.data.OperationGroup(() => {
         this.notifyResult(null);
     });
 }
 calCalendarSearchListener.prototype = {
     mFinalListener: null,
     mNumOperations: 0,
     opGroup: null,
 
--- a/calendar/base/src/calFreeBusyService.js
+++ b/calendar/base/src/calFreeBusyService.js
@@ -4,17 +4,17 @@
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://calendar/modules/calUtils.jsm");
 
 function calFreeBusyListener(numOperations, finalListener) {
     this.mFinalListener = finalListener;
     this.mNumOperations = numOperations;
 
-    this.opGroup = new cal.calOperationGroup(() => {
+    this.opGroup = new cal.data.OperationGroup(() => {
         this.notifyResult(null);
     });
 }
 calFreeBusyListener.prototype = {
     mFinalListener: null,
     mNumOperations: 0,
     opGroup: null,
 
--- a/calendar/base/src/calUtils.js
+++ b/calendar/base/src/calUtils.js
@@ -5,17 +5,17 @@
 /* This file contains commonly used functions in a centralized place so that
  * various components (and other js scopes) don't need to replicate them. Note
  * that loading this file twice in the same scope will throw errors.
  */
 
 /* exported getCalendarDirectory, attendeeMatchesAddresses,
  *          calTryWrappedJSObject, compareObjects, LOG, WARN, ERROR, showError,
  *          sendMailTo, applyAttributeToMenuChildren, isPropertyValueSame,
- *          calIterateEmailIdentities, calGetString
+ *          calIterateEmailIdentities, calGetString, getUUID
  */
 
 ChromeUtils.import("resource:///modules/mailServices.js");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/Preferences.jsm");
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
@@ -254,108 +254,16 @@ function sendMailTo(aRecipient, aSubject
     msgParams.format = Components.interfaces.nsIMsgCompFormat.Default;
     msgParams.composeFields = composeFields;
     msgParams.identity = aIdentity;
 
     MailServices.compose.OpenComposeWindowWithParams(null, msgParams);
 }
 
 /**
- * This object implements calIOperation and could group multiple sub
- * operations into one. You can pass a cancel function which is called once
- * the operation group is cancelled.
- * Users must call notifyCompleted() once all sub operations have been
- * successful, else the operation group will stay pending.
- * The reason for the latter is that providers currently should (but need
- * not) implement (and return) calIOperation handles, thus there may be pending
- * calendar operations (without handle).
- */
-function calOperationGroup(cancelFunc) {
-    this.wrappedJSObject = this;
-    if (calOperationGroup.mOpGroupId === undefined) {
-        calOperationGroup.mOpGroupId = 0;
-    }
-    if (calOperationGroup.mOpGroupPrefix === undefined) {
-        calOperationGroup.mOpGroupPrefix = getUUID() + "-";
-    }
-    this.mCancelFunc = cancelFunc;
-    this.mId = calOperationGroup.mOpGroupPrefix + calOperationGroup.mOpGroupId++;
-    this.mSubOperations = [];
-}
-calOperationGroup.prototype = {
-    mCancelFunc: null,
-    mId: null,
-    mIsPending: true,
-    mStatus: Components.results.NS_OK,
-    mSubOperations: null,
-
-    add: function(aOperation) {
-        if (aOperation && aOperation.isPending) {
-            this.mSubOperations.push(aOperation);
-        }
-    },
-
-    remove: function(aOperation) {
-        if (aOperation) {
-            this.mSubOperations = this.mSubOperations.filter(operation => aOperation.id != operation.id);
-        }
-    },
-
-    get isEmpty() {
-        return (this.mSubOperations.length == 0);
-    },
-
-    notifyCompleted: function(status) {
-        ASSERT(this.isPending, "[calOperationGroup_notifyCompleted] this.isPending");
-        if (this.isPending) {
-            this.mIsPending = false;
-            if (status) {
-                this.mStatus = status;
-            }
-        }
-    },
-
-    toString: function() {
-        return "[calOperationGroup] id=" + this.id;
-    },
-
-    // calIOperation:
-    get id() {
-        return this.mId;
-    },
-
-    get isPending() {
-        return this.mIsPending;
-    },
-
-    get status() {
-        return this.mStatus;
-    },
-
-    cancel: function(status) {
-        if (this.isPending) {
-            if (!status) {
-                status = Components.interfaces.calIErrors.OPERATION_CANCELLED;
-            }
-            this.notifyCompleted(status);
-            let cancelFunc = this.mCancelFunc;
-            if (cancelFunc) {
-                this.mCancelFunc = null;
-                cancelFunc();
-            }
-            let subOperations = this.mSubOperations;
-            this.mSubOperations = [];
-            for (let operation of subOperations) {
-                operation.cancel(Components.interfaces.calIErrors.OPERATION_CANCELLED);
-            }
-        }
-    }
-};
-
-/**
  * TODO: The following UI-related functions need to move somewhere different,
  * i.e calendar-ui-utils.js
  */
 
 
 /**
  * compares the value of a property of an array of objects and returns
  * true or false if it is same or not among all array members
--- a/calendar/providers/composite/calCompositeCalendar.js
+++ b/calendar/providers/composite/calCompositeCalendar.js
@@ -446,17 +446,17 @@ calCompositeGetListenerHelper.prototype 
     mOpGroup: null,
     mReceivedCompletes: 0,
     mFinished: false,
     mMaxItems: 0,
     mItemsReceived: 0,
 
     get opGroup() {
         if (!this.mOpGroup) {
-            this.mOpGroup = new cal.calOperationGroup(() => {
+            this.mOpGroup = new cal.data.OperationGroup(() => {
                 let listener = this.mRealListener;
                 this.mRealListener = null;
                 if (listener) {
                     listener.onOperationComplete(
                         this, Components.interfaces.calIErrors.OPERATION_CANCELLED,
                         calIOperationListener.GET, null, null);
                     if (this.mCompositeCalendar.statusDisplayed) {
                         this.mCompositeCalendar.mStatusObserver.stopMeteors();
--- a/calendar/test/unit/test_utils.js
+++ b/calendar/test/unit/test_utils.js
@@ -7,17 +7,17 @@ function run_test() {
 }
 
 function really_run_test() {
     test_recentzones();
     test_formatcss();
     test_attendeeMatchesAddresses();
     test_getDefaultStartDate();
     test_getStartEndProps();
-    test_calOperationGroup();
+    test_OperationGroup();
     test_sameDay();
     test_binarySearch();
 }
 
 function test_recentzones() {
     let oldDefaultTz = Preferences.get("calendar.timezone.local", "");
     Preferences.set("calendar.timezone.local", "floating");
 
@@ -117,27 +117,27 @@ function test_getStartEndProps() {
     equal(cal.dtz.endDateProp(cal.createTodo()), "dueDate");
 
     throws(() => cal.dtz.startDateProp(null),
            /2147500033/);
     throws(() => cal.dtz.endDateProp(null),
            /2147500033/);
 }
 
-function test_calOperationGroup() {
+function test_OperationGroup() {
     let cancelCalled = false;
     function cancelFunc() {
         cancelCalled = true;
         return true;
     }
 
-    let group = new cal.calOperationGroup(cancelFunc);
+    let group = new cal.data.OperationGroup(cancelFunc);
 
     ok(group.isEmpty);
-    equal(group.id, cal.calOperationGroup.mOpGroupPrefix + "0");
+    ok(group.id.endsWith("-0"));
     equal(group.status, Components.results.NS_OK);
     equal(group.isPending, true);
 
     let completedOp = { isPending: false };
 
     group.add(completedOp);
     ok(group.isEmpty);
     equal(group.isPending, true);