home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2006 June / PCpro_2006_06.ISO / files / firefox / calendar_windows_latest.xpi / components / calCalendarManager.js < prev    next >
Encoding:
Text File  |  2005-12-04  |  14.4 KB  |  424 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 Oracle Corporation
  18.  * Portions created by the Initial Developer are Copyright (C) 2005
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *   Stuart Parmenter <stuart.parmenter@oracle.com>
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38.  
  39. const kStorageServiceContractID = "@mozilla.org/storage/service;1";
  40. const kStorageServiceIID = Components.interfaces.mozIStorageService;
  41.  
  42. const kMozStorageStatementWrapperContractID = "@mozilla.org/storage/statement-wrapper;1";
  43. const kMozStorageStatementWrapperIID = Components.interfaces.mozIStorageStatementWrapper;
  44. var MozStorageStatementWrapper = null;
  45.  
  46. function createStatement (dbconn, sql) {
  47.     var stmt = dbconn.createStatement(sql);
  48.     var wrapper = MozStorageStatementWrapper();
  49.     wrapper.initialize(stmt);
  50.     return wrapper;
  51. }
  52.  
  53. function onCalCalendarManagerLoad() {
  54.     MozStorageStatementWrapper = new Components.Constructor(kMozStorageStatementWrapperContractID, kMozStorageStatementWrapperIID);
  55. }
  56.  
  57. function calCalendarManager() {
  58.     this.wrappedJSObject = this;
  59.     this.initDB();
  60.     this.mCache = {};
  61.     this.setUpReadOnlyObservers();
  62. }
  63.  
  64. function makeURI(uriString)
  65. {
  66.     var ioservice = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService);
  67.     return ioservice.newURI(uriString, null, null);
  68. }
  69.  
  70. var calCalendarManagerClassInfo = {
  71.     getInterfaces: function (count) {
  72.         var ifaces = [
  73.             Components.interfaces.nsISupports,
  74.             Components.interfaces.calICalendarManager,
  75.             Components.interfaces.nsIClassInfo
  76.         ];
  77.         count.value = ifaces.length;
  78.         return ifaces;
  79.     },
  80.  
  81.     getHelperForLanguage: function (language) {
  82.         return null;
  83.     },
  84.  
  85.     contractID: "@mozilla.org/calendar/manager;1",
  86.     classDescription: "Calendar Manager",
  87.     classID: Components.ID("{f42585e7-e736-4600-985d-9624c1c51992}"),
  88.     implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
  89.     flags: 0
  90. };
  91.  
  92. calCalendarManager.prototype = {
  93.     QueryInterface: function (aIID) {
  94.         if (aIID.equals(Components.interfaces.nsIClassInfo))
  95.             return calCalendarManagerClassInfo;
  96.  
  97.         if (!aIID.equals(Components.interfaces.nsISupports) &&
  98.             !aIID.equals(Components.interfaces.calICalendarManager))
  99.         {
  100.             throw Components.results.NS_ERROR_NO_INTERFACE;
  101.         }
  102.  
  103.         return this;
  104.     },
  105.  
  106.     // When a calendar fails, its onError doesn't point back to the calendar.
  107.     // Therefore, we add a new announcer for each calendar to tell the user that
  108.     // a specific calendar has failed.  The calendar itself is responsible for
  109.     // putting itself in readonly mode.
  110.     setUpReadOnlyObservers: function() {
  111.         var calendars = this.getCalendars({});
  112.         for each(calendar in calendars) {
  113.             var newObserver = new errorAnnouncer(calendar);
  114.             calendar.addObserver(newObserver.observer);
  115.         }
  116.     },
  117.  
  118.     initDB: function() {
  119.         var sqlTables = { cal_calendars: "id INTEGER PRIMARY KEY, type STRING, uri STRING",
  120.                           cal_calendars_prefs: "id INTEGER PRIMARY KEY, calendar INTEGER, name STRING, value STRING"
  121.         };
  122.  
  123.         var dbService = Components.classes[kStorageServiceContractID].getService(kStorageServiceIID);
  124.  
  125.     if ( "getProfileStorage" in dbService ) {
  126.       // 1.8 branch
  127.       this.mDB = dbService.getProfileStorage("profile");
  128.     } else {
  129.       // trunk 
  130.       this.mDB = dbService.openSpecialDatabase("profile");
  131.     }
  132.  
  133.         for (table in sqlTables) {
  134.             try {
  135.                 this.mDB.createTable(table, sqlTables[table]);
  136.             } catch (ex) {
  137.                 dump("error creating table " + table + " -- probably already exists\n");
  138.             }
  139.         }
  140.  
  141.         this.mSelectCalendars = createStatement (
  142.             this.mDB,
  143.             "SELECT oid,* FROM cal_calendars");
  144.  
  145.         this.mFindCalendar = createStatement (
  146.             this.mDB,
  147.             "SELECT id FROM cal_calendars WHERE type = :type AND uri = :uri");
  148.  
  149.         this.mRegisterCalendar = createStatement (
  150.             this.mDB,
  151.             "INSERT INTO cal_calendars (type, uri) " +
  152.             "VALUES (:type, :uri)"
  153.             );
  154.  
  155.         this.mUnregisterCalendar = createStatement (
  156.             this.mDB,
  157.             "DELETE FROM cal_calendars WHERE id = :id"
  158.             );
  159.  
  160.         this.mGetPref = createStatement (
  161.             this.mDB,
  162.             "SELECT value FROM cal_calendars_prefs WHERE calendar = :calendar AND name = :name");
  163.  
  164.         this.mDeletePref = createStatement (
  165.             this.mDB,
  166.             "DELETE FROM cal_calendars_prefs WHERE calendar = :calendar AND name = :name");
  167.  
  168.         this.mInsertPref = createStatement (
  169.             this.mDB,
  170.             "INSERT INTO cal_calendars_prefs (calendar, name, value) " +
  171.             "VALUES (:calendar, :name, :value)");
  172.  
  173.         this.mDeletePrefs = createStatement (
  174.             this.mDB,
  175.             "DELETE FROM cal_calendars_prefs WHERE calendar = :calendar");
  176.  
  177.     },
  178.  
  179.     findCalendarID: function(calendar) {
  180.         var stmt = this.mFindCalendar;
  181.         stmt.reset();
  182.         var pp = stmt.params;
  183.         pp.type = calendar.type;
  184.         pp.uri = calendar.uri.spec;
  185.  
  186.         var id = -1;
  187.         if (stmt.step()) {
  188.             id = stmt.row.id;
  189.         }
  190.         stmt.reset();
  191.         return id;
  192.     },
  193.     
  194.     notifyObservers: function(functionName, args) {
  195.         function notify(obs) {
  196.             try { obs[functionName].apply(obs, args);  }
  197.             catch (e) { }
  198.         }
  199.         this.mObservers.forEach(notify);
  200.     },
  201.  
  202.     /**
  203.      * calICalendarManager interface
  204.      */
  205.     createCalendar: function(type, uri) {
  206.         var calendar = Components.classes["@mozilla.org/calendar/calendar;1?type=" + type].createInstance(Components.interfaces.calICalendar);
  207.         calendar.uri = uri;
  208.         return calendar;
  209.     },
  210.  
  211.     registerCalendar: function(calendar) {
  212.         // bail if this calendar (or one that looks identical to it) is already registered
  213.         if (this.findCalendarID(calendar) > 0) {
  214.             dump ("registerCalendar: calendar already registered\n");
  215.             throw Components.results.NS_ERROR_FAILURE;
  216.         }
  217.  
  218.         // Add an observer to track readonly-mode triggers
  219.         var newObserver = new errorAnnouncer(calendar);
  220.         calendar.addObserver(newObserver.observer);
  221.  
  222.         var pp = this.mRegisterCalendar.params;
  223.         pp.type = calendar.type;
  224.         pp.uri = calendar.uri.spec;
  225.  
  226.         this.mRegisterCalendar.step();
  227.         this.mRegisterCalendar.reset();
  228.         //dump("adding [" + this.mDB.lastInsertRowID + "]\n");
  229.         //this.mCache[this.mDB.lastInsertRowID] = calendar;
  230.         this.mCache[this.findCalendarID(calendar)] = calendar;
  231.  
  232.         this.notifyObservers("onCalendarRegistered", [calendar]);
  233.     },
  234.  
  235.     unregisterCalendar: function(calendar) {
  236.         this.notifyObservers("onCalendarUnregistering", [calendar]);
  237.  
  238.         var calendarID = this.findCalendarID(calendar);
  239.  
  240.         var pp = this.mUnregisterCalendar.params;
  241.         pp.id = calendarID;
  242.         this.mUnregisterCalendar.step();
  243.         this.mUnregisterCalendar.reset();
  244.  
  245.         // delete prefs for the calendar too
  246.         pp = this.mDeletePrefs.params;
  247.         pp.calendar = calendarID;
  248.         this.mDeletePrefs.step();
  249.         this.mDeletePrefs.reset();
  250.  
  251.         delete this.mCache[calendarID];
  252.     },
  253.  
  254.     deleteCalendar: function(calendar) {
  255.         /* check to see if calendar is unregistered first... */
  256.         /* delete the calendar for good */
  257.         
  258.         this.notifyObservers("onCalendarDeleting", [calendar]);
  259.     },
  260.  
  261.     getCalendars: function(count) {
  262.         var calendars = [];
  263.  
  264.         var stmt = this.mSelectCalendars;
  265.         stmt.reset();
  266.  
  267.         var newCalendarData = [];
  268.  
  269.         while (stmt.step()) {
  270.             var id = stmt.row.id;
  271.             if (!(id in this.mCache)) {
  272.                 newCalendarData.push ({id: id, type: stmt.row.type, uri: stmt.row.uri });
  273.             }
  274.         }
  275.         stmt.reset();
  276.  
  277.         for each (var caldata in newCalendarData) {
  278.             try {
  279.                 this.mCache[caldata.id] = this.createCalendar(caldata.type, makeURI(caldata.uri));
  280.             } catch (e) {
  281.                 dump("Can't create calendar for " + caldata.id + " (" + caldata.type + ", " + 
  282.                      caldata.uri + "): " + e + "\n");
  283.                 continue;
  284.             }
  285.         }
  286.  
  287.         for each (var cal in this.mCache)
  288.             calendars.push (cal);
  289.  
  290.         count.value = calendars.length;
  291.         return calendars;
  292.     },
  293.  
  294.     getCalendarPref: function(calendar, name) {
  295.         // pref names must be lower case
  296.         name = name.toLowerCase();
  297.  
  298.         var stmt = this.mGetPref;
  299.         stmt.reset();
  300.         var pp = stmt.params;
  301.         pp.calendar = this.findCalendarID(calendar);
  302.         pp.name = name;
  303.  
  304.         var value = null;
  305.         if (stmt.step()) {
  306.             value = stmt.row.value;
  307.         }
  308.         stmt.reset();
  309.         return value;
  310.     },
  311.  
  312.     setCalendarPref: function(calendar, name, value) {
  313.         // pref names must be lower case
  314.         name = name.toLowerCase();
  315.  
  316.         var calendarID = this.findCalendarID(calendar);
  317.  
  318.         this.mDB.beginTransaction();
  319.  
  320.         var pp = this.mDeletePref.params;
  321.         pp.calendar = calendarID;
  322.         pp.name = name;
  323.         this.mDeletePref.step();
  324.         this.mDeletePref.reset();
  325.  
  326.         pp = this.mInsertPref.params;
  327.         pp.calendar = calendarID;
  328.         pp.name = name;
  329.         pp.value = value;
  330.         this.mInsertPref.step();
  331.         this.mInsertPref.reset();
  332.  
  333.         this.mDB.commitTransaction();
  334.  
  335.         this.notifyObservers("onCalendarPrefSet", [calendar, name, value])
  336.     },
  337.  
  338.     deleteCalendarPref: function(calendar, name) {
  339.         // pref names must be lower case
  340.         name = name.toLowerCase();
  341.  
  342.         this.notifyObservers("onCalendarPrefDeleting", [calendar, name]);
  343.  
  344.         var calendarID = this.findCalendarID(calendar);
  345.  
  346.         var pp = this.mDeletePref.params;
  347.         pp.calendar = calendarID;
  348.         pp.name = name;
  349.         this.mDeletePref.step();
  350.         this.mDeletePref.reset();
  351.     },
  352.  
  353.     mObservers: Array(),
  354.     addObserver: function(aObserver) {
  355.         if (this.mObservers.indexOf(aObserver) != -1)
  356.             return;
  357.  
  358.         this.mObservers.push(aObserver);
  359.     },
  360.  
  361.     removeObserver: function(aObserver) {
  362.         function notThis(v) {
  363.             return v != aObserver;
  364.         }
  365.         
  366.         this.mObservers = this.mObservers.filter(notThis);
  367.     }
  368. };
  369.  
  370. // This is a prototype object for announcing the fact that a calendar error has
  371. // happened and that the calendar has therefore been put in readOnly mode.  We
  372. // implement a new one of these for each calendar registered to the calmgr.
  373. function errorAnnouncer(calendar) {
  374.     this.calendar = calendar;
  375.     // We compare this to determine if the state actually changed.
  376.     this.storedReadOnly = calendar.readOnly;
  377.     var announcer = this;
  378.     this.observer = {
  379.         onStartBatch: function() {},
  380.         onEndBatch: function() {},
  381.         onLoad: function() {},
  382.         onAddItem: function(aItem) {},
  383.         onModifyItem: function(aNewItem, aOldItem) {},
  384.         onDeleteItem: function(aDeletedItem) {},
  385.         onAlarm: function(aAlarmItem) {},
  386.         onError: function(aErrNo, aMessage) {
  387.             announcer.announceError(aErrNo, aMessage);
  388.         }
  389.     }
  390. }
  391.  
  392. errorAnnouncer.prototype.announceError = function(aErrNo, aMessage) {
  393.     var paramBlock = Components.classes["@mozilla.org/embedcomp/dialogparam;1"]
  394.                                .createInstance(Components.interfaces.nsIDialogParamBlock);
  395.     var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
  396.                         .getService(Components.interfaces.nsIStringBundleService);
  397.     var props = sbs.createBundle("chrome://calendar/locale/calendar.properties");
  398.     var errMsg;
  399.     paramBlock.SetNumberStrings(3);
  400.     if (!this.storedReadOnly && this.calendar.readOnly) {
  401.         // Major errors change the calendar to readOnly
  402.         errMsg = props.formatStringFromName("readOnlyMode", [this.calendar.name], 1);
  403.     } else if (!this.storedReadOnly && !this.calendar.readOnly) {
  404.         // Minor errors don't, but still tell the user something went wrong
  405.         errMsg = props.formatStringFromName("minorError", [this.calendar.name], 1);
  406.     } else {
  407.         // The calendar was already in readOnly mode, but still tell the user
  408.         errMsg = props.formatStringFromName("stillReadOnlyError", [this.calendar.name], 1);
  409.     }
  410.     paramBlock.SetString(0, errMsg);
  411.     paramBlock.SetString(1, "0x"+aErrNo.toString(16));
  412.     paramBlock.SetString(2, aMessage);
  413.  
  414.     this.storedReadOnly = this.calendar.readOnly;
  415.  
  416.     var wWatcher = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  417.                              .getService(Components.interfaces.nsIWindowWatcher);
  418.     wWatcher.openWindow(null,
  419.                         "chrome://calendar/content/calErrorPrompt.xul",
  420.                         "_blank",
  421.                         "chrome,dialog=yes",
  422.                         paramBlock);
  423. }
  424.