in-memory and mozStorage calICalendar providers initial checkin
git-svn-id: svn://10.0.0.236/trunk@165087 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
49
mozilla/calendar/providers/memory/Makefile.in
Normal file
49
mozilla/calendar/providers/memory/Makefile.in
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is the Oracle Corporation code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Oracle Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2004
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Vladimir Vukicevic <vladimir.vukicevic@oracle.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
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. 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 *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = calMemoryCalendar
|
||||
|
||||
EXTRA_COMPONENTS = calMemoryCalendar.js
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
316
mozilla/calendar/providers/memory/calMemoryCalendar.js
Normal file
316
mozilla/calendar/providers/memory/calMemoryCalendar.js
Normal file
@@ -0,0 +1,316 @@
|
||||
|
||||
//
|
||||
// calMemoryCalendar.js
|
||||
//
|
||||
|
||||
function calMemoryCalendar() {
|
||||
}
|
||||
|
||||
calMemoryCalendar.prototype = {
|
||||
//
|
||||
// private members
|
||||
//
|
||||
mObservers: Array(),
|
||||
mItems: Array(),
|
||||
|
||||
//
|
||||
// nsISupports interface
|
||||
//
|
||||
QueryInterface: function (aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.calICalendar))
|
||||
{
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
//
|
||||
// nsICalendar interface
|
||||
//
|
||||
|
||||
mBatchMode: false,
|
||||
// attribute boolean batchMode;
|
||||
get batchMode() { return this.mBatchMode; },
|
||||
set batchMode(aBatchMode) {
|
||||
this.mBatchMode = aBatchMode;
|
||||
},
|
||||
|
||||
// attribute nsIURI uri;
|
||||
get uri() { return false; },
|
||||
set uri(aURI) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; },
|
||||
|
||||
// attribute boolean suppressAlarms;
|
||||
get suppressAlarms() { return false; },
|
||||
set suppressAlarms(aSuppressAlarms) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; },
|
||||
|
||||
// XXX what happens when we add an observer that already exists with a different filter?
|
||||
// we can add them separately, but when we remove, we'll remove all instances
|
||||
// void addObserver( in calIObserver observer, in unsigned long aItemFilter );
|
||||
addObserver: function (aObserver, aItemFilter) {
|
||||
for (var i = 0; i < this.mObservers.length; i++) {
|
||||
if (this.mObservers[i].observer == aObserver &&
|
||||
this.mObservers[i].filter == aItemFilter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.mObservers.push( {observer: aObserver, filter: aItemFilter} );
|
||||
},
|
||||
|
||||
// void removeObserver( in calIObserver observer );
|
||||
removeObserver: function (aObserver) {
|
||||
var newObservers = Array();
|
||||
for (var i = 0; i < this.mObservers.length; i++) {
|
||||
if (this.mObservers[i].observer != aObserver)
|
||||
newObservers.push(mObservers[i]);
|
||||
}
|
||||
this.mObservers = newObservers;
|
||||
},
|
||||
|
||||
// void addItem( in calIItemBase aItem, in calIOperationListener aListener );
|
||||
addItem: function (aItem, aListener) {
|
||||
if (aItem.id == null) {
|
||||
// is this an error? Or should we generate an IID?
|
||||
}
|
||||
if (this.mItems[aItem.id] != null) {
|
||||
// is this an error?
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aItem.id,
|
||||
aListener.ADD,
|
||||
"ID already eists for addItem");
|
||||
return;
|
||||
}
|
||||
|
||||
this.mItems[aItem.id] = aItem;
|
||||
|
||||
// notify observers
|
||||
this.observeAddItem(aItem);
|
||||
|
||||
// notify the listener
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_OK,
|
||||
aItem.id,
|
||||
aListener.ADD,
|
||||
aItem);
|
||||
},
|
||||
|
||||
// void modifyItem( in calIItemBase aItem, in calIOperationListener aListener );
|
||||
modifyItem: function (aItem, aListener) {
|
||||
if (aItem.id == null ||
|
||||
this.mItems[aItem.id] == null)
|
||||
{
|
||||
// this is definitely an error
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aItem.id,
|
||||
aListener.MODIFY,
|
||||
"ID for modifyItem doesn't exist or is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// technically, they should be the same item
|
||||
var modifiedItem = this.mItems[aItem.id];
|
||||
this.mItems[aItem.id] = aItem;
|
||||
|
||||
// notify observers
|
||||
this.observeModifyItem(modifiedItem, aItem);
|
||||
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_OK,
|
||||
aItem.id,
|
||||
aListener.MODIFY,
|
||||
aItem);
|
||||
},
|
||||
|
||||
// void deleteItem( in string id, in calIOperationListener aListener );
|
||||
deleteItem: function (aId, aListener) {
|
||||
if (aId == null ||
|
||||
this.mItems[aId] == null)
|
||||
{
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aId,
|
||||
aListener.DELETE,
|
||||
"ID doesn't exist for deleteItem");
|
||||
return;
|
||||
}
|
||||
|
||||
deletedItem = this.mItems[aId];
|
||||
delete this.mItems[aId];
|
||||
|
||||
// notify observers
|
||||
observeDeleteItem(deletedItem);
|
||||
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_OK,
|
||||
aId,
|
||||
aListener.DELETE,
|
||||
null);
|
||||
|
||||
},
|
||||
|
||||
// void getItem( in string id, in calIOperationListener aListener );
|
||||
getItem: function (aId, aListener) {
|
||||
if (aId == null ||
|
||||
this.mItems[aId] == null)
|
||||
{
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aId,
|
||||
aListener.GET,
|
||||
"ID doesn't exist for getItem");
|
||||
return;
|
||||
}
|
||||
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_OK,
|
||||
aId,
|
||||
aListener.GET,
|
||||
this.mItems[aId]);
|
||||
},
|
||||
|
||||
// void getItems( in nsIIDRef aItemType, in unsigned long aItemFilter,
|
||||
// in unsigned long aCount, in calIDateTime aRangeStart,
|
||||
// in calIDateTime aRangeEnd,
|
||||
// in calIOperationListener aListener );
|
||||
getItems: function (aItemType, aItemFilter, aCount,
|
||||
aRangeStart, aRangeEnd, aListener)
|
||||
{
|
||||
// we ignore aItemFilter; we always return all items. if
|
||||
// aCount != 0, we don't attempt to sort anything, and instead
|
||||
// return the first aCount items that match.
|
||||
|
||||
var itemsFound = Array();
|
||||
var startTime = 0;
|
||||
// endTime needs to be the max value a PRTime can be
|
||||
var endTime = 0x7fffffffffffffff;
|
||||
if (aRangeStart)
|
||||
startTime = aRangeStart.utcTime;
|
||||
if (aRangeEnd)
|
||||
endTime = aRangeEnd.utcTime;
|
||||
|
||||
const calIEvent = Components.interfaces.calIEvent;
|
||||
const calITodo = Components.interfaces.calITodo;
|
||||
|
||||
for (var i = 0; i < this.mItems.length; i++) {
|
||||
var item = this.mItems[i];
|
||||
|
||||
if (aItemType)
|
||||
item = item.QueryInterface(aItemType);
|
||||
if (item) {
|
||||
var itemStartTime = 0;
|
||||
var itemEndTime = 0;
|
||||
|
||||
var tmpitem = item;
|
||||
if (aItemType == calIEvent ||
|
||||
(tmpitem = item.QueryInterface(calIEvent)) != null)
|
||||
{
|
||||
itemStartTime = tmpitem.startDate.utcTime;
|
||||
itemEndTime = tmpitem.endDate.utcTime;
|
||||
} else if (aItemType == calITodo ||
|
||||
(tmpitem = item.QueryInterface(calITodo)) != null)
|
||||
{
|
||||
itemStartTime = tmpitem.entryTime.utcTime;
|
||||
itemEndTime = tmpitem.entryTime.utcTime;
|
||||
} else {
|
||||
// XXX unknown item type, wth do we do?
|
||||
continue;
|
||||
}
|
||||
|
||||
// determine whether any endpoint falls within the range
|
||||
if ((itemStartTime >= startTime && itemEndTime <= endTime) ||
|
||||
(itemStartTime <= startTime && itemEndTime > startTime) ||
|
||||
(itemStartTime <= endTime && itemEndTime >= endTime))
|
||||
{
|
||||
itemsFound.push(item);
|
||||
}
|
||||
|
||||
if (aCount && itemsFound.length >= aCount)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (aListener)
|
||||
aListener.onGetComplete (Components.results.NS_OK,
|
||||
aItemType,
|
||||
null,
|
||||
itemsFound);
|
||||
},
|
||||
|
||||
// void reportError( in unsigned long errorid, in AUTF8String aMessage );
|
||||
reportError: function (aErrorId, aMessage)
|
||||
{
|
||||
},
|
||||
|
||||
//
|
||||
// Helper functions
|
||||
//
|
||||
observeBatchChange: function (aNewBatchMode) {
|
||||
for (var i = 0; i < this.mObservers.length; i++) {
|
||||
if (aNewBatchMode)
|
||||
this.mObservers[i].onStartBatch ();
|
||||
else
|
||||
this.mObservers[i].onEndBatch ();
|
||||
}
|
||||
},
|
||||
|
||||
observeAddItem: function (aItem) {
|
||||
for (var i = 0; i < this.mObservers.length; i++)
|
||||
this.mObservers[i].onAddItem (aItem);
|
||||
},
|
||||
|
||||
observeModifyItem: function (aOldItem, aNewItem) {
|
||||
for (var i = 0; i < this.mObservers.length; i++)
|
||||
this.mObservers[i].onModifyItem (aOldItem, aNewItem);
|
||||
},
|
||||
|
||||
observeDeleteItem: function (aDeletedItem) {
|
||||
for (var i = 0; i < this.mObservers.length; i++)
|
||||
this.mObservers[i].onDeleteItem (aDeletedItem);
|
||||
},
|
||||
}
|
||||
|
||||
/****
|
||||
**** module registration
|
||||
****/
|
||||
|
||||
var calStorageCalendarModule = {
|
||||
mCID: Components.ID("{bda0dd7f-0a2f-4fcf-ba08-5517e6fbf133}"),
|
||||
mContractID: "@mozilla.org/calendar/calendar;1&type=memory",
|
||||
|
||||
registerSelf: function (compMgr, fileSpec, location, type) {
|
||||
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
||||
compMgr.registerFactoryLocation(this.mCID,
|
||||
"Calendar in-memory back-end",
|
||||
this.mContractID,
|
||||
fileSpec,
|
||||
location,
|
||||
type);
|
||||
},
|
||||
|
||||
getClassObject: function (compMgr, cid, iid) {
|
||||
if (!cid.equals(this.mCID))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
|
||||
if (!iid.equals(Components.interfaces.nsIFactory))
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
return this.mFactory;
|
||||
},
|
||||
|
||||
mFactory: {
|
||||
createInstance: function (outer, iid) {
|
||||
if (outer != null)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
return (new calStorageCalendar()).QueryInterface(iid);
|
||||
}
|
||||
},
|
||||
|
||||
canUnload: function(compMgr) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
49
mozilla/calendar/providers/storage/Makefile.in
Normal file
49
mozilla/calendar/providers/storage/Makefile.in
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is the Oracle Corporation code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is Oracle Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2004
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Vladimir Vukicevic <vladimir.vukicevic@oracle.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
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. 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 *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = calStorageCalendar
|
||||
|
||||
EXTRA_COMPONENTS = calStorageCalendar.js
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
523
mozilla/calendar/providers/storage/calStorageCalendar.js
Normal file
523
mozilla/calendar/providers/storage/calStorageCalendar.js
Normal file
@@ -0,0 +1,523 @@
|
||||
|
||||
//
|
||||
// calStorageCalendar.js
|
||||
//
|
||||
|
||||
const kStorageServiceContractID = "@mozilla.org/storage/service;1";
|
||||
const kStorageServiceIID = Components.interfaces.mozIStorageService;
|
||||
|
||||
const kCalEventContractID = "@mozilla.org/calendar/item;1&type=event";
|
||||
const kCalEventIID = Components.interfaces.calIEvent;
|
||||
|
||||
const kCalDateTimeContractID = "@mozilla.org/calendar/datetime;1";
|
||||
const kCalDateTimeIID = Components.interfaces.calIDateTime;
|
||||
|
||||
// column ids in cal_events
|
||||
const EV_HASHID = 0;
|
||||
const EV_TITLE = 1;
|
||||
const EV_DESCRIPTION = 2;
|
||||
const EV_LOCATION = 3;
|
||||
const EV_CATEGORIES = 4;
|
||||
const EV_TIME_START = 5;
|
||||
const EV_TIME_END = 6;
|
||||
const EV_FLAGS = 7;
|
||||
const EV_LAST_MODIFIED = 8;
|
||||
const EV_ALARM_DATA = 9;
|
||||
const EV_ALARM_TIME = 10;
|
||||
const EV_RECUR_TYPE = 11;
|
||||
const EV_RECUR_INTERVAL = 12;
|
||||
const EV_RECUR_DATA = 13;
|
||||
const EV_RECUR_END = 14;
|
||||
const EV_RECUR_FLAGS = 15;
|
||||
|
||||
// helpers
|
||||
function newDateTime(aPRTime) {
|
||||
var t = Components.classes[kCalDateTimeContractID]
|
||||
.createInstance(kCalDateTimeIID);
|
||||
t.utcTime = aPRTime;
|
||||
return t;
|
||||
}
|
||||
|
||||
function calStorageCalendar() {
|
||||
}
|
||||
|
||||
calStorageCalendar.prototype = {
|
||||
//
|
||||
// private members
|
||||
//
|
||||
mObservers: Array(),
|
||||
mDB: null,
|
||||
mItemCache: Array(),
|
||||
|
||||
// database statements
|
||||
mSelectEventByHash: null,
|
||||
mSelectEventByOid: null,
|
||||
mSelectEventsByRange: null,
|
||||
mSelectEventsByRangeWithLimit: null,
|
||||
mDeleteEventByHash: null,
|
||||
mInsertEvent: null,
|
||||
|
||||
//
|
||||
// nsISupports interface
|
||||
//
|
||||
QueryInterface: function (aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.calICalendar))
|
||||
{
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
//
|
||||
// nsICalendar interface
|
||||
//
|
||||
|
||||
mBatchMode: false,
|
||||
// attribute boolean batchMode;
|
||||
get batchMode() { return this.mBatchMode; },
|
||||
set batchMode(aBatchMode) {
|
||||
this.mBatchMode = aBatchMode;
|
||||
|
||||
},
|
||||
|
||||
mURI: null,
|
||||
// attribute nsIURI uri;
|
||||
get uri() { return this.mURI; },
|
||||
set uri(aURI) {
|
||||
// we can only load once
|
||||
if (this.mURI)
|
||||
throw Components.results.NS_ERROR_FAILURE;
|
||||
|
||||
// we can only load storage bits from a file
|
||||
this.mURI = aURI;
|
||||
var fileURL = aURI.QueryInterface(Components.interfaces.nsIFileURL);
|
||||
if (!fileURL)
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
// open the database
|
||||
var dbService = Components.classes[kStorageServiceContractID]
|
||||
.getService(kStorageServiceIID);
|
||||
this.mDB = dbService.openDatabase (fileURL.file);
|
||||
|
||||
initDB();
|
||||
},
|
||||
|
||||
// attribute boolean suppressAlarms;
|
||||
get suppressAlarms() { return false; },
|
||||
set suppressAlarms(aSuppressAlarms) { throw Components.results.NS_ERROR_NOT_IMPLEMENTED; },
|
||||
|
||||
// XXX what happens when we add an observer that already exists with a different filter?
|
||||
// we can add them separately, but when we remove, we'll remove all instances
|
||||
// void addObserver( in calIObserver observer, in unsigned long aItemFilter );
|
||||
addObserver: function (aObserver, aItemFilter) {
|
||||
for (var i = 0; i < this.mObservers.length; i++) {
|
||||
if (this.mObservers[i].observer == aObserver &&
|
||||
this.mObservers[i].filter == aItemFilter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.mObservers.push( {observer: aObserver, filter: aItemFilter} );
|
||||
},
|
||||
|
||||
// void removeObserver( in calIObserver observer );
|
||||
removeObserver: function (aObserver) {
|
||||
var newObservers = Array();
|
||||
for (var i = 0; i < this.mObservers.length; i++) {
|
||||
if (this.mObservers[i].observer != aObserver)
|
||||
newObservers.push(this.mObservers[i]);
|
||||
}
|
||||
this.mObservers = newObservers;
|
||||
},
|
||||
|
||||
// void addItem( in calIItemBase aItem, in calIOperationListener aListener );
|
||||
addItem: function (aItem, aListener) {
|
||||
if (aItem.id == null) {
|
||||
// is this an error? Or should we generate an IID?
|
||||
}
|
||||
if (this.mItems[aItem.id] != null) {
|
||||
// is this an error?
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aItem.id,
|
||||
aListener.ADD,
|
||||
"ID already eists for addItem");
|
||||
return;
|
||||
}
|
||||
|
||||
// is this item an event?
|
||||
var event = aItem.QueryInterface(kCalEventIID);
|
||||
if (event) {
|
||||
flushEvent (event);
|
||||
} else {
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aItem.id,
|
||||
aListener.ADD,
|
||||
"Don't know how to add items of the given type");
|
||||
return;
|
||||
}
|
||||
|
||||
// notify observers
|
||||
observeAddItem(aItem);
|
||||
|
||||
// notify the listener
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_OK,
|
||||
aItem.id,
|
||||
aListener.ADD,
|
||||
aItem);
|
||||
},
|
||||
|
||||
// void modifyItem( in calIItemBase aItem, in calIOperationListener aListener );
|
||||
modifyItem: function (aItem, aListener) {
|
||||
if (aItem.id == null)
|
||||
{
|
||||
// this is definitely an error
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aItem.id,
|
||||
aListener.MODIFY,
|
||||
"ID for modifyItem item is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// is this item an event?
|
||||
var event = aItem.QueryInterface(kCalEventIID);
|
||||
if (event) {
|
||||
flushEvent (event);
|
||||
} else {
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aItem.id,
|
||||
aListener.MODIFY,
|
||||
"Don't know how to modify items of the given type");
|
||||
return;
|
||||
}
|
||||
|
||||
// notify observers
|
||||
observeModifyItem(modifiedItem, aItem);
|
||||
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_OK,
|
||||
aItem.id,
|
||||
aListener.MODIFY,
|
||||
aItem);
|
||||
},
|
||||
|
||||
// void deleteItem( in string id, in calIOperationListener aListener );
|
||||
deleteItem: function (aId, aListener) {
|
||||
if (aId == null)
|
||||
{
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aId,
|
||||
aListener.DELETE,
|
||||
"ID is null for deleteItem");
|
||||
return;
|
||||
}
|
||||
|
||||
// is this item an event?
|
||||
var event = aItem.QueryInterface(kCalEventIID);
|
||||
if (event) {
|
||||
deleteEvent (aId);
|
||||
} else {
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aItem.id,
|
||||
aListener.DELETE,
|
||||
"Don't know how to delete items of the given type");
|
||||
return;
|
||||
}
|
||||
|
||||
// notify observers XXX
|
||||
//observeDeleteItem(deletedItem);
|
||||
|
||||
if (aListener)
|
||||
aListener.onOperationComplete (Components.results.NS_OK,
|
||||
aId,
|
||||
aListener.DELETE,
|
||||
null);
|
||||
|
||||
},
|
||||
|
||||
// void getItem( in string id, in calIOperationListener aListener );
|
||||
getItem: function (aId, aListener) {
|
||||
if (!aListener)
|
||||
return;
|
||||
|
||||
// XXX what do we load from? this thing is horribly underspecified
|
||||
var item = getEventByHash (aId);
|
||||
if (item) {
|
||||
aListener.onOperationComplete (Components.results.NS_OK,
|
||||
aId,
|
||||
aListener.GET,
|
||||
item);
|
||||
} else {
|
||||
aListener.onOperationComplete (Components.results.NS_ERROR_FAILURE,
|
||||
aId,
|
||||
aListener.GET,
|
||||
"ID not found");
|
||||
}
|
||||
},
|
||||
|
||||
// void getItems( in nsIIDRef aItemType, in unsigned long aItemFilter,
|
||||
// in unsigned long aCount, in calIDateTime aRangeStart,
|
||||
// in calIDateTime aRangeEnd,
|
||||
// in calIOperationListener aListener );
|
||||
getItems: function (aItemType, aItemFilter, aCount,
|
||||
aRangeStart, aRangeEnd, aListener)
|
||||
{
|
||||
if (!aListener)
|
||||
return;
|
||||
|
||||
// we ignore aItemFilter; we always return all items. if
|
||||
// aCount != 0, we don't attempt to sort anything, and instead
|
||||
// return the first aCount items that match.
|
||||
|
||||
var itemsFound = Array();
|
||||
var startTime = 0;
|
||||
// endTime needs to be the max value a PRTime can be
|
||||
var endTime = 0x7fffffffffffffff;
|
||||
if (aRangeStart)
|
||||
startTime = aRangeStart.utcTime;
|
||||
if (aRangeEnd)
|
||||
endTime = aRangeEnd.utcTime;
|
||||
|
||||
if (aItemType != null && aItemType != kCalEventIID) {
|
||||
// we don't know what to do with anything but events for now
|
||||
aListener.onGetComplete(Components.results.NS_ERROR_FAILURE,
|
||||
aItemType,
|
||||
"Don't know how to get the requested item type",
|
||||
aCount, Array());
|
||||
return;
|
||||
}
|
||||
|
||||
var events = getEventsByRange();
|
||||
|
||||
if (aListener)
|
||||
aListener.onGetComplete (Components.results.NS_OK,
|
||||
aItemType,
|
||||
null,
|
||||
itemsFound);
|
||||
},
|
||||
|
||||
// void reportError( in unsigned long errorid, in AUTF8String aMessage );
|
||||
reportError: function (aErrorId, aMessage)
|
||||
{
|
||||
},
|
||||
|
||||
//
|
||||
// Helper functions
|
||||
//
|
||||
observeLoad: function () {
|
||||
for (var i = 0; i < mObservers.length; i++)
|
||||
mObservers[i].onLoad ();
|
||||
},
|
||||
|
||||
observeBatchChange: function (aNewBatchMode) {
|
||||
for (var i = 0; i < mObservers.length; i++) {
|
||||
if (aNewBatchMode)
|
||||
mObservers[i].onStartBatch ();
|
||||
else
|
||||
mObservers[i].onEndBatch ();
|
||||
}
|
||||
},
|
||||
|
||||
observeAddItem: function (aItem) {
|
||||
for (var i = 0; i < mObservers.length; i++)
|
||||
mObservers[i].onAddItem (aItem);
|
||||
},
|
||||
|
||||
observeModifyItem: function (aOldItem, aNewItem) {
|
||||
for (var i = 0; i < mObservers.length; i++)
|
||||
mObservers[i].onModifyItem (aOldItem, aNewItem);
|
||||
},
|
||||
|
||||
observeDeleteItem: function (aDeletedItem) {
|
||||
for (var i = 0; i < mObservers.length; i++)
|
||||
mObservers[i].onDeleteItem (aDeletedItem);
|
||||
},
|
||||
|
||||
// database initialization
|
||||
// assumes mDB is valid
|
||||
initDB: function () {
|
||||
try {
|
||||
mDB.createTable ("cal_events",
|
||||
"hashid, title, description, location, categories, " +
|
||||
"time_start, time_end, flags, last_modified, " +
|
||||
"alarm_data, alarm_time, " +
|
||||
"recur_type, recur_interval, recur_data, recur_end, recur_flags");
|
||||
mDB.createTable ("cal_event_recur_exceptions",
|
||||
"event_id, skip_date");
|
||||
mDB.createTable ("cal_event_attendees",
|
||||
"event_id, attendee, attendee_status");
|
||||
mDB.createTable ("cal_evnent_attachments",
|
||||
"event_id, attachment_type, attachment_data");
|
||||
|
||||
mDB.executeSimpleSQL ("CREATE INDEX cal_events_hash_idx ON cal_events.hashid");
|
||||
} catch (e) {
|
||||
// ...
|
||||
}
|
||||
|
||||
mSelectEventByHash = mDB.createStatement ("SELECT * FROM cal_events WHERE hashid = ? LIMIT 1");
|
||||
mSelectEventByOid = mDB.createStatement ("SELECT * FROM cal_events WHERE oid = ? LIMIT 1");
|
||||
// this needs to have the range bound like this: start, end, start, start, end, end
|
||||
mSelectEventsByRange = mDB.createStatement ("SELECT * FROM cal_events WHERE (time_start >= ? AND time_end <= ?) OR (time_start <= ? AND time_end > ?) OR (time_start <= ? AND time_end <= ?)");
|
||||
mSelectEventsByRangeAndLimit = mDB.createStatement ("SELECT * FROM cal_events WHERE (time_start >= ? AND time_end <= ?) OR (time_start <= ? AND time_end > ?) OR (time_start <= ? AND time_end <= ?) LIMIT ?");
|
||||
|
||||
mDeleteEventByHash = mDB.createStatement ("DELETE FROM cal_events WHERE hashid = ?");
|
||||
|
||||
// XXX create a function helper for this, too easy to screw up with all the ?'s
|
||||
mInsertEvent = mDB.createStatement ("INSERT INTO cal_events VALUES (?,?,?,?,?, ?,?,?,?,?, ?,?,?,?,?, ?)");
|
||||
},
|
||||
|
||||
// database helper functions
|
||||
getEventFromRow: function (aDBRow) {
|
||||
// create a new generic event
|
||||
var e = Components.classes[kCalEventContractID]
|
||||
.createInstance(kCalEventIID);
|
||||
|
||||
// read the data from the statement row
|
||||
// XXX do I need getAsPRTime?
|
||||
e.startDate = newDateTime (aDBRow.getAsInt64(EV_TIME_START));
|
||||
e.endDate = newDateTime (aDBRow.getAsInt64(EV_TIME_END));
|
||||
e.title = aDBRow.getAsString(EV_TITLE);
|
||||
e.description = aDBRow.getAsString(EV_DESCRIPTION);
|
||||
e.location = aDBRow.getAsString(EV_LOCATION);
|
||||
e.categories = aDBRow.getAsString(EV_CATEGORIES);
|
||||
|
||||
e.id = aID;
|
||||
e.parent = this;
|
||||
|
||||
return e;
|
||||
},
|
||||
|
||||
// get an event from the db or cache with the given ID
|
||||
getEventByHash: function (aID) {
|
||||
// cached?
|
||||
if (mEventHash[aID] != null)
|
||||
return mEventHash[aID];
|
||||
|
||||
var retval;
|
||||
|
||||
// not cached; need to read from the db
|
||||
mSelectEventByHash.bindCStringParameter (0, aID);
|
||||
if (mSelectEventByHash.executeStep()) {
|
||||
var e = getEventFromRow (mSelectEventByHash);
|
||||
retval = e;
|
||||
// stick into cache
|
||||
mEventHash[aID] = e;
|
||||
} else {
|
||||
// not found
|
||||
// throw? return null?
|
||||
retval = null;
|
||||
}
|
||||
|
||||
mSelectEventByHash.reset();
|
||||
|
||||
return retval;
|
||||
},
|
||||
|
||||
// get a list of events from the db in the given range
|
||||
getEventsByRange: function (aRangeStart, aRangeEnd, aCount) {
|
||||
var stmt = mSelectEventsByRange;
|
||||
if (aCount)
|
||||
stmt = mSelectEventsByRangeAndLimit;
|
||||
|
||||
stmt.bindInt64Parameter(0, aRangeStart);
|
||||
stmt.bindInt64Parameter(1, aRangeEnd);
|
||||
stmt.bindInt64Parameter(2, aRangeStart);
|
||||
stmt.bindInt64Parameter(3, aRangeStart);
|
||||
stmt.bindInt64Parameter(4, aRangeEnd);
|
||||
stmt.bindInt64Parameter(5, aRangeEnd);
|
||||
if (aCount)
|
||||
stmt.bindInt32Parameter(6, aCount);
|
||||
|
||||
var events = Array();
|
||||
while (stmt.executeStep()) {
|
||||
var e = getEventFromRow(stmt);
|
||||
events.push (e);
|
||||
mEventHash[e.id] = e;
|
||||
}
|
||||
|
||||
return events;
|
||||
},
|
||||
|
||||
// write this event's changed data to the db
|
||||
flushEvent: function (aEvent) {
|
||||
// set up statements before executing the transaction
|
||||
mDeleteEventByHash.bindCStringParameter (0, aEvent.id);
|
||||
|
||||
mInsertEvent.bindCStringParameter (EV_HASHID, aEvent.id);
|
||||
|
||||
mInsertEvent.bindInt64Parameter (EV_TIME_START, aEvent.start.utcTime);
|
||||
mInsertEvent.bindInt64Parameter (EV_TIME_END, aEvent.end.utcTime);
|
||||
|
||||
mInsertEvent.bindStringParameter (EV_TITLE, aEvent.title);
|
||||
mInsertEvent.bindStringParameter (EV_DESCRIPTION, aEvent.description);
|
||||
mInsertEvent.bindStringParameter (EV_LOCATION, aEvent.location);
|
||||
mInsertEvent.bindStringParameter (EV_CATEGORIES, aEvent.categories);
|
||||
|
||||
mDB.beginTransaction();
|
||||
mDeleteEventByHash.execute();
|
||||
mInsertEvent.execute();
|
||||
mDB.commitTransaction();
|
||||
|
||||
mDeleteEventByHash.reset();
|
||||
mInsertEvent.reset();
|
||||
|
||||
mEventHash[aEvent.id] = aEvent;
|
||||
},
|
||||
|
||||
// delete the event with the given uid
|
||||
deleteEvent: function (aID) {
|
||||
mDeleteEventByHash.bindCStringParameter (0, aID);
|
||||
mDeleteEventByHash.execute ();
|
||||
mDeleteEventByHash.reset ();
|
||||
|
||||
delete mEventHash[aID];
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
/****
|
||||
**** module registration
|
||||
****/
|
||||
|
||||
var calStorageCalendarModule = {
|
||||
mCID: Components.ID("{b3eaa1c4-5dfe-4c0a-b62a-b3a514218461}"),
|
||||
mContractID: "@mozilla.org/calendar/calendar;1&type=storage",
|
||||
|
||||
registerSelf: function (compMgr, fileSpec, location, type) {
|
||||
compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
|
||||
compMgr.registerFactoryLocation(this.mCID,
|
||||
"Calendar mozStorage/SQL back-end",
|
||||
this.mContractID,
|
||||
fileSpec,
|
||||
location,
|
||||
type);
|
||||
},
|
||||
|
||||
getClassObject: function (compMgr, cid, iid) {
|
||||
if (!cid.equals(this.mCID))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
|
||||
if (!iid.equals(Components.interfaces.nsIFactory))
|
||||
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
return this.mFactory;
|
||||
},
|
||||
|
||||
mFactory: {
|
||||
createInstance: function (outer, iid) {
|
||||
if (outer != null)
|
||||
throw Components.results.NS_ERROR_NO_AGGREGATION;
|
||||
return (new calStorageCalendar()).QueryInterface(iid);
|
||||
}
|
||||
},
|
||||
|
||||
canUnload: function(compMgr) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user