home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2006 June / PCpro_2006_06.ISO / files / firefox / calendar_windows_latest.xpi / components / calCompositeCalendar.js < prev    next >
Encoding:
JavaScript  |  2005-11-07  |  16.4 KB  |  507 lines

  1. /* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is Oracle Corporation code.
  16.  *
  17.  * The Initial Developer of the Original Code is
  18.  *  Oracle Corporation
  19.  * Portions created by the Initial Developer are Copyright (C) 2004
  20.  * the Initial Developer. All Rights Reserved.
  21.  *
  22.  * Contributor(s):
  23.  *   Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
  24.  *
  25.  * Alternatively, the contents of this file may be used under the terms of
  26.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  27.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  28.  * in which case the provisions of the GPL or the LGPL are applicable instead
  29.  * of those above. If you wish to allow use of your version of this file only
  30.  * under the terms of either the GPL or the LGPL, and not to allow others to
  31.  * use your version of this file under the terms of the MPL, indicate your
  32.  * decision by deleting the provisions above and replace them with the notice
  33.  * and other provisions required by the GPL or the LGPL. If you do not delete
  34.  * the provisions above, a recipient may use your version of this file under
  35.  * the terms of any one of the MPL, the GPL or the LGPL.
  36.  *
  37.  * ***** END LICENSE BLOCK ***** */
  38.  
  39. //
  40. // calCompositeCalendar.js
  41. //
  42.  
  43. const calIOperationListener = Components.interfaces.calIOperationListener;
  44.  
  45. function calCompositeCalendarObserverHelper (compCalendar) {
  46.     this.compCalendar = compCalendar;
  47. }
  48.  
  49. calCompositeCalendarObserverHelper.prototype = {
  50.     QueryInterface: function (aIID) {
  51.         if (!aIID.equals(Components.interfaces.calIObserver) &&
  52.             !aIID.equals(Components.interfaces.nsISupports))
  53.         {
  54.             throw Components.results.NS_ERROR_NO_INTERFACE;
  55.         }
  56.  
  57.         return this;
  58.     },
  59.  
  60.     // We could actually reach up into our caller for method name
  61.     // and arguments, but it hardly seems worth it.
  62.     notifyObservers: function(method, args) {
  63.         this.compCalendar.mObservers.forEach(function (o) {
  64.             try { o[method].apply(o, args); }
  65.             catch (e) { }
  66.         });
  67.     },
  68.     
  69.     onStartBatch: function() {
  70.         this.notifyObservers("onStartBatch");
  71.     },
  72.  
  73.     onEndBatch: function() {
  74.         this.notifyObservers("onEndBatch");
  75.     },
  76.  
  77.     onLoad: function() {
  78.         this.notifyObservers("onLoad");
  79.     },
  80.  
  81.     onAddItem: function(aItem) {
  82.         this.notifyObservers("onAddItem", arguments);
  83.     },
  84.  
  85.     onModifyItem: function(aNewItem, aOldItem) {
  86.         this.notifyObservers("onModifyItem", arguments);
  87.     },
  88.  
  89.     onDeleteItem: function(aDeletedItem) {
  90.         this.notifyObservers("onDeleteItem", arguments);
  91.     },
  92.  
  93.     onAlarm: function(aAlarmItem) {
  94.         this.notifyObservers("onAlarm", arguments);
  95.     },
  96.  
  97.     onError: function(aErrNo, aMessage) {
  98.         this.notifyObservers("onError", arguments);
  99.     }
  100. };
  101.  
  102. function calCompositeCalendar () {
  103.     this.mObserverHelper = new calCompositeCalendarObserverHelper(this);
  104.     this.wrappedJSObject = this;
  105. }
  106.  
  107. calCompositeCalendar.prototype = {
  108.     //
  109.     // private members
  110.     //
  111.     mCalendars: Array(),
  112.     mDefaultCalendar: null,
  113.  
  114.     //
  115.     // nsISupports interface
  116.     //
  117.     QueryInterface: function (aIID) {
  118.         if (!aIID.equals(Components.interfaces.nsISupports) &&
  119.             !aIID.equals(Components.interfaces.calICalendar) &&
  120.             !aIID.equals(Components.interfaces.calICompositeCalendar))
  121.         {
  122.             throw Components.results.NS_ERROR_NO_INTERFACE;
  123.         }
  124.  
  125.         return this;
  126.     },
  127.  
  128.     //
  129.     // calICompositeCalendar interface
  130.     //
  131.  
  132.     mCalendars: Array(),
  133.     mDefaultCalendar: null,
  134.     mPrefPrefix: null,
  135.     mDefaultPref: null,
  136.     mActivePref: null,
  137.     _mCalMgr: null,
  138.     get mCalMgr () {
  139.         if (!this._mCalMgr) {
  140.             this._mCalMgr = Components.
  141.                 classes["@mozilla.org/calendar/manager;1"].
  142.                 getService(Components.interfaces.calICalendarManager);
  143.         }
  144.         return this._mCalMgr;
  145.     },
  146.     
  147.     set prefPrefix (aPrefPrefix) {
  148.         if (this.mPrefPrefix) {
  149.             this.mCalendars.forEach(this.removeCalendar, this);
  150.         }
  151.         this.mPrefPrefix = aPrefPrefix;
  152.         this.mActivePref = aPrefPrefix + "-in-composite";
  153.         this.mDefaultPref = aPrefPrefix + "-default";
  154.         var mgr = this.mCalMgr;
  155.         var cals = mgr.getCalendars({});
  156.  
  157.         cals.forEach(function (c) {
  158.             if (mgr.getCalendarPref(c, this.mActivePref))
  159.                 this.addCalendar(c);
  160.             if (mgr.getCalendarPref(c, this.mDefaultPref))
  161.                 this.setDefaultCalendar(c, false);
  162.         }, this);
  163.     },
  164.  
  165.     get prefPrefix () {
  166.         return this.mPrefPrefix;
  167.     },
  168.  
  169.     addCalendar: function (aCalendar) {
  170.         // check if the calendar already exists
  171.         for each (cal in this.mCalendars) {
  172.             if (aCalendar.uri.equals(cal.uri)) {
  173.                 // throw exception if calendar already exists?
  174.                 return;
  175.             }
  176.         }
  177.  
  178.         // add our observer helper
  179.         aCalendar.addObserver(this.mObserverHelper);
  180.  
  181.         this.mCalendars.push(aCalendar);
  182.         if (this.mPrefPrefix) {
  183.             this.mCalMgr.setCalendarPref(aCalendar, this.mActivePref,
  184.                                          "true");
  185.         }
  186.         this.notifyObservers("onCalendarAdded", [aCalendar]);
  187.  
  188.         // if we have no default calendar, we need one here
  189.         if (this.mDefaultCalendar == null)
  190.             this.setDefaultCalendar(aCalendar, false);
  191.     },
  192.  
  193.     removeCalendar: function (aServer) {
  194.         var newCalendars = Array();
  195.         var calToRemove = null;
  196.         for each (cal in this.mCalendars) {
  197.             if (!aServer.equals(cal.uri))
  198.                 newCalendars.push(cal);
  199.             else
  200.                 calToRemove = cal;
  201.         }
  202.  
  203.         if (calToRemove) {
  204.             this.mCalendars = newCalendars;
  205.             if (this.mPrefPrefix) {
  206.                 this.mCalMgr.deleteCalendarPref(calToRemove,
  207.                                                 this.mActivePref);
  208.                 this.mCalMgr.deleteCalendarPref(calToRemove,
  209.                                                 this.mDefaultPref);
  210.             }   
  211.             calToRemove.removeObserver(this.mObserverHelper);
  212.             this.notifyObservers("onCalendarRemoved", [calToRemove]);
  213.         }
  214.     },
  215.  
  216.     getCalendar: function (aServer) {
  217.         for each (cal in this.mCalendars) {
  218.             if (aServer.equals(cal.uri))
  219.                 return cal;
  220.         }
  221.  
  222.         return null;
  223.     },
  224.  
  225.     get calendars() {
  226.         // return a nsISimpleEnumerator of this array.  This sucks.
  227.         // XXX make this an array, like the calendar manager?
  228.         return null;
  229.     },
  230.  
  231.     get defaultCalendar() { 
  232.         return this.mDefaultCalendar;
  233.     },
  234.  
  235.     setDefaultCalendar: function (cal, usePref) {
  236.         if (this.mDefaultCalendar == cal) // .equals(uri) ??
  237.             return;
  238.         if (usePref && this.mPrefPrefix) {
  239.             this.mCalMgr.deleteCalendarPref(this.mDefaultCalendar,
  240.                                             this.mDefaultPref);
  241.             this.mCalMgr.setCalendarPref(cal, this.mDefaultPref,
  242.                                          "true");
  243.         }
  244.         this.mDefaultCalendar = cal;
  245.         this.notifyObservers("onDefaultCalendarChanged", [cal]);
  246.     },
  247.  
  248.     set defaultCalendar(v) {
  249.         this.setDefaultCalendar(v, true);
  250.     },
  251.  
  252.     //
  253.     // calICalendar interface
  254.     //
  255.     // Write operations here are forwarded to either the item's
  256.     // parent calendar, or to the default calendar if one is set.
  257.     // Get operations are sent to each calendar.
  258.     //
  259.  
  260.     // this could, at some point, return some kind of URI identifying
  261.     // all the child calendars, thus letting us create nifty calendar
  262.     // trees.
  263.     get uri() {
  264.         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  265.     },
  266.     set uri(v) {
  267.         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  268.     },
  269.  
  270.     get readOnly() { 
  271.         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  272.     },
  273.     set readOnly(bool) {
  274.         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  275.     },
  276.  
  277.     // void addObserver( in calIObserver observer );
  278.     mCompositeObservers: Array(),
  279.     mObservers: Array(),
  280.     addObserver: function (aObserver) {
  281.         const calICompositeObserver = Components.interfaces.calICompositeObserver;
  282.         if (aObserver instanceof calICompositeObserver) {
  283.             if (this.mCompositeObservers.indexOf(aObserver) == -1) {
  284.                 var compobs = aObserver.QueryInterface (calICompositeObserver);
  285.                 this.mCompositeObservers.push(compobs);
  286.             }
  287.         }
  288.  
  289.         if (this.mObservers.indexOf(aObserver) == -1)
  290.             this.mObservers.push(aObserver);
  291.     },
  292.  
  293.     // void removeObserver( in calIObserver observer );
  294.     removeObserver: function (aObserver) {
  295.         const calICompositeObserver = Components.interfaces.calICompositeObserver;
  296.         if (aObserver instanceof calICompositeObserver)
  297.             this.mCompositeObservers = this.mCompositeObservers.filter( function (v) { return v != aObserver; } );
  298.  
  299.         this.mObservers = this.mObservers.filter( function (v) { return v != aObserver; } );
  300.     },
  301.  
  302.     refresh: function() {
  303.         for each (cal in this.mCalendars) {
  304.             try { cal.refresh(); } catch (e) { }
  305.         }
  306.     },
  307.  
  308.     // void modifyItem( in calIItemBase aNewItem, in calIItemBase aOldItem, in calIOperationListener aListener );
  309.     modifyItem: function (aNewItem, aOldItem, aListener) {
  310.         if (aNewItem.calendar == null) {
  311.             // XXX Can't modify item with NULL parent
  312.             throw Components.results.NS_ERROR_FAILURE;
  313.         }
  314.  
  315.         aNewItem.calendar.modifyItem (aNewItem, aOldItem, aListener);
  316.     },
  317.  
  318.     // void deleteItem( in string id, in calIOperationListener aListener );
  319.     deleteItem: function (aItem, aListener) {
  320.         if (aItem.calendar == null) {
  321.             // XXX Can't delete item with NULL parent
  322.             throw Components.results.NS_ERROR_FAILURE;
  323.         }
  324.  
  325.         aItem.calendar.deleteItem (aItem, aListener);
  326.     },
  327.  
  328.     // void addItem( in calIItemBase aItem, in calIOperationListener aListener );
  329.     addItem: function (aItem, aListener) {
  330.         this.mDefaultCalendar.addItem (aItem, aListener);
  331.     },
  332.  
  333.     // void getItem( in string aId, in calIOperationListener aListener );
  334.     getItem: function (aId, aListener) {
  335.         var cmpListener = new calCompositeGetListenerHelper(this.mCalendars.length, aListener);
  336.         for each (cal in this.mCalendars) {
  337.             cal.getItem (aId, cmpListener);
  338.         }
  339.     },
  340.  
  341.     // void getItems( in unsigned long aItemFilter, in unsigned long aCount, 
  342.     //                in calIDateTime aRangeStart, in calIDateTime aRangeEnd,
  343.     //                in calIOperationListener aListener );
  344.     getItems: function (aItemFilter, aCount, aRangeStart, aRangeEnd, aListener) {
  345.         // If there are no calendars, then we just call onOperationComplete
  346.         if (this.mCalendars.length == 0) {
  347.             aListener.onOperationComplete (this,
  348.                                            Components.results.NS_OK,
  349.                                            calIOperationListener.GET,
  350.                                            null,
  351.                                            null);
  352.             return;
  353.         }
  354.  
  355.         var cmpListener = new calCompositeGetListenerHelper(this.mCalendars.length, aListener, aCount);
  356.         for (cal in this.mCalendars) {
  357.             this.mCalendars[cal].getItems (aItemFilter, aCount, aRangeStart, aRangeEnd, cmpListener);
  358.         }
  359.     },
  360.  
  361.     startBatch: function ()
  362.     {
  363.         this.notifyObservers("onStartBatch");
  364.     },
  365.     endBatch: function ()
  366.     {
  367.         this.notifyObservers("onEndBatch");
  368.     },
  369.  
  370.     //
  371.     // observer helpers
  372.     //
  373.     notifyObservers: function(method, args) {
  374.         this.mCompositeObservers.forEach(function (o) {
  375.             try { o[method].apply(o, args); }
  376.             catch (e) { }
  377.         });
  378.     }
  379. };
  380.  
  381. // composite listener helper
  382. function calCompositeGetListenerHelper(aNumQueries, aRealListener, aMaxItems) {
  383.     this.wrappedJSObject = this;
  384.     this.mNumQueries = aNumQueries;
  385.     this.mRealListener = aRealListener;
  386.     this.mMaxItems = aMaxItems;
  387. }
  388.  
  389. calCompositeGetListenerHelper.prototype = {
  390.     mNumQueries: 0,
  391.     mRealListener: null,
  392.     mReceivedCompletes: 0,
  393.     mFinished: false,
  394.     mMaxItems: 0,
  395.     mItemsReceived: 0,
  396.  
  397.     QueryInterface: function (aIID) {
  398.         if (!aIID.equals(Components.interfaces.nsISupports) &&
  399.             !aIID.equals(Components.interfaces.calIOperationListener))
  400.         {
  401.             throw Components.results.NS_ERROR_NO_INTERFACE;
  402.         }
  403.  
  404.         return this;
  405.     },
  406.  
  407.     onOperationComplete: function (aCalendar, aStatus, aOperationType, aId, aDetail) {
  408.         if (this.mFinished) {
  409.             dump ("+++ calCompositeGetListenerHelper.onOperationComplete: called with mFinished == true!");
  410.             return;
  411.         }
  412.  
  413.         if (!Components.isSuccessCode(aStatus)) {
  414.             // proxy this to a onGetResult
  415.             // XXX - do we want to give the real calendar? or this?
  416.             // XXX - get rid of iid param
  417.             this.mRealListener.onGetResult (aCalendar, aStatus, 
  418.                                             Components.interfaces.nsISupports,
  419.                                             aDetail, 0, []);
  420.         }
  421.  
  422.         this.mReceivedCompletes++;
  423.  
  424.         if (this.mReceivedCompletes == this.mNumQueries) {
  425.             // we're done here.
  426.             this.mRealListener.onOperationComplete (this,
  427.                                                     aOperationType,
  428.                                                     calIOperationListener.GET,
  429.                                                     null,
  430.                                                     null);
  431.             this.mFinished = true;
  432.         }
  433.     },
  434.  
  435.     onGetResult: function (aCalendar, aStatus, aItemType, aDetail, aCount, aItems) {
  436.         if (this.mFinished) {
  437.             dump ("+++ calCompositeGetListenerHelper.onGetResult: called with mFinished == true!");
  438.             return;
  439.         }
  440.  
  441.         // ignore if we have a max and we're past it
  442.         if (this.mMaxItems && this.mItemsReceived >= this.mMaxItems)
  443.             return;
  444.  
  445.         if (Components.isSuccessCode(aStatus) &&
  446.             this.mMaxItems &&
  447.             ((this.mItemsReceived + aCount) > this.mMaxItems))
  448.         {
  449.             // this will blow past the limit
  450.             aCount = this.mMaxItems - this.mItemsReceived;
  451.             aItems = aItems.slice(0, numToSend);
  452.         }
  453.  
  454.         // send GetResults to the real listener
  455.         this.mRealListener.onGetResult (aCalendar, aStatus, aItemType, aDetail, aCount, aItems);
  456.         this.mItemsReceived += aCount;
  457.     }
  458.  
  459. };
  460.  
  461.  
  462.  
  463. /****
  464.  **** module registration
  465.  ****/
  466.  
  467. var calCompositeCalendarModule = {
  468.     mCID: Components.ID("{aeff788d-63b0-4996-91fb-40a7654c6224}"),
  469.     mContractID: "@mozilla.org/calendar/calendar;1?type=composite",
  470.     
  471.     registerSelf: function (compMgr, fileSpec, location, type) {
  472.         compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  473.         compMgr.registerFactoryLocation(this.mCID,
  474.                                         "Calendar composite provider",
  475.                                         this.mContractID,
  476.                                         fileSpec,
  477.                                         location,
  478.                                         type);
  479.     },
  480.  
  481.     getClassObject: function (compMgr, cid, iid) {
  482.         if (!cid.equals(this.mCID))
  483.             throw Components.results.NS_ERROR_NO_INTERFACE;
  484.  
  485.         if (!iid.equals(Components.interfaces.nsIFactory))
  486.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  487.  
  488.         return this.mFactory;
  489.     },
  490.  
  491.     mFactory: {
  492.         createInstance: function (outer, iid) {
  493.             if (outer != null)
  494.                 throw Components.results.NS_ERROR_NO_AGGREGATION;
  495.             return (new calCompositeCalendar()).QueryInterface(iid);
  496.         }
  497.     },
  498.  
  499.     canUnload: function(compMgr) {
  500.         return true;
  501.     }
  502. };
  503.  
  504. function NSGetModule(compMgr, fileSpec) {
  505.     return calCompositeCalendarModule;
  506. }
  507.