mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
b=293183, implement exception support for recurrence, r=shaver
This commit is contained in:
parent
003486ce09
commit
1afea82710
@ -40,7 +40,6 @@
|
||||
|
||||
#include "calDateTime.h"
|
||||
#include "calICSService.h"
|
||||
#include "calRecurrenceInfo.h"
|
||||
#include "calRecurrenceRule.h"
|
||||
#include "calRecurrenceDate.h"
|
||||
#include "calRecurrenceDateSet.h"
|
||||
@ -49,37 +48,73 @@
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(calDateTime)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(calICSService)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(calRecurrenceInfo)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(calRecurrenceRule)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(calRecurrenceDate)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(calRecurrenceDateSet)
|
||||
|
||||
NS_DECL_CLASSINFO(calDateTime)
|
||||
NS_DECL_CLASSINFO(calICSService)
|
||||
NS_DECL_CLASSINFO(calRecurrenceRule)
|
||||
NS_DECL_CLASSINFO(calRecurrenceDate)
|
||||
NS_DECL_CLASSINFO(calRecurrenceDateSet)
|
||||
|
||||
static const nsModuleComponentInfo components[] =
|
||||
{
|
||||
{ "Calendar DateTime Object",
|
||||
CAL_DATETIME_CID,
|
||||
CAL_DATETIME_CONTRACTID,
|
||||
calDateTimeConstructor },
|
||||
calDateTimeConstructor,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NS_CI_INTERFACE_GETTER_NAME(calDateTime),
|
||||
NULL,
|
||||
&NS_CLASSINFO_NAME(calDateTime)
|
||||
},
|
||||
{ "ICS parser/serializer",
|
||||
CAL_ICSSERVICE_CID,
|
||||
CAL_ICSSERVICE_CONTRACTID,
|
||||
calICSServiceConstructor },
|
||||
{ "Calendar Recurrence Object",
|
||||
CAL_RECURRENCEINFO_CID,
|
||||
CAL_RECURRENCEINFO_CONTRACTID,
|
||||
calRecurrenceInfoConstructor },
|
||||
calICSServiceConstructor,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NS_CI_INTERFACE_GETTER_NAME(calICSService),
|
||||
NULL,
|
||||
&NS_CLASSINFO_NAME(calICSService)
|
||||
},
|
||||
{ "Calendar Recurrence Rule",
|
||||
CAL_RECURRENCERULE_CID,
|
||||
CAL_RECURRENCERULE_CONTRACTID,
|
||||
calRecurrenceRuleConstructor },
|
||||
calRecurrenceRuleConstructor,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NS_CI_INTERFACE_GETTER_NAME(calRecurrenceRule),
|
||||
NULL,
|
||||
&NS_CLASSINFO_NAME(calRecurrenceRule)
|
||||
},
|
||||
{ "Calendar Recurrence Date",
|
||||
CAL_RECURRENCEDATE_CID,
|
||||
CAL_RECURRENCEDATE_CONTRACTID,
|
||||
calRecurrenceDateConstructor },
|
||||
calRecurrenceDateConstructor,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NS_CI_INTERFACE_GETTER_NAME(calRecurrenceDate),
|
||||
NULL,
|
||||
&NS_CLASSINFO_NAME(calRecurrenceDate)
|
||||
},
|
||||
{ "Calendar Recurrence Date Set",
|
||||
CAL_RECURRENCEDATESET_CID,
|
||||
CAL_RECURRENCEDATESET_CONTRACTID,
|
||||
calRecurrenceDateSetConstructor }
|
||||
calRecurrenceDateSetConstructor,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NS_CI_INTERFACE_GETTER_NAME(calRecurrenceDateSet),
|
||||
NULL,
|
||||
&NS_CLASSINFO_NAME(calRecurrenceDateSet)
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_NSGETMODULE(calBaseModule, components)
|
||||
|
@ -76,9 +76,13 @@ function onAccept()
|
||||
{
|
||||
// if this event isn't mutable, we need to clone it like a sheep
|
||||
var originalEvent = window.calendarEvent;
|
||||
var event = null;
|
||||
var event = originalEvent;
|
||||
|
||||
event = (originalEvent.isMutable) ? originalEvent : originalEvent.clone();
|
||||
if (!event.isMutable) {
|
||||
event = event.clone();
|
||||
} else {
|
||||
dump ("#### modifyEvent is mutable already?\n");
|
||||
}
|
||||
|
||||
saveDialog(event);
|
||||
|
||||
@ -137,12 +141,20 @@ function loadDialog()
|
||||
}
|
||||
|
||||
/* recurrence */
|
||||
if (event.recurrenceInfo) {
|
||||
/* if the item is a proxy occurrence/instance, a few things aren't valid:
|
||||
* - Setting recurrence on the item
|
||||
* - changing the calendar
|
||||
*/
|
||||
if (event.parentItem != event) {
|
||||
setElementValue("event-recurrence", "true", "disabled");
|
||||
setElementValue("set-recurrence", "true", "disabled");
|
||||
setElementValue("event-calendar", "true", "disabled");
|
||||
} else if (event.recurrenceInfo) {
|
||||
setElementValue("event-recurrence", "true", "checked");
|
||||
}
|
||||
|
||||
/* alarms */
|
||||
if (event.hasAlarm) {
|
||||
if (event.alarmTime) {
|
||||
var alarmLength = event.getProperty("alarmLength");
|
||||
if (alarmLength != null) {
|
||||
setElementValue("alarm-length-field", alarmLength);
|
||||
@ -193,8 +205,8 @@ function saveDialog(event)
|
||||
}
|
||||
|
||||
/* alarms */
|
||||
event.hasAlarm = (getElementValue("event-alarm") != "none");
|
||||
if (!event.hasAlarm) {
|
||||
var hasAlarm = (getElementValue("event-alarm") != "none");
|
||||
if (!hasAlarm) {
|
||||
event.deleteProperty("alarmLength");
|
||||
event.deleteProperty("alarmUnits");
|
||||
event.deleteProperty("alarmRelated");
|
||||
|
@ -43,10 +43,16 @@ calendar-event-column {
|
||||
|
||||
.fgdragcontainer[dragging="true"] {
|
||||
display: -moz-box;
|
||||
/* This is a workaround for a stack bug and display: hidden in underlying
|
||||
* elements -- the display: hidden bits get misrendered as being on top.
|
||||
* Setting an opacity here forces a view to be created for this element, too.
|
||||
*/
|
||||
opacity: 0.9999;
|
||||
}
|
||||
|
||||
.fgdragbox-label {
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/*== calendar-event-box ==*/
|
||||
@ -58,6 +64,7 @@ calendar-event-box {
|
||||
.calendar-event-box-container {
|
||||
background: #4e84c2;
|
||||
padding: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.calendar-event-box-container[parentorient="vertical"] {
|
||||
|
@ -110,7 +110,7 @@
|
||||
if (!orient) orient = "horizontal";
|
||||
if (orient == "vertical") otherorient = "horizontal";
|
||||
|
||||
dump ("calendar-time-bar: orient: " + orient + " other: " + otherorient + "\n");
|
||||
//dump ("calendar-time-bar: orient: " + orient + " other: " + otherorient + "\n");
|
||||
|
||||
function makeTimeBox(timestr, size) {
|
||||
var box = createXULElement("box");
|
||||
@ -242,7 +242,7 @@
|
||||
<xul:box anonid="bgbox" flex="1"/>
|
||||
<xul:box anonid="topbox" flex="1" equalsize="always"/>
|
||||
<xul:box anonid="fgbox" flex="1" class="fgdragcontainer">
|
||||
<xul:box anonid="fgdragspacer" style="display: inherit;">
|
||||
<xul:box anonid="fgdragspacer" style="display: inherit; overflow: hidden;">
|
||||
<xul:spacer flex="1"/>
|
||||
<xul:label anonid="fgdragbox-startlabel" class="fgdragbox-label"/>
|
||||
</xul:box>
|
||||
@ -408,7 +408,9 @@
|
||||
<parameter name="aOccurrence"/>
|
||||
<body><![CDATA[
|
||||
for each (var chunk in this.mEvents) {
|
||||
if (chunk.event.equals(aOccurrence)) {
|
||||
if (chunk.event.id == aOccurrence.id &&
|
||||
chunk.event.startDate.compare(aOccurrence.startDate) == 0)
|
||||
{
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
@ -445,7 +447,9 @@
|
||||
var i;
|
||||
for (i = 0; i < this.mEvents.length; i++) {
|
||||
occ = this.mEvents[i].event;
|
||||
if (occ.equals(aOccurrence)) {
|
||||
if (occ.id == aOccurrence.id &&
|
||||
occ.startDate.compare(aOccurrence.startDate) == 0)
|
||||
{
|
||||
itemIndex = i;
|
||||
break;
|
||||
}
|
||||
@ -478,8 +482,8 @@
|
||||
<method name="getStartEndMinutesForOccurrence">
|
||||
<parameter name="aOccurrence"/>
|
||||
<body><![CDATA[
|
||||
var stdate = aOccurrence.occurrenceStartDate;
|
||||
var enddate = aOccurrence.occurrenceEndDate;
|
||||
var stdate = aOccurrence.startDate;
|
||||
var enddate = aOccurrence.endDate;
|
||||
|
||||
if (stdate.timezone != this.mTimezone)
|
||||
stdate = stdate.getInTimezone (this.mTimezone);
|
||||
@ -650,7 +654,7 @@
|
||||
|
||||
<method name="computeEventMap">
|
||||
<body><![CDATA[
|
||||
//dump ("computeEventMap\n");
|
||||
//dump ("computeEventMap\n");
|
||||
// we need to build a layout data structure
|
||||
// that looks like this:
|
||||
// [
|
||||
@ -679,7 +683,7 @@
|
||||
eventMap.push(new Array());
|
||||
|
||||
for each (var event in this.mEvents) {
|
||||
//if (event.occurrenceStartDate.isDate)
|
||||
//if (event.startDate.isDate)
|
||||
// continue;
|
||||
|
||||
if (event.startMinute == null || event.endMinute == null || event.event == null)
|
||||
@ -972,7 +976,7 @@
|
||||
<parameter name="aMouseX"/>
|
||||
<parameter name="aMouseY"/>
|
||||
<body><![CDATA[
|
||||
dump ("startSweepingToModify\n");
|
||||
//dump ("startSweepingToModify\n");
|
||||
this.mDragState = {
|
||||
origColumn: this,
|
||||
dragOccurrence: aOccurrence,
|
||||
@ -982,7 +986,7 @@
|
||||
var interval = this.mPixPerMin * 15;
|
||||
var sizeattr;
|
||||
|
||||
dump ("AMY: " + aMouseY + " boY: " + this.parentNode.boxObject.screenY + "\n");
|
||||
//dump ("AMY: " + aMouseY + " boY: " + this.parentNode.boxObject.screenY + "\n");
|
||||
var frameloc;
|
||||
if (this.getAttribute("orient") == "vertical") {
|
||||
this.mDragState.origLoc = aMouseY;
|
||||
@ -1050,7 +1054,7 @@
|
||||
document.calendarEventColumnDragging = this;
|
||||
//this.onEventSweepMouseMove(event);
|
||||
|
||||
dump (">>> drag is: " + this.mDragState.dragType + "\n");
|
||||
//dump (">>> drag is: " + this.mDragState.dragType + "\n");
|
||||
|
||||
window.addEventListener("mousemove", this.onEventSweepMouseMove, false);
|
||||
window.addEventListener("mouseup", this.onEventSweepMouseUp, false);
|
||||
@ -1160,7 +1164,7 @@
|
||||
<xul:box anonid="eventbox" xbl:inherits="orient,width,height" flex="1">
|
||||
<xul:calendar-event-gripbar anonid="gripbar1" whichside="start" xbl:inherits="parentorient=orient"/>
|
||||
<xul:vbox class="calendar-event-box-container" xbl:inherits="parentorient=orient" flex="1" align="left">
|
||||
<xul:label anonid="event-name" flex="1" crop="right"/>
|
||||
<xul:label anonid="event-name" flex="1" crop="right"/>
|
||||
<!-- for some reason, textboxes suck ass for reflow. -->
|
||||
<!-- <xul:textbox class="plain" style="background: transparent !important" anonid="event-name" flex="1" crop="right"/> -->
|
||||
</xul:vbox>
|
||||
@ -1224,10 +1228,15 @@
|
||||
]]></getter>
|
||||
<setter><![CDATA[
|
||||
this.mOccurrence = val;
|
||||
if (val && val.item)
|
||||
this.eventNameLabel.setAttribute('value', val.item.title);
|
||||
else
|
||||
this.eventNameLabel.setAttribute('value', 'Untitled Event');
|
||||
var evl = this.eventNameLabel;
|
||||
while (evl.firstChild)
|
||||
evl.removeChild(evl.firstChild);
|
||||
|
||||
if (val) {
|
||||
evl.appendChild(document.createTextNode(val.title));
|
||||
} else {
|
||||
evl.appendChild(document.createTextNode("Untitled Event"));
|
||||
}
|
||||
return val;
|
||||
]]></setter>
|
||||
</property>
|
||||
@ -1237,10 +1246,10 @@
|
||||
onset="return (this.mParentColumn = val);"/>
|
||||
|
||||
<property name="startMinute" readonly="true"
|
||||
onget="if (!this.mOccurrence) return 0; return this.mOccurrence.occurrenceStartDate.hour * 60 + this.mOccurrence.occurrenceStartDate.minute"/>
|
||||
onget="if (!this.mOccurrence) return 0; return this.mOccurrence.startDate.hour * 60 + this.mOccurrence.startDate.minute"/>
|
||||
|
||||
<property name="endMinute" readonly="true"
|
||||
onget="if (!this.mOccurrence) return 0; return this.mOccurrence.occurrenceEndDate.hour * 60 + this.mOccurrence.occurrenceEndDate.minute"/>
|
||||
onget="if (!this.mOccurrence) return 0; return this.mOccurrence.endDate.hour * 60 + this.mOccurrence.endDate.minute"/>
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
@ -1248,11 +1257,6 @@
|
||||
event.preventBubble();
|
||||
this.calendarView.selectedOccurrence = this.mOccurrence;
|
||||
|
||||
if (this.mOccurrence.item.recurrenceInfo) {
|
||||
// XXXvv can't drag recurring events yet, FIXME
|
||||
return;
|
||||
}
|
||||
|
||||
this.mInMouseDown = true;
|
||||
this.mMouseX = event.screenX;
|
||||
this.mMouseY = event.screenY;
|
||||
@ -1357,7 +1361,7 @@
|
||||
this.calView.refresh();
|
||||
},
|
||||
onAddItem: function (aItem) {
|
||||
//dump ("++ AddItem\n");
|
||||
//dump ("++ AddItem " + aItem + "\n");
|
||||
if (!(aItem instanceof Components.interfaces.calIEvent))
|
||||
return;
|
||||
aItem = aItem.QueryInterface(Components.interfaces.calIEvent);
|
||||
@ -1365,6 +1369,7 @@
|
||||
var occs = aItem.getOccurrencesBetween(this.calView.startDate,
|
||||
this.calView.endDate,
|
||||
{});
|
||||
//dump ("occs: " + occs.length + "\n");
|
||||
for each (var occ in occs) {
|
||||
this.calView.doAddEvent(occ);
|
||||
}
|
||||
@ -1591,7 +1596,11 @@
|
||||
if (this.mSelectedOccurrence != val) {
|
||||
if (this.mSelectedOccurrence) {
|
||||
var col = this.findColumnForEvent(this.mSelectedOccurrence);
|
||||
col.column.selectOccurrence(null);
|
||||
if (col) {
|
||||
col.column.selectOccurrence(null);
|
||||
} else {
|
||||
dump ("Thought I had a selected occurrence (id: " + this.mSelectedOccurrence.id + "), but couldn't find a column for it!\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (val) {
|
||||
@ -1675,7 +1684,7 @@
|
||||
labelbox.setAttribute("height", 30);
|
||||
labelbox.removeAttribute("width");
|
||||
|
||||
var timebarWidth = 50;
|
||||
var timebarWidth = 100;
|
||||
timebar.setAttribute("width", timebarWidth);
|
||||
timebar.removeAttribute("height");
|
||||
headertimespacer.setAttribute("width", timebarWidth);
|
||||
@ -1689,7 +1698,7 @@
|
||||
labelbox.setAttribute("width", 30);
|
||||
labelbox.removeAttribute("height");
|
||||
|
||||
var timebarHeight = 30;
|
||||
var timebarHeight = 40;
|
||||
timebar.setAttribute("height", timebarHeight);
|
||||
timebar.removeAttribute("width");
|
||||
headertimespacer.setAttribute("height", timebarHeight);
|
||||
@ -1833,8 +1842,8 @@
|
||||
<method name="findColumnForEvent">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
var estart = aEvent.occurrenceStartDate;
|
||||
var eend = aEvent.occurrenceEndDate;
|
||||
var estart = aEvent.startDate;
|
||||
var eend = aEvent.endDate;
|
||||
|
||||
var eday = estart.clone();
|
||||
eday.isDate = true;
|
||||
@ -1884,7 +1893,7 @@
|
||||
var column = col.column;
|
||||
var header = col.header;
|
||||
|
||||
var estart = aEvent.occurrenceStartDate;
|
||||
var estart = aEvent.startDate;
|
||||
if (estart.isDate) {
|
||||
// add it to header
|
||||
} else {
|
||||
@ -1903,7 +1912,7 @@
|
||||
var column = col.column;
|
||||
var header = col.header;
|
||||
|
||||
var estart = aEvent.occurrenceStartDate;
|
||||
var estart = aEvent.startDate;
|
||||
if (estart.isDate) {
|
||||
// remove from header
|
||||
} else {
|
||||
|
@ -143,7 +143,7 @@ function saveDialog()
|
||||
var deckNumber = Number(getElementValue("period-list"));
|
||||
|
||||
var recurrenceInfo = createRecurrenceInfo();
|
||||
recurrenceInfo.initialize(window.calendarEvent);
|
||||
recurrenceInfo.item = window.calendarEvent;
|
||||
|
||||
var recRule = new calRecurrenceRule();
|
||||
|
||||
|
@ -55,6 +55,7 @@ XPIDLSRCS = calIAlarmService.idl \
|
||||
calICalendarView.idl \
|
||||
calICalendarViewController.idl \
|
||||
calIDateTime.idl \
|
||||
calIErrors.idl \
|
||||
calIEvent.idl \
|
||||
calIICSService.idl \
|
||||
calIItemBase.idl \
|
||||
|
@ -51,11 +51,6 @@
|
||||
#define CAL_ICSSERVICE_CONTRACTID \
|
||||
"@mozilla.org/calendar/ics-service;1"
|
||||
|
||||
#define CAL_RECURRENCEINFO_CID \
|
||||
{ 0x04027036, 0x5884, 0x4a30, { 0xb4, 0xaf, 0xf2, 0xca, 0xd7, 0x9f, 0x6e, 0xdf } }
|
||||
#define CAL_RECURRENCEINFO_CONTRACTID \
|
||||
"@mozilla.org/calendar/recurrence-info;1"
|
||||
|
||||
#define CAL_RECURRENCERULE_CID \
|
||||
{ 0xd9560bf9, 0x3065, 0x404a, { 0x90, 0x4c, 0xc8, 0x82, 0xfc, 0x9c, 0x9b, 0x74 } }
|
||||
#define CAL_RECURRENCERULE_CONTRACTID \
|
||||
@ -72,11 +67,6 @@
|
||||
"@mozilla.org/calendar/recurrence-date;1"
|
||||
|
||||
/* JS -- Update these from calItemModule.js */
|
||||
#define CAL_ITEM_OCCURRENCE_CID \
|
||||
{ 0xbad672b3, 0x30b8, 0x4ecd, { 0x80, 0x75, 0x71, 0x53, 0x31, 0x3d, 0x1f, 0x2c } }
|
||||
#define CAL_ITEM_OCCURRENCE_CONTRACTID \
|
||||
"@mozilla.org/calendar/item-occurrence;1"
|
||||
|
||||
#define CAL_EVENT_CID \
|
||||
{ 0x974339d5, 0xab86, 0x4491, { 0xaa, 0xaf, 0x2b, 0x2c, 0xa1, 0x77, 0xc1, 0x2b } }
|
||||
#define CAL_EVENT_CONTRACTID \
|
||||
@ -92,6 +82,11 @@
|
||||
#define CAL_ATTENDEE_CONTRACTID \
|
||||
"@mozilla.org/calendar/attendee;1"
|
||||
|
||||
#define CAL_RECURRENCEINFO_CID \
|
||||
{ 0x04027036, 0x5884, 0x4a30, { 0xb4, 0xaf, 0xf2, 0xca, 0xd7, 0x9f, 0x6e, 0xdf } }
|
||||
#define CAL_RECURRENCEINFO_CONTRACTID \
|
||||
"@mozilla.org/calendar/recurrence-info;1"
|
||||
|
||||
#define NS_ERROR_CALENDAR_WRONG_COMPONENT_TYPE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CALENDAR, 1)
|
||||
// Until extensible xpconnect error mapping works
|
||||
// #define NS_ERROR_CALENDAR_IMMUTABLE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_CALENDAR, 2)
|
||||
|
@ -42,9 +42,9 @@
|
||||
interface calICalendar;
|
||||
interface calIDateTime;
|
||||
interface calICalendarViewController;
|
||||
interface calIItemOccurrence;
|
||||
interface calIItemBase;
|
||||
|
||||
[scriptable, uuid(be9b4f26-2475-4aeb-9b46-e165fc0809fb)]
|
||||
[scriptable, uuid(448a7f1a-384c-4e47-b5b5-1c372b4ad3d1)]
|
||||
interface calICalendarView : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -110,7 +110,7 @@ interface calICalendarView : nsISupports
|
||||
void getDateList(out unsigned long aCount, [array,size_is(aCount),retval] out calIDateTime aDates);
|
||||
|
||||
/**
|
||||
* Get or set the selected occurrence. Only one occurrence may be selected.
|
||||
* Get or set the selected item. Only one item may be selected.
|
||||
*/
|
||||
attribute calIItemOccurrence selectedOccurrence;
|
||||
attribute calIItemBase selectedItem;
|
||||
};
|
||||
|
@ -47,7 +47,6 @@ interface nsIVariant;
|
||||
interface nsIPropertyBag;
|
||||
|
||||
interface calICalendar;
|
||||
interface calIItemOccurrence;
|
||||
|
||||
interface calIDateTime;
|
||||
|
||||
@ -63,7 +62,7 @@ interface calIIcalComponent;
|
||||
// Base for Events, Todos, Journals, etc.
|
||||
//
|
||||
|
||||
[scriptable, uuid(096b8cc5-113c-40fb-bc52-d64e3992980c)]
|
||||
[scriptable, uuid(18521d75-346d-4616-8778-de2c4a9a676e)]
|
||||
interface calIItemBase : nsISupports
|
||||
{
|
||||
// returns true if this thing is able to be modified;
|
||||
@ -121,9 +120,9 @@ interface calIItemBase : nsISupports
|
||||
attribute calIIcalComponent icalComponent;
|
||||
|
||||
//
|
||||
// alarms
|
||||
// alarms; alarmTime is null if there is no
|
||||
// alarm set.
|
||||
//
|
||||
attribute boolean hasAlarm;
|
||||
attribute calIDateTime alarmTime;
|
||||
|
||||
//
|
||||
@ -137,10 +136,22 @@ interface calIItemBase : nsISupports
|
||||
// if this item is mutable, the returned array will be a nsIMutableArray
|
||||
readonly attribute nsIArray attachments;
|
||||
|
||||
//
|
||||
// All event properties are stored in a property bag;
|
||||
// some number of these are "promoted" to top-level
|
||||
// accessor attributes. For example, "SUMMARY" is
|
||||
// promoted to the top-level "title" attribute.
|
||||
//
|
||||
// other properties come in through a property bag
|
||||
// The isPropertyPromoted() attribute can will indicate
|
||||
// if a particular property is promoted or not, for
|
||||
// serialization purposes.
|
||||
//
|
||||
|
||||
// Note that if this item is a proxy, then any requests for
|
||||
// non-existant properties will be forward to the parent item.
|
||||
|
||||
// some other properties that may exist:
|
||||
//
|
||||
// 'description' - description (string)
|
||||
// 'location' - location (string)
|
||||
// 'categories' - categories (string)
|
||||
@ -149,21 +160,19 @@ interface calIItemBase : nsISupports
|
||||
// alarmLength/alarmUnits/alarmEmailAddress/lastAlarmAck
|
||||
// recurInterval/recurCount/recurWeekdays/recurWeeknumber
|
||||
|
||||
// Ideally, /all/ of the properties on the event should
|
||||
// be available via the property bag. (And maybe the
|
||||
// nsIItemBase impl should be QI'able to
|
||||
// nsIWritablePropertyBag also)
|
||||
|
||||
// if this item is mutable, the returned bag will be a nsIWritablePropertyBag
|
||||
//readonly attribute nsIPropertyBag properties;
|
||||
// these forward to an internal property bag; implemented here, so we can
|
||||
// do access control on set/delete.
|
||||
// do access control on set/delete to have control over mutability.
|
||||
readonly attribute nsISimpleEnumerator propertyEnumerator;
|
||||
boolean hasProperty(in AString name);
|
||||
nsIVariant getProperty(in AString name);
|
||||
void setProperty(in AString name, in nsIVariant value);
|
||||
// will not throw an error if you delete a property that doesn't exist
|
||||
void deleteProperty(in AString name);
|
||||
|
||||
// returns true if the given property is promoted to some
|
||||
// top-level attribute (e.g. id or title)
|
||||
boolean isPropertyPromoted(in AString name);
|
||||
|
||||
/**
|
||||
* The organizer (originator) of the item. We will likely not
|
||||
* honour or preserve all fields in the calIAttendee passed around here.
|
||||
@ -172,6 +181,10 @@ interface calIItemBase : nsISupports
|
||||
*/
|
||||
attribute calIAttendee organizer;
|
||||
|
||||
//
|
||||
// Attendees
|
||||
//
|
||||
|
||||
// The array returned here is not live; it will not reflect calls to
|
||||
// removeAttendee/addAttendee that follow the call to getAttendees.
|
||||
void getAttendees(out PRUint32 count,
|
||||
@ -181,43 +194,66 @@ interface calIItemBase : nsISupports
|
||||
void addAttendee(in calIAttendee attendee);
|
||||
void removeAllAttendees();
|
||||
|
||||
// return a list of occurrences of this item between the given dates
|
||||
//
|
||||
// Occurrence querying
|
||||
//
|
||||
|
||||
/**
|
||||
* Return a list of occurrences of this item between the given dates. The items
|
||||
* returned are the same type as this one, as proxies.
|
||||
*/
|
||||
void getOccurrencesBetween (in calIDateTime aStartDate, in calIDateTime aEndDate,
|
||||
out PRUint32 aCount,
|
||||
[array,size_is(aCount),retval] out calIItemOccurrence aOccurrences);
|
||||
[array,size_is(aCount),retval] out calIItemBase aOccurrences);
|
||||
|
||||
/**
|
||||
* The next occurrence after this one, if any.
|
||||
*/
|
||||
readonly attribute calIItemBase nextOccurrence;
|
||||
|
||||
/**
|
||||
* The previous occurrence before this one, if any.
|
||||
*/
|
||||
readonly attribute calIItemBase previousOccurrence;
|
||||
|
||||
//
|
||||
// proxy support
|
||||
//
|
||||
|
||||
/**
|
||||
* create a proxy for this item; the returned item
|
||||
* proxy will have parentItem set to this instance.
|
||||
*/
|
||||
calIItemBase createProxy();
|
||||
|
||||
/**
|
||||
* If this item is a proxy, parentItem will point upwards
|
||||
* to our parent. Otherwise, it will point to this.
|
||||
* parentItem can thus always be used for modifyItem() calls
|
||||
* to providers.
|
||||
*/
|
||||
attribute calIItemBase parentItem;
|
||||
|
||||
/**
|
||||
* The recurrence ID, a.k.a. DTSTART-of-calculated-occurrence,
|
||||
* or null if this isn't an occurrence.
|
||||
*/
|
||||
attribute calIDateTime recurrenceId;
|
||||
|
||||
/**
|
||||
* Returns the given property value if it is natively set on the item,
|
||||
* otherwise returns null.
|
||||
*/
|
||||
nsIVariant getUnproxiedProperty(in AString name);
|
||||
|
||||
/**
|
||||
* An enumerator that lets us walk down the list of properties
|
||||
* that are actually changed by this proxy from the base. If this
|
||||
* item is not a proxy, then this list will be equivalent to the one
|
||||
* returned from propertyEnumerator.
|
||||
*
|
||||
* The elements returned by the enumerator will be of type nsIProperty,
|
||||
* as with a normal nsIPropertyBag enumerator.
|
||||
*/
|
||||
readonly attribute nsISimpleEnumerator unproxiedPropertyEnumerator;
|
||||
};
|
||||
|
||||
//
|
||||
// calIItemOccurrence
|
||||
//
|
||||
// An item representing a specific instance of a possibly recurring item.
|
||||
// XXX unclear how recurrence (& this) works for todo events with due dates.
|
||||
//
|
||||
|
||||
[scriptable, uuid(b19f3d7e-e848-4139-af3e-505a8023568d)]
|
||||
interface calIItemOccurrence : nsISupports
|
||||
{
|
||||
// Initialize this Occurrence
|
||||
void initialize (in calIItemBase aItem,
|
||||
in calIDateTime aStartDate,
|
||||
in calIDateTime aEndDate);
|
||||
//
|
||||
// The parent item for which this is the occurrence item for
|
||||
//
|
||||
readonly attribute calIItemBase item;
|
||||
|
||||
//
|
||||
// The start and end times to display for this event instance
|
||||
//
|
||||
readonly attribute calIDateTime occurrenceStartDate;
|
||||
readonly attribute calIDateTime occurrenceEndDate;
|
||||
|
||||
// same as item.getNextOccurrence(occurrenceEndDate)
|
||||
readonly attribute calIItemOccurrence next;
|
||||
// same as item.getPreviousOccurrence(occurrenceStartDate)
|
||||
readonly attribute calIItemOccurrence previous;
|
||||
|
||||
// is this occurrence equal to the other
|
||||
boolean equals (in calIItemOccurrence aOther);
|
||||
};
|
||||
|
||||
|
@ -42,7 +42,6 @@
|
||||
|
||||
interface calIItemBase;
|
||||
interface calIDateTime;
|
||||
interface calIItemOccurrence;
|
||||
|
||||
interface calIIcalProperty;
|
||||
|
||||
|
@ -42,7 +42,6 @@
|
||||
|
||||
interface calIItemBase;
|
||||
interface calIDateTime;
|
||||
interface calIItemOccurrence;
|
||||
|
||||
interface calIIcalProperty;
|
||||
|
||||
|
@ -40,13 +40,12 @@
|
||||
|
||||
interface calIItemBase;
|
||||
interface calIDateTime;
|
||||
interface calIItemOccurrence;
|
||||
|
||||
interface calIRecurrenceItem;
|
||||
|
||||
interface calIIcalProperty;
|
||||
|
||||
[scriptable, uuid(a6a458cf-052c-45d1-bee7-b700ad21109a)]
|
||||
[scriptable, uuid(8ca5db89-2583-4f0c-b845-4a6d2f229efd)]
|
||||
interface calIRecurrenceInfo : nsISupports
|
||||
{
|
||||
// returns true if this thing is able to be modified;
|
||||
@ -62,12 +61,11 @@ interface calIRecurrenceInfo : nsISupports
|
||||
|
||||
// initialize this with the item for which this recurrence
|
||||
// applies, so that the start date can be tracked
|
||||
void initialize (in calIItemBase aItem);
|
||||
readonly attribute calIItemBase item;
|
||||
attribute calIItemBase item;
|
||||
|
||||
//
|
||||
// set of recurrence items; the order of these matters.
|
||||
//
|
||||
/*
|
||||
* Set of recurrence items; the order of these matters.
|
||||
*/
|
||||
|
||||
void getRecurrenceItems (out unsigned long aCount, [array,size_is(aCount),retval] out calIRecurrenceItem aItems);
|
||||
void setRecurrenceItems (in unsigned long aCount, [array,size_is(aCount)] in calIRecurrenceItem aItems);
|
||||
@ -81,18 +79,90 @@ interface calIRecurrenceInfo : nsISupports
|
||||
// inserts the item at the given index, pushing the item that was previously there forward
|
||||
void insertRecurrenceItemAt (in calIRecurrenceItem aItem, in unsigned long aIndex);
|
||||
|
||||
//
|
||||
// recurrence calculation
|
||||
//
|
||||
/**
|
||||
* isFinite is true if the recurrence items specify a finite number
|
||||
* of occurrences. This is useful for UI and for possibly other users.
|
||||
*/
|
||||
readonly attribute boolean isFinite;
|
||||
|
||||
// return the next display item for the event,
|
||||
// where the start time is > aStartTime
|
||||
calIItemOccurrence getNextOccurrence (in calIDateTime aOccurrenceTime);
|
||||
/**
|
||||
* This is a shortcut to appending or removing a single negative
|
||||
* date assertion. This shortcut may or may not cause problems
|
||||
* later on, but hey, that's fixable later!
|
||||
*/
|
||||
void removeOccurrenceAt (in calIDateTime aRecurrenceId);
|
||||
void restoreOccurrenceAt (in calIDateTime aRecurrenceId);
|
||||
|
||||
// return array of calIItemOccurrence representing all
|
||||
// occurrences of this event between start (inclusive) and end (non-inclusive).
|
||||
/*
|
||||
* exceptions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modify an a particular occurrence with the given exception proxy
|
||||
* item. If the recurrenceId isn't an already existing exception item,
|
||||
* a new exception is added. Otherwise, the existing exception
|
||||
* is modified.
|
||||
*
|
||||
* The item's parentItem must be equal to this RecurrenceInfo's
|
||||
* item. <-- XXX check this, compare by calendar/id only
|
||||
*/
|
||||
void modifyException (in calIItemBase anItem);
|
||||
|
||||
/**
|
||||
* Return an existing exception item for the given recurrence ID.
|
||||
* If an exception does not exist, and aCreate is set, a new one
|
||||
* is created and returned. Otherwise, null is returned.
|
||||
*/
|
||||
calIItemBase getExceptionFor (in calIDateTime aRecurrenceId, in boolean aCreate);
|
||||
|
||||
/**
|
||||
* Removes an exception item for the given recurrence ID, if
|
||||
* any exist.
|
||||
*/
|
||||
void removeExceptionFor (in calIDateTime aRecurrenceId);
|
||||
|
||||
/**
|
||||
* Returns a list of all recurrence ids that have exceptions.
|
||||
*/
|
||||
void getExceptionIds (out unsigned long aCount, [array,size_is(aCount),retval] out calIDateTime aIds);
|
||||
|
||||
/*
|
||||
* recurrence calculation
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get the occurrence at the given recurrence ID; if there is no
|
||||
* exception, then create a new proxy object with the normal occurrence.
|
||||
* Otherwise, return the exception.
|
||||
*/
|
||||
calIItemBase getOccurrenceFor (in calIDateTime aRecurrenceId);
|
||||
|
||||
/**
|
||||
* Return the next start calIDateTime of the recurrence specified by
|
||||
* this RecurrenceInfo, after aOccurrenceTime.
|
||||
*/
|
||||
calIDateTime getNextOccurrenceDate (in calIDateTime aOccurrenceTime);
|
||||
|
||||
/**
|
||||
* Return the next item specified by this RecurrenceInfo, after aOccurrenceTime.
|
||||
*/
|
||||
calIItemBase getNextOccurrence (in calIDateTime aOccurrenceTime);
|
||||
|
||||
/**
|
||||
* Return an array of calIDateTime representing all start times of this event
|
||||
* between start (inclusive) and end (non-inclusive).
|
||||
*/
|
||||
void getOccurrenceDates (in calIDateTime aRangeStart,
|
||||
in calIDateTime aRangeEnd,
|
||||
in unsigned long aMaxCount,
|
||||
out unsigned long aCount, [array,size_is(aCount),retval] out calIDateTime aDates);
|
||||
|
||||
/**
|
||||
* Return an array of calIItemOccurrence representing all
|
||||
* occurrences of this event between start (inclusive) and end (non-inclusive).
|
||||
*/
|
||||
void getOccurrences (in calIDateTime aRangeStart,
|
||||
in calIDateTime aRangeEnd,
|
||||
in unsigned long aMaxCount,
|
||||
out unsigned long aCount, [array,size_is(aCount),retval] out calIItemOccurrence aItems);
|
||||
out unsigned long aCount, [array,size_is(aCount),retval] out calIItemBase aItems);
|
||||
};
|
||||
|
@ -44,7 +44,7 @@ interface calIItemOccurrence;
|
||||
|
||||
interface calIIcalProperty;
|
||||
|
||||
[scriptable, uuid(d438b44a-9d6e-4ebb-bb03-321c9b81b216)]
|
||||
[scriptable, uuid(943be334-4995-477e-b325-f0c2319183e8)]
|
||||
interface calIRecurrenceItem : nsISupports
|
||||
{
|
||||
// returns true if this thing is able to be modified;
|
||||
@ -62,6 +62,10 @@ interface calIRecurrenceItem : nsISupports
|
||||
// as a negative rule (e.g. exceptions instead of rdates)
|
||||
attribute boolean isNegative;
|
||||
|
||||
// returns whether this item has a finite number of dates
|
||||
// or not (e.g. a rule with no end date)
|
||||
readonly attribute boolean isFinite;
|
||||
|
||||
// return the next start time after aOccurrencetime for this
|
||||
// recurrence, starting at aStartTime.
|
||||
calIDateTime getNextOccurrence (in calIDateTime aStartTime,
|
||||
|
@ -42,7 +42,6 @@
|
||||
|
||||
interface calIItemBase;
|
||||
interface calIDateTime;
|
||||
interface calIItemOccurrence;
|
||||
|
||||
// an interface implementing a RRULE
|
||||
|
||||
|
@ -61,9 +61,13 @@ REQUIRES = xpcom \
|
||||
# sqlite3 \
|
||||
# $(NULL)
|
||||
|
||||
XPIDL_MODULE = calbaseinternal
|
||||
XPIDLSRCS = \
|
||||
calInternalInterfaces.idl \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = calDateTime.cpp \
|
||||
calICSService.cpp \
|
||||
calRecurrenceInfo.cpp \
|
||||
calRecurrenceRule.cpp \
|
||||
calRecurrenceDate.cpp \
|
||||
calRecurrenceDateSet.cpp \
|
||||
@ -75,6 +79,7 @@ EXTRA_COMPONENTS = \
|
||||
calAttachment.js \
|
||||
calAttendee.js \
|
||||
calCalendarManager.js \
|
||||
calRecurrenceInfo.js \
|
||||
calEvent.js \
|
||||
calItemBase.js \
|
||||
calItemModule.js \
|
||||
|
@ -80,13 +80,13 @@ function calAlarmService() {
|
||||
onEndBatch: function() { },
|
||||
onLoad: function() { },
|
||||
onAddItem: function(aItem) {
|
||||
if (aItem.hasAlarm)
|
||||
if (aItem.alarmTime)
|
||||
this.alarmService.addAlarm(aItem, false);
|
||||
},
|
||||
onModifyItem: function(aNewItem, aOldItem) {
|
||||
this.alarmService.removeAlarm(aOldItem);
|
||||
|
||||
if (aNewItem.hasAlarm)
|
||||
if (aNewItem.alarmTime)
|
||||
this.alarmService.addAlarm(aNewItem, false);
|
||||
},
|
||||
onDeleteItem: function(aDeletedItem) {
|
||||
@ -112,12 +112,13 @@ function calAlarmService() {
|
||||
};
|
||||
}
|
||||
|
||||
calAlarmServiceClassInfo = {
|
||||
var calAlarmServiceClassInfo = {
|
||||
getInterfaces: function (count) {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calIAlarmService,
|
||||
Components.interfaces.nsIObserver
|
||||
Components.interfaces.nsIObserver,
|
||||
Components.interfaces.nsIClassInfo
|
||||
];
|
||||
count.value = ifaces.length;
|
||||
return ifaces;
|
||||
@ -334,7 +335,7 @@ calAlarmService.prototype = {
|
||||
onGetResult: function(aCalendar, aStatus, aItemType, aDetail, aCount, aItems) {
|
||||
for (var i = 0; i < aCount; ++i) {
|
||||
var item = aItems[i];
|
||||
if (item.hasAlarm) {
|
||||
if (item.alarmTime) {
|
||||
this.alarmService.addAlarm(item, false);
|
||||
}
|
||||
}
|
||||
|
@ -40,11 +40,12 @@
|
||||
//
|
||||
function calAttachment() { }
|
||||
|
||||
calAttachmentClassInfo = {
|
||||
var calAttachmentClassInfo = {
|
||||
getInterfaces: function (count) {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calIAttachment
|
||||
Components.interfaces.calIAttachment,
|
||||
Components.interfaces.nsIClassInfo
|
||||
];
|
||||
count.value = ifaces.length;
|
||||
return ifaces;
|
||||
|
@ -42,11 +42,12 @@ function calAttendee() {
|
||||
createInstance(Components.interfaces.nsIWritablePropertyBag);
|
||||
}
|
||||
|
||||
calAttendeeClassInfo = {
|
||||
var calAttendeeClassInfo = {
|
||||
getInterfaces: function (count) {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calIAttendee
|
||||
Components.interfaces.calIAttendee,
|
||||
Components.interfaces.nsIClassInfo
|
||||
];
|
||||
count.value = ifaces.length;
|
||||
return ifaces;
|
||||
|
@ -66,11 +66,12 @@ function makeURI(uriString)
|
||||
return ioservice.newURI(uriString, null, null);
|
||||
}
|
||||
|
||||
calCalendarManagerClassInfo = {
|
||||
var calCalendarManagerClassInfo = {
|
||||
getInterfaces: function (count) {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calICalendarManager
|
||||
Components.interfaces.calICalendarManager,
|
||||
Components.interfaces.nsIClassInfo
|
||||
];
|
||||
count.value = ifaces.length;
|
||||
return ifaces;
|
||||
|
@ -54,7 +54,7 @@ extern "C" {
|
||||
|
||||
static NS_DEFINE_CID(kCalICSService, CAL_ICSSERVICE_CID);
|
||||
|
||||
NS_IMPL_ISUPPORTS2(calDateTime, calIDateTime, nsIXPCScriptable)
|
||||
NS_IMPL_ISUPPORTS2_CI(calDateTime, calIDateTime, nsIXPCScriptable)
|
||||
|
||||
calDateTime::calDateTime()
|
||||
: mImmutable(PR_FALSE),
|
||||
@ -107,7 +107,7 @@ NS_IMETHODIMP
|
||||
calDateTime::MakeImmutable()
|
||||
{
|
||||
if (mImmutable)
|
||||
return NS_ERROR_CALENDAR_IMMUTABLE;
|
||||
return NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
mImmutable = PR_TRUE;
|
||||
return NS_OK;
|
||||
@ -243,7 +243,7 @@ calDateTime::AddDuration(calIDateTime *aDuration)
|
||||
|
||||
mLastModified = PR_Now();
|
||||
|
||||
return SetTimeInTimezone(mNativeTime + nativeDur, mTimezone);
|
||||
return SetNativeTime(mNativeTime + nativeDur);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -48,17 +48,26 @@ function calEvent() {
|
||||
this.wrappedJSObject = this;
|
||||
this.initItemBase();
|
||||
this.initEvent();
|
||||
|
||||
this.eventPromotedProps = {
|
||||
"DTSTART": true,
|
||||
"DTEND": true,
|
||||
"DTSTAMP": true,
|
||||
__proto__: this.itemBasePromotedProps
|
||||
}
|
||||
}
|
||||
|
||||
// var trickery to suppress lib-as-component errors from loader
|
||||
var calItemBase;
|
||||
|
||||
calEventClassInfo = {
|
||||
var calEventClassInfo = {
|
||||
getInterfaces: function (count) {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calIItemBase,
|
||||
Components.interfaces.calIEvent
|
||||
Components.interfaces.calIEvent,
|
||||
Components.interfaces.calIInternalShallowCopy,
|
||||
Components.interfaces.nsIClassInfo
|
||||
];
|
||||
count.value = ifaces.length;
|
||||
return ifaces;
|
||||
@ -79,7 +88,8 @@ calEvent.prototype = {
|
||||
__proto__: calItemBase ? (new calItemBase()) : {},
|
||||
|
||||
QueryInterface: function (aIID) {
|
||||
if (aIID.equals(Components.interfaces.calIEvent))
|
||||
if (aIID.equals(Components.interfaces.calIEvent) ||
|
||||
aIID.equals(Components.interfaces.calIInternalShallowCopy))
|
||||
return this;
|
||||
|
||||
if (aIID.equals(Components.interfaces.nsIClassInfo))
|
||||
@ -88,36 +98,55 @@ calEvent.prototype = {
|
||||
return this.__proto__.__proto__.QueryInterface.call(this, aIID);
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
cloneShallow: function (aNewParent) {
|
||||
var m = new calEvent();
|
||||
this.cloneItemBaseInto(m);
|
||||
m.mStartDate = this.mStartDate.clone();
|
||||
m.mEndDate = this.mEndDate.clone();
|
||||
m.isAllDay = this.isAllDay;
|
||||
this.cloneItemBaseInto(m, aNewParent);
|
||||
|
||||
return m;
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
var m;
|
||||
|
||||
if (this.mParentItem) {
|
||||
var clonedParent = this.mParentItem.clone();
|
||||
m = clonedParent.recurrenceInfo.getOccurrenceFor (this.recurrenceId);
|
||||
} else {
|
||||
m = this.cloneShallow(null);
|
||||
}
|
||||
|
||||
return m;
|
||||
},
|
||||
|
||||
createProxy: function () {
|
||||
if (this.mIsProxy) {
|
||||
calDebug("Tried to create a proxy for an existing proxy!\n");
|
||||
throw Components.results.NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
var m = new calEvent();
|
||||
m.initializeProxy(this);
|
||||
|
||||
return m;
|
||||
},
|
||||
|
||||
makeImmutable: function () {
|
||||
this.mStartDate.makeImmutable();
|
||||
this.mEndDate.makeImmutable();
|
||||
|
||||
this.makeItemBaseImmutable();
|
||||
},
|
||||
|
||||
initEvent: function() {
|
||||
this.mStartDate = new CalDateTime();
|
||||
this.mEndDate = new CalDateTime();
|
||||
this.startDate = new CalDateTime();
|
||||
this.endDate = new CalDateTime();
|
||||
},
|
||||
|
||||
get duration() {
|
||||
var dur = new CalDateTime();
|
||||
dur.setTimeInTimezone (this.mEndDate.nativeTime - this.mStartDate.nativeTime, "floating");
|
||||
dur.setTimeInTimezone (this.endDate.nativeTime - this.startDate.nativeTime, "floating");
|
||||
return dur;
|
||||
},
|
||||
|
||||
get recurrenceStartDate() {
|
||||
return this.mStartDate;
|
||||
return this.startDate;
|
||||
},
|
||||
|
||||
icsEventPropMap: [
|
||||
@ -163,6 +192,8 @@ calEvent.prototype = {
|
||||
return icalcomp;
|
||||
},
|
||||
|
||||
eventPromotedProps: null,
|
||||
|
||||
set icalComponent(event) {
|
||||
this.modify();
|
||||
if (event.componentType != "VEVENT") {
|
||||
@ -173,19 +204,17 @@ calEvent.prototype = {
|
||||
|
||||
this.setItemBaseFromICS(event);
|
||||
this.mapPropsFromICS(event, this.icsEventPropMap);
|
||||
this.mIsAllDay = this.mStartDate && this.mStartDate.isDate;
|
||||
this.mIsAllDay = this.startDate && this.startDate.isDate;
|
||||
|
||||
var promotedProps = {
|
||||
"DTSTART": true,
|
||||
"DTEND": true,
|
||||
"DTSTAMP": true,
|
||||
__proto__: this.itemBasePromotedProps
|
||||
};
|
||||
this.importUnpromotedProperties(event, promotedProps);
|
||||
this.importUnpromotedProperties(event, eventPromotedProps);
|
||||
// Importing didn't really change anything
|
||||
this.mDirty = false;
|
||||
},
|
||||
|
||||
isPropertyPromoted: function (name) {
|
||||
return (this.eventPromotedProps[name]);
|
||||
},
|
||||
|
||||
getOccurrencesBetween: function(aStartDate, aEndDate, aCount) {
|
||||
if (this.recurrenceInfo) {
|
||||
return this.recurrenceInfo.getOccurrences(aStartDate, aEndDate, 0, aCount);
|
||||
@ -194,10 +223,8 @@ calEvent.prototype = {
|
||||
if ((this.startDate.compare(aStartDate) >= 0 && this.startDate.compare(aEndDate) <= 0) ||
|
||||
(this.endDate.compare(aStartDate) >= 0 && this.endDate.compare(aEndDate) <= 0))
|
||||
{
|
||||
var occ = Components.classes["@mozilla.org/calendar/item-occurrence;1"].createInstance(Components.interfaces.calIItemOccurrence);
|
||||
occ.initialize(this, this.startDate, this.endDate);
|
||||
aCount.value = 1;
|
||||
return ([ occ ]);
|
||||
return ([ this ]);
|
||||
}
|
||||
|
||||
aCount.value = 0;
|
||||
@ -209,7 +236,8 @@ calEvent.prototype = {
|
||||
|
||||
var makeMemberAttr;
|
||||
if (makeMemberAttr) {
|
||||
makeMemberAttr(calEvent, "mStartDate", null, "startDate");
|
||||
makeMemberAttr(calEvent, "mEndDate", null, "endDate");
|
||||
makeMemberAttr(calEvent, "DTSTART", null, "startDate", true);
|
||||
makeMemberAttr(calEvent, "DTEND", null, "endDate", true);
|
||||
// XXX get rid of this
|
||||
makeMemberAttr(calEvent, "mIsAllDay", false, "isAllDay");
|
||||
}
|
||||
|
@ -948,7 +948,7 @@ calIcalComponent::RemoveProperty(calIIcalProperty *prop)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(calICSService, calIICSService)
|
||||
NS_IMPL_ISUPPORTS1_CI(calICSService, calIICSService)
|
||||
|
||||
calICSService::calICSService()
|
||||
{
|
||||
|
@ -42,10 +42,23 @@
|
||||
//
|
||||
|
||||
const ICAL = Components.interfaces.calIIcalComponent;
|
||||
const kHashPropertyBagContractID = "@mozilla.org/hash-property-bag;1";
|
||||
const kIWritablePropertyBag = Components.interfaces.nsIWritablePropertyBag;
|
||||
const HashPropertyBag = new Components.Constructor(kHashPropertyBagContractID, kIWritablePropertyBag);
|
||||
|
||||
function calItemBase() { }
|
||||
function NewCalDateTime(aJSDate) {
|
||||
var c = new CalDateTime();
|
||||
if (aJSDate)
|
||||
c.jsDate = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
function calItemBase() {
|
||||
}
|
||||
|
||||
calItemBase.prototype = {
|
||||
mIsProxy: false,
|
||||
|
||||
QueryInterface: function (aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.calIItemBase))
|
||||
@ -56,21 +69,63 @@ calItemBase.prototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
mParentItem: null,
|
||||
get parentItem() {
|
||||
if (this.mParentItem)
|
||||
return this.mParentItem;
|
||||
else
|
||||
return this;
|
||||
},
|
||||
set parentItem(value) {
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
this.mIsProxy = true;
|
||||
this.mParentItem = value;
|
||||
},
|
||||
|
||||
initializeProxy: function (aParentItem) {
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
if (this.mParentItem != null)
|
||||
throw Components.results.NS_ERROR_FAILURE;
|
||||
|
||||
this.mParentItem = aParentItem;
|
||||
this.mCalendar = aParentItem.mCalendar;
|
||||
this.mIsProxy = true;
|
||||
},
|
||||
|
||||
//
|
||||
// calIItemBase
|
||||
//
|
||||
mImmutable: false,
|
||||
get isMutable() { return !this.mImmutable; },
|
||||
|
||||
mDirty: false,
|
||||
modify: function() {
|
||||
if (this.mImmutable)
|
||||
// Components.results.NS_ERROR_CALENDAR_IMMUTABLE;
|
||||
throw Components.results.NS_ERROR_FAILURE;
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
this.mDirty = true;
|
||||
},
|
||||
|
||||
makeItemBaseImmutable: function() {
|
||||
// make all our components immutable
|
||||
this.mCreationDate.makeImmutable();
|
||||
ensureNotDirty: function() {
|
||||
if (!this.mDirty)
|
||||
return;
|
||||
|
||||
if (this.mImmutable) {
|
||||
dump ("### Something tried to undirty a dirty immutable event!\n");
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
}
|
||||
|
||||
this.setProperty("LAST-MODIFIED", NewCalDateTime(new Date()));
|
||||
this.mDirty = false;
|
||||
},
|
||||
|
||||
makeItemBaseImmutable: function() {
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
// make all our components immutable
|
||||
if (this.mRecurrenceInfo)
|
||||
this.mRecurrenceInfo.makeImmutable();
|
||||
if (this.mAlarmTime)
|
||||
@ -80,25 +135,31 @@ calItemBase.prototype = {
|
||||
this.mOrganizer.makeImmutable();
|
||||
for (var i = 0; i < this.mAttendees.length; i++)
|
||||
this.mAttendees[i].makeImmutable();
|
||||
|
||||
var e = this.mProperties.enumerator;
|
||||
while (e.hasMoreElements()) {
|
||||
var prop = e.getNext().QueryInterface(Components.interfaces.nsIProperty);
|
||||
var val = prop.value;
|
||||
|
||||
if (prop.value instanceof Components.interfaces.calIDateTime) {
|
||||
if (prop.value.isMutable)
|
||||
prop.value.makeImmutable();
|
||||
}
|
||||
}
|
||||
|
||||
this.ensureNotDirty();
|
||||
this.mImmutable = true;
|
||||
},
|
||||
|
||||
// initialize this class's members
|
||||
initItemBase: function () {
|
||||
this.mCreationDate = new CalDateTime();
|
||||
this.mAlarmTime = new CalDateTime();
|
||||
this.mLastModifiedTime = new CalDateTime();
|
||||
this.mStampTime = new CalDateTime();
|
||||
var now = new Date();
|
||||
|
||||
this.mCreationDate.jsDate = new Date();
|
||||
this.mLastModifiedTime.jsDate = new Date();
|
||||
this.mStampTime.jsDate = new Date();
|
||||
|
||||
this.mProperties = Components.classes["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Components.interfaces.nsIWritablePropertyBag);
|
||||
this.mProperties = new HashPropertyBag();
|
||||
|
||||
this.mAttachments = Components.classes["@mozilla.org/array;1"].
|
||||
createInstance(Components.interfaces.nsIArray);
|
||||
this.setProperty("CREATED", NewCalDateTime(now));
|
||||
this.setProperty("LAST-MODIFIED", NewCalDateTime(now));
|
||||
this.setProperty("DTSTAMP", NewCalDateTime(now));
|
||||
|
||||
this.mAttendees = [];
|
||||
|
||||
@ -108,82 +169,173 @@ calItemBase.prototype = {
|
||||
},
|
||||
|
||||
// for subclasses to use; copies the ItemBase's values
|
||||
// into m
|
||||
cloneItemBaseInto: function (m) {
|
||||
var suppressDCE = this.lastModifiedTime;
|
||||
suppressDCE = this.stampTime;
|
||||
// into m. aNewParent is optional
|
||||
cloneItemBaseInto: function (m, aNewParent) {
|
||||
this.updateStampTime();
|
||||
this.ensureNotDirty();
|
||||
|
||||
m.mImmutable = false;
|
||||
m.mGeneration = this.mGeneration;
|
||||
m.mLastModifiedTime = this.mLastModifiedTime.clone();
|
||||
m.mCalendar = this.mCalendar;
|
||||
m.mId = this.mId;
|
||||
m.mTitle = this.mTitle;
|
||||
m.mPriority = this.mPriority;
|
||||
m.mPrivacy = this.mPrivacy;
|
||||
m.mStatus = this.mStatus;
|
||||
m.mHasAlarm = this.mHasAlarm;
|
||||
m.mIsProxy = this.mIsProxy;
|
||||
m.mParentItem = aNewParent || this.mParentItem;
|
||||
|
||||
m.mCreationDate = this.mCreationDate.clone();
|
||||
m.mStampTime = this.mStampTime.clone();
|
||||
m.mCalendar = this.mCalendar;
|
||||
if (this.mRecurrenceInfo) {
|
||||
m.mRecurrenceInfo = this.mRecurrenceInfo.clone();
|
||||
dump ("old recurType: " + this.mRecurrenceInfo.recurType + " new type: " + m.mRecurrenceInfo.recurType + "\n");
|
||||
m.mRecurrenceInfo.item = m;
|
||||
}
|
||||
if (this.mAlarmTime)
|
||||
m.mAlarmTime = this.mAlarmTime.clone();
|
||||
|
||||
m.mAttendees = [];
|
||||
for (var i = 0; i < this.mAttendees.length; i++)
|
||||
m.mAttendees[i] = this.mAttendees[i].clone();
|
||||
|
||||
// these need fixing
|
||||
m.mAttachments = this.mAttachments;
|
||||
|
||||
m.mProperties = Components.classes["@mozilla.org/hash-property-bag;1"].
|
||||
createInstance(Components.interfaces.nsIWritablePropertyBag);
|
||||
|
||||
var e = this.mProperties.enumerator;
|
||||
while (e.hasMoreElements()) {
|
||||
var prop = e.getNext().QueryInterface(Components.interfaces.nsIProperty);
|
||||
m.mProperties.setProperty (prop.name, prop.value);
|
||||
var val = prop.value;
|
||||
|
||||
if (prop.value instanceof Components.interfaces.calIDateTime)
|
||||
val = prop.value.clone();
|
||||
|
||||
m.mProperties.setProperty (prop.name, val);
|
||||
}
|
||||
|
||||
m.mDirty = this.mDirty;
|
||||
m.mDirty = false;
|
||||
|
||||
// these need fixing
|
||||
m.mAttachments = this.mAttachments;
|
||||
return m;
|
||||
},
|
||||
|
||||
get lastModifiedTime() {
|
||||
if (this.mDirty) {
|
||||
this.mLastModifiedTime.jsDate = new Date();
|
||||
this.mDirty = false;
|
||||
}
|
||||
return this.mLastModifiedTime;
|
||||
this.ensureNotDirty();
|
||||
return this.getProperty("LAST-MODIFIED");
|
||||
},
|
||||
|
||||
mStampTime: null,
|
||||
get stampTime() {
|
||||
if (this.mStampTime.isValid)
|
||||
return this.mStampTime;
|
||||
return this.mLastModifiedTime;
|
||||
var prop = this.getProperty("DTSTAMP");
|
||||
if (prop && prop.isValid)
|
||||
return prop;
|
||||
return this.getProperty("LAST-MODIFIED");
|
||||
},
|
||||
|
||||
updateStampTime: function() {
|
||||
// can't update the stamp time on an immutable event
|
||||
if (this.mImmutable)
|
||||
return;
|
||||
|
||||
this.modify();
|
||||
this.mStampTime.jsDate = new Date();
|
||||
this.setProperty("DTSTAMP", NewCalDateTime(new Date()));
|
||||
},
|
||||
|
||||
get propertyEnumerator() { return this.mProperties.enumerator; },
|
||||
get unproxiedPropertyEnumerator() {
|
||||
return this.mProperties.enumerator;
|
||||
},
|
||||
|
||||
get propertyEnumerator() {
|
||||
if (this.mIsProxy) {
|
||||
// nsISimpleEnumerator sucks. It really, really sucks.
|
||||
// The interface is badly defined, it's not clear
|
||||
// what happens if you just keep calling getNext() without
|
||||
// calling hasMoreElements in between, which seems like more
|
||||
// of an informational thing. An interface with
|
||||
// "advance()" which returns true or false, and with "item()",
|
||||
// which returns the item the enumerator is pointing to, makes
|
||||
// far more sense. Right now we have getNext() doing both
|
||||
// item returning and enumerator advancing, which makes
|
||||
// no sense.
|
||||
return {
|
||||
firstEnumerator: this.mProperties.eumerator,
|
||||
secondEnumerator: this.mParentItem.propertyEnumerator,
|
||||
handledProperties: { },
|
||||
|
||||
currentItem: null,
|
||||
|
||||
QueryInterface: function(aIID) {
|
||||
if (!aIID.equals(Components.interfaces.nsISimpleEnumerator) ||
|
||||
!aIID.equals(Components.interfaces.nsISupports))
|
||||
{
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
hasMoreElements: function() {
|
||||
if (!this.secondEnumerator)
|
||||
return false;
|
||||
|
||||
if (this.firstEnumerator) {
|
||||
var moreFirst = this.firstEnumerator.hasMoreElements();
|
||||
if (moreFirst) {
|
||||
this.currentItem = this.firstEnumerator.getNext();
|
||||
this.handledProperties[this.currentItem.name] = true;
|
||||
return true;
|
||||
}
|
||||
this.firstEnumerator = null;
|
||||
}
|
||||
|
||||
var moreSecond = this.secondEnumerator.hasMoreElements();
|
||||
if (moreSecond) {
|
||||
while (this.currentItem.name in this.handledProperties &&
|
||||
this.secondEnumerator.hasMoreElements())
|
||||
do {
|
||||
this.currentItem = this.secondEnumerator.getNext();
|
||||
} while (this.currentItem.name in this.handledProperties &&
|
||||
((this.currentItem = null) == null) && // hack
|
||||
this.secondEnumerator.hasMoreElements());
|
||||
|
||||
if (!this.currentItem)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
this.secondEnumerator = null;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
getNext: function() {
|
||||
if (!currentItem)
|
||||
throw Components.results.NS_ERROR_UNEXPECTED;
|
||||
|
||||
var rval = this.currentItem;
|
||||
this.currentItem = null;
|
||||
return rval;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return this.mProperties.enumerator;
|
||||
}
|
||||
},
|
||||
|
||||
getProperty: function (aName) {
|
||||
try {
|
||||
return this.mProperties.getProperty(aName);
|
||||
} catch (e) {
|
||||
try {
|
||||
if (this.mIsProxy) {
|
||||
return this.mParentItem.getProperty(aName);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
getUnproxiedProperty: function (aName) {
|
||||
try {
|
||||
return this.mProperties.getProperty(aName);
|
||||
} catch (e) { }
|
||||
return null;
|
||||
},
|
||||
|
||||
hasProperty: function (aName) {
|
||||
return (this.getProperty(aName) != null);
|
||||
},
|
||||
|
||||
setProperty: function (aName, aValue) {
|
||||
this.modify();
|
||||
this.mProperties.setProperty(aName, aValue);
|
||||
@ -193,8 +345,7 @@ calItemBase.prototype = {
|
||||
this.modify();
|
||||
try {
|
||||
this.mProperties.deleteProperty(aName);
|
||||
} catch (e) {
|
||||
}
|
||||
} catch (e) { }
|
||||
},
|
||||
|
||||
getAttendees: function (countObj) {
|
||||
@ -240,8 +391,7 @@ calItemBase.prototype = {
|
||||
|
||||
set calendar (v) {
|
||||
if (this.mImmutable)
|
||||
// Components.results.NS_ERROR_CALENDAR_IMMUTABLE;
|
||||
throw Components.results.NS_ERROR_FAILURE;
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
this.mCalendar = v;
|
||||
},
|
||||
|
||||
@ -280,38 +430,37 @@ calItemBase.prototype = {
|
||||
"RDATE": true,
|
||||
"ATTENDEE": true,
|
||||
"ORGANIZER": true,
|
||||
"RECURRENCE-ID": true,
|
||||
},
|
||||
|
||||
icsBasePropMap: [
|
||||
{ cal: "CREATED", ics: "createdTime" },
|
||||
{ cal: "LAST-MODIFIED", ics: "lastModified" },
|
||||
{ cal: "DTSTAMP", ics: "stampTime" },
|
||||
{ cal: "UID", ics: "uid" },
|
||||
{ cal: "SUMMARY", ics: "summary" },
|
||||
{ cal: "PRIORITY", ics: "priority" },
|
||||
{ cal: "STATUS", ics: "status" },
|
||||
{ cal: "CLASS", ics: "icalClass" } ],
|
||||
|
||||
mapPropsFromICS: function(icalcomp, propmap) {
|
||||
for (var i = 0; i < propmap.length; i++) {
|
||||
var prop = propmap[i];
|
||||
var val = icalcomp[prop.ics];
|
||||
if (val != null && val != ICAL.INVALID_VALUE)
|
||||
this[prop.cal] = val;
|
||||
this.setProperty(prop.cal, val);
|
||||
}
|
||||
},
|
||||
|
||||
mapPropsToICS: function(icalcomp, propmap) {
|
||||
for (var i = 0; i < propmap.length; i++) {
|
||||
var prop = propmap[i];
|
||||
if (!(prop.cal in this))
|
||||
continue;
|
||||
var val = this[prop.cal];
|
||||
var val = this.getProperty(prop.cal);
|
||||
if (val != null && val != ICAL.INVALID_VALUE)
|
||||
icalcomp[prop.ics] = val;
|
||||
}
|
||||
},
|
||||
|
||||
icsBasePropMap: [
|
||||
{ cal: "mCreationDate", ics: "createdTime" },
|
||||
{ cal: "mLastModifiedTime", ics: "lastModified" },
|
||||
{ cal: "mStampTime", ics: "stampTime" },
|
||||
{ cal: "mId", ics: "uid" },
|
||||
{ cal: "mTitle", ics: "summary" },
|
||||
{ cal: "mPriority", ics: "priority" },
|
||||
{ cal: "mStatus", ics: "status" },
|
||||
{ cal: "mPrivacy", ics: "icalClass" }],
|
||||
|
||||
setItemBaseFromICS: function (icalcomp) {
|
||||
this.modify();
|
||||
|
||||
@ -360,7 +509,7 @@ calItemBase.prototype = {
|
||||
|
||||
if (!rec) {
|
||||
rec = new CalRecurrenceInfo();
|
||||
rec.initialize(this);
|
||||
rec.item = this;
|
||||
}
|
||||
|
||||
rec.appendRecurrenceItem(ritem);
|
||||
@ -380,14 +529,19 @@ calItemBase.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
isPropertyPromoted: function (name) {
|
||||
return (this.itemBasePromotedProps[name]);
|
||||
},
|
||||
|
||||
get icalComponent() {
|
||||
throw Components.results.NS_NOT_IMPLEMENTED;
|
||||
},
|
||||
|
||||
fillIcalComponentFromBase: function (icalcomp) {
|
||||
// Make sure that the LMT and ST are updated
|
||||
var suppressDCE = this.lastModifiedTime;
|
||||
suppressDCE = this.stampTime;
|
||||
this.updateStampTime();
|
||||
this.ensureNotDirty();
|
||||
|
||||
this.mapPropsToICS(icalcomp, this.icsBasePropMap);
|
||||
|
||||
if (this.mOrganizer)
|
||||
@ -415,107 +569,35 @@ calItemBase.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function calItemOccurrence () {
|
||||
this.wrappedJSObject = this;
|
||||
makeMemberAttr(calItemBase, "X-MOZILLA-GENERATION", 0, "generation", true);
|
||||
makeMemberAttr(calItemBase, "CREATED", null, "creationDate", true);
|
||||
makeMemberAttr(calItemBase, "UID", null, "id", true);
|
||||
makeMemberAttr(calItemBase, "SUMMARY", null, "title", true);
|
||||
makeMemberAttr(calItemBase, "PRIORITY", 0, "priority", true);
|
||||
makeMemberAttr(calItemBase, "CLASS", "PUBLIC", "privacy", true);
|
||||
makeMemberAttr(calItemBase, "STATUS", null, "status", true);
|
||||
makeMemberAttr(calItemBase, "ALARMTIME", null, "alarmTime", true);
|
||||
makeMemberAttr(calItemBase, "RECURRENCE-ID", null, "recurrenceId", true);
|
||||
|
||||
this.occurrenceStartDate = new CalDateTime();
|
||||
this.occurrenceEndDate = new CalDateTime();
|
||||
}
|
||||
|
||||
calItemOccurrenceClassInfo = {
|
||||
getInterfaces: function (count) {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calIItemOccurrence
|
||||
];
|
||||
count.value = ifaces.length;
|
||||
return ifaces;
|
||||
},
|
||||
|
||||
getHelperForLanguage: function (language) {
|
||||
return null;
|
||||
},
|
||||
|
||||
contractID: "@mozilla.org/calendar/item-occurrence;1",
|
||||
classDescription: "Calendar Item Occurrence",
|
||||
classID: Components.ID("{bad672b3-30b8-4ecd-8075-7153313d1f2c}"),
|
||||
implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
|
||||
flags: 0
|
||||
};
|
||||
|
||||
calItemOccurrence.prototype = {
|
||||
QueryInterface: function (aIID) {
|
||||
if (aIID.equals(Components.interfaces.nsIClassInfo))
|
||||
return calItemOccurrenceClassInfo;
|
||||
|
||||
if (!aIID.equals(Components.interfaces.nsISupports) &&
|
||||
!aIID.equals(Components.interfaces.calIItemOccurrence))
|
||||
{
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
initialize: function (aItem, aStartDate, aEndDate) {
|
||||
this.item = aItem;
|
||||
this.occurrenceStartDate = aStartDate.clone();
|
||||
this.occurrenceStartDate.makeImmutable();
|
||||
this.occurrenceEndDate = aEndDate.clone();
|
||||
this.occurrenceEndDate.makeImmutable();
|
||||
},
|
||||
|
||||
item: null,
|
||||
occurrenceStartDate: null,
|
||||
occurrenceEndDate: null,
|
||||
|
||||
get next() {
|
||||
if (this.item.recurrenceInfo)
|
||||
return this.item.recurrenceInfo.getNextOccurrence(this.item, aEndDate);
|
||||
return null;
|
||||
},
|
||||
get previous() {
|
||||
if (this.item.recurrenceInfo)
|
||||
return this.item.recurrenceInfo.getPreviousOccurrence(this.item, aStartDate);
|
||||
return null;
|
||||
},
|
||||
|
||||
equals: function(aOther) {
|
||||
if (this.item.id != aOther.item.id)
|
||||
return false;
|
||||
|
||||
if (this.occurrenceStartDate.compare(aOther.occurrenceStartDate) != 0)
|
||||
return false;
|
||||
|
||||
if (this.occurrenceEndDate.compare(aOther.occurrenceEndDate) != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
makeMemberAttr(calItemBase, "mGeneration", 0, "generation");
|
||||
makeMemberAttr(calItemBase, "mCreationDate", null, "creationDate");
|
||||
makeMemberAttr(calItemBase, "mId", null, "id");
|
||||
makeMemberAttr(calItemBase, "mTitle", null, "title");
|
||||
makeMemberAttr(calItemBase, "mPriority", 0, "priority");
|
||||
makeMemberAttr(calItemBase, "mPrivacy", "PUBLIC", "privacy");
|
||||
makeMemberAttr(calItemBase, "mStatus", null, "status");
|
||||
makeMemberAttr(calItemBase, "mHasAlarm", false, "hasAlarm");
|
||||
makeMemberAttr(calItemBase, "mAlarmTime", null, "alarmTime");
|
||||
makeMemberAttr(calItemBase, "mRecurrenceInfo", null, "recurrenceInfo");
|
||||
makeMemberAttr(calItemBase, "mAttachments", null, "attachments");
|
||||
makeMemberAttr(calItemBase, "mProperties", null, "properties");
|
||||
|
||||
function makeMemberAttr(ctor, varname, dflt, attr)
|
||||
function makeMemberAttr(ctor, varname, dflt, attr, asProperty)
|
||||
{
|
||||
ctor.prototype[varname] = dflt;
|
||||
// XXX handle defaults!
|
||||
var getter = function () {
|
||||
return this[varname];
|
||||
if (asProperty)
|
||||
return this.getProperty(varname);
|
||||
else
|
||||
return this[varname];
|
||||
};
|
||||
var setter = function (v) {
|
||||
this.modify();
|
||||
this[varname] = v;
|
||||
if (asProperty)
|
||||
this.setProperty(varname, v);
|
||||
else
|
||||
this[varname] = v;
|
||||
};
|
||||
ctor.prototype.__defineGetter__(attr, getter);
|
||||
ctor.prototype.__defineSetter__(attr, setter);
|
||||
|
@ -105,11 +105,6 @@ const componentData =
|
||||
script: "calTodo.js",
|
||||
constructor: "calTodo"},
|
||||
|
||||
{cid: Components.ID("{bad672b3-30b8-4ecd-8075-7153313d1f2c}"),
|
||||
contractid: "@mozilla.org/calendar/item-occurrence;1",
|
||||
script: null,
|
||||
constructor: "calItemOccurrence"},
|
||||
|
||||
{cid: Components.ID("{5c8dcaa3-170c-4a73-8142-d531156f664d}"),
|
||||
contractid: "@mozilla.org/calendar/attendee;1",
|
||||
script: "calAttendee.js",
|
||||
@ -118,7 +113,12 @@ const componentData =
|
||||
{cid: Components.ID("{5f76b352-ab75-4c2b-82c9-9206dbbf8571}"),
|
||||
contractid: "@mozilla.org/calendar/attachment;1",
|
||||
script: "calAttachment.js",
|
||||
constructor: "calAttachment"}
|
||||
constructor: "calAttachment"},
|
||||
|
||||
{cid: Components.ID("{04027036-5884-4a30-b4af-f2cad79f6edf}"),
|
||||
contractid: "@mozilla.org/calendar/recurrence-info;1",
|
||||
script: "calRecurrenceInfo.js",
|
||||
constructor: "calRecurrenceInfo"}
|
||||
];
|
||||
|
||||
var calItemModule = {
|
||||
@ -151,8 +151,13 @@ var calItemModule = {
|
||||
var f = appdir.clone();
|
||||
f.append(scriptName);
|
||||
|
||||
var fileurl = iosvc.newFileURI(f);
|
||||
loader.loadSubScript(fileurl.spec, null);
|
||||
try {
|
||||
var fileurl = iosvc.newFileURI(f);
|
||||
loader.loadSubScript(fileurl.spec, null);
|
||||
} catch (e) {
|
||||
dump("Error while loading " + fileurl.spec + "\n");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
this.mScriptsLoaded = true;
|
||||
|
@ -48,7 +48,7 @@ extern "C" {
|
||||
#include "ical.h"
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS2(calRecurrenceDate, calIRecurrenceItem, calIRecurrenceDate)
|
||||
NS_IMPL_ISUPPORTS2_CI(calRecurrenceDate, calIRecurrenceItem, calIRecurrenceDate)
|
||||
|
||||
calRecurrenceDate::calRecurrenceDate()
|
||||
: mImmutable(PR_FALSE),
|
||||
@ -112,6 +112,15 @@ calRecurrenceDate::SetIsNegative(PRBool aIsNegative)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute boolean isFinite; */
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceDate::GetIsFinite(PRBool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
*_retval = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceDate::GetDate(calIDateTime **aDate)
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ extern "C" {
|
||||
#include "ical.h"
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS2(calRecurrenceDateSet, calIRecurrenceItem, calIRecurrenceDateSet)
|
||||
NS_IMPL_ISUPPORTS2_CI(calRecurrenceDateSet, calIRecurrenceItem, calIRecurrenceDateSet)
|
||||
|
||||
calRecurrenceDateSet::calRecurrenceDateSet()
|
||||
: mImmutable(PR_FALSE),
|
||||
@ -121,6 +121,15 @@ calRecurrenceDateSet::SetIsNegative(PRBool aIsNegative)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute boolean isFinite; */
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceDateSet::GetIsFinite(PRBool *_retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
*_retval = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceDateSet::GetDates(PRUint32 *aCount, calIDateTime ***aDates)
|
||||
{
|
||||
|
@ -1,398 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** 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 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 ***** */
|
||||
|
||||
#include "calBaseCID.h"
|
||||
|
||||
#include "calRecurrenceInfo.h"
|
||||
#include "calDateTime.h"
|
||||
#include "calIItemBase.h"
|
||||
#include "calIEvent.h"
|
||||
|
||||
#include "calICSService.h"
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(calRecurrenceInfo, calIRecurrenceInfo)
|
||||
|
||||
calRecurrenceInfo::calRecurrenceInfo()
|
||||
: mImmutable(PR_FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::GetIsMutable(PRBool *aResult)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aResult);
|
||||
|
||||
*aResult = !mImmutable;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::MakeImmutable()
|
||||
{
|
||||
if (mImmutable)
|
||||
return NS_ERROR_FAILURE; // XXX another error code
|
||||
|
||||
mImmutable = PR_TRUE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::Clone(calIRecurrenceInfo **aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
calRecurrenceInfo *cri = new calRecurrenceInfo;
|
||||
if (!cri)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
cri->mBaseItem = mBaseItem;
|
||||
|
||||
for (int i = 0; i < mRecurrenceItems.Count(); i++) {
|
||||
nsCOMPtr<calIRecurrenceItem> item;
|
||||
rv = mRecurrenceItems[i]->Clone(getter_AddRefs(item));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
cri->mRecurrenceItems.AppendObject(item);
|
||||
}
|
||||
|
||||
NS_ADDREF(*aResult = cri);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::Initialize(calIItemBase *aItem)
|
||||
{
|
||||
// should it be an error to initialize an already-initialized objet?
|
||||
mBaseItem = aItem;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::GetItem(calIItemBase **aResult)
|
||||
{
|
||||
NS_IF_ADDREF(*aResult = mBaseItem);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Recurrence Item set munging
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::GetRecurrenceItems (PRUint32 *aCount, calIRecurrenceItem ***aItems)
|
||||
{
|
||||
if (mRecurrenceItems.Count() == 0) {
|
||||
*aItems = nsnull;
|
||||
*aCount = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
calIRecurrenceItem **items = (calIRecurrenceItem**) nsMemory::Alloc (sizeof(calIRecurrenceItem*) * mRecurrenceItems.Count());
|
||||
if (!items)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
for (PRInt32 i = 0; i < mRecurrenceItems.Count(); i++) {
|
||||
NS_IF_ADDREF (items[i] = mRecurrenceItems[i]);
|
||||
}
|
||||
|
||||
*aItems = items;
|
||||
*aCount = mRecurrenceItems.Count();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::SetRecurrenceItems (PRUint32 aCount, calIRecurrenceItem **aItems)
|
||||
{
|
||||
if (mImmutable) {
|
||||
return NS_ERROR_FAILURE; // XXX different error
|
||||
}
|
||||
|
||||
mRecurrenceItems.Clear();
|
||||
for (PRUint32 i = 0; i < aCount; i++)
|
||||
mRecurrenceItems.AppendObject(aItems[i]);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::CountRecurrenceItems (PRUint32 *aCount)
|
||||
{
|
||||
*aCount = mRecurrenceItems.Count();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::GetRecurrenceItemAt (PRUint32 aIndex, calIRecurrenceItem **aItem)
|
||||
{
|
||||
NS_IF_ADDREF(*aItem = mRecurrenceItems[aIndex]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::AppendRecurrenceItem (calIRecurrenceItem *aItem)
|
||||
{
|
||||
if (mImmutable) {
|
||||
return NS_ERROR_FAILURE; // XXX different error
|
||||
}
|
||||
|
||||
mRecurrenceItems.AppendObject(aItem);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::DeleteRecurrenceItemAt (PRUint32 aIndex)
|
||||
{
|
||||
if (!mRecurrenceItems.RemoveObjectAt(aIndex))
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::InsertRecurrenceItemAt (calIRecurrenceItem *aItem, PRUint32 aIndex)
|
||||
{
|
||||
if (!mRecurrenceItems.InsertObjectAt(aItem, aIndex))
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::ClearRecurrenceItems ()
|
||||
{
|
||||
mRecurrenceItems.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// recurrence calculation
|
||||
//
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::GetNextOccurrence (calIDateTime *aOccurrenceTime, calIItemOccurrence **aItem)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aOccurrenceTime);
|
||||
NS_ENSURE_ARG_POINTER(aItem);
|
||||
|
||||
NS_ASSERTION (mBaseItem, "RecurrenceInfo not initialized");
|
||||
|
||||
PRInt32 i, j;
|
||||
PRInt32 result;
|
||||
nsresult rv;
|
||||
|
||||
nsCOMArray<calIDateTime> dates;
|
||||
nsCOMPtr<calIDateTime> date;
|
||||
|
||||
nsCOMPtr<calIDateTime> startDate;
|
||||
rv = mBaseItem->GetRecurrenceStartDate(getter_AddRefs(startDate));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
for (i = 0; i < mRecurrenceItems.Count(); i++) {
|
||||
rv = mRecurrenceItems[i]->GetNextOccurrence (startDate, aOccurrenceTime, getter_AddRefs(date));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if there is no next occurrence, continue.
|
||||
if (!date)
|
||||
continue;
|
||||
|
||||
PRBool isNegative = PR_FALSE;
|
||||
rv = mRecurrenceItems[i]->GetIsNegative(&isNegative);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (isNegative) {
|
||||
// if this is negative, we look for this date in the existing set, and remove it if its there
|
||||
for (j = dates.Count() - 1; j >= 0; j--) {
|
||||
if (NS_SUCCEEDED(dates[j]->Compare(date, &result)) && result == 0)
|
||||
dates.RemoveObjectAt(j);
|
||||
}
|
||||
} else {
|
||||
// if positive, we just add the date to the existing set
|
||||
dates.AppendObject(date);
|
||||
}
|
||||
}
|
||||
|
||||
// no next date found
|
||||
if (dates.Count() == 0) {
|
||||
*aItem = nsnull;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// find the earliest date in the set
|
||||
date = dates[0];
|
||||
for (i = 0; i < dates.Count(); i++) {
|
||||
if (NS_SUCCEEDED(date->Compare(dates[i], &result)) && result > 0)
|
||||
date = dates[i];
|
||||
}
|
||||
nsCOMPtr<calIDateTime> enddate;
|
||||
date->Clone(getter_AddRefs(enddate));
|
||||
|
||||
nsCOMPtr<calIEvent> event = do_QueryInterface(mBaseItem);
|
||||
if (event) {
|
||||
nsCOMPtr<calIDateTime> duration;
|
||||
rv = event->GetDuration(getter_AddRefs(duration));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
enddate->AddDuration(duration);
|
||||
}
|
||||
|
||||
nsCOMPtr<calIItemOccurrence> occ = do_CreateInstance(CAL_ITEM_OCCURRENCE_CONTRACTID);
|
||||
occ->Initialize(mBaseItem, date, enddate);
|
||||
NS_ADDREF(*aItem = occ);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static int PR_CALLBACK
|
||||
calDateTimeComparator (calIDateTime *aElement1,
|
||||
calIDateTime *aElement2,
|
||||
void *aData)
|
||||
{
|
||||
PRInt32 result;
|
||||
aElement1->Compare(aElement2, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceInfo::GetOccurrences (calIDateTime *aRangeStart,
|
||||
calIDateTime *aRangeEnd,
|
||||
PRUint32 aMaxCount,
|
||||
PRUint32 *aCount, calIItemOccurrence ***aItems)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRangeStart);
|
||||
NS_ENSURE_ARG_POINTER(aCount);
|
||||
NS_ENSURE_ARG_POINTER(aItems);
|
||||
|
||||
NS_ASSERTION (mBaseItem, "RecurrenceInfo not initialized");
|
||||
|
||||
PRInt32 i, j, k;
|
||||
PRInt32 result;
|
||||
nsresult rv;
|
||||
|
||||
nsCOMArray<calIDateTime> dates;
|
||||
|
||||
nsCOMPtr<calIDateTime> startDate;
|
||||
rv = mBaseItem->GetRecurrenceStartDate(getter_AddRefs(startDate));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
for (i = 0; i < mRecurrenceItems.Count(); i++) {
|
||||
calIDateTime **cur_dates = nsnull;
|
||||
PRUint32 num_cur_dates = 0;
|
||||
|
||||
// if both range start and end are specified, we ask for all of the occurrences,
|
||||
// to make sure we catch all possible exceptions. If aRangeEnd isn't specified,
|
||||
// then we have to ask for aMaxCount, and hope for the best.
|
||||
if (aRangeStart && aRangeEnd)
|
||||
rv = mRecurrenceItems[i]->GetOccurrences (startDate, aRangeStart, aRangeEnd, 0, &num_cur_dates, &cur_dates);
|
||||
else
|
||||
rv = mRecurrenceItems[i]->GetOccurrences (startDate, aRangeStart, aRangeEnd, aMaxCount, &num_cur_dates, &cur_dates);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// if there are no occurrences, continue.
|
||||
if (num_cur_dates == 0)
|
||||
continue;
|
||||
|
||||
PRBool isNegative = PR_FALSE;
|
||||
rv = mRecurrenceItems[i]->GetIsNegative(&isNegative);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (isNegative) {
|
||||
// if this is negative, we look for any of the given dates
|
||||
// in the existing set, and remove them if they're
|
||||
// present.
|
||||
for (j = dates.Count() - 1; j >= 0; j--) {
|
||||
for (k = 0; k < (int) num_cur_dates; k++) {
|
||||
if (NS_SUCCEEDED(dates[j]->Compare(cur_dates[k], &result)) && result == 0) {
|
||||
dates.RemoveObjectAt(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if positive, we just add these date to the existing set,
|
||||
// but only if they're not already there
|
||||
for (j = 0; j < (int) num_cur_dates; j++) {
|
||||
PRBool isFound = PR_FALSE;
|
||||
for (k = 0; k < dates.Count(); k++) {
|
||||
if (NS_SUCCEEDED(dates[k]->Compare(cur_dates[j], &result)) && result == 0) {
|
||||
isFound = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFound)
|
||||
dates.AppendObject(cur_dates[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now sort the resulting list
|
||||
dates.Sort(calDateTimeComparator, nsnull);
|
||||
|
||||
nsCOMPtr<calIDateTime> duration;
|
||||
nsCOMPtr<calIEvent> event = do_QueryInterface(mBaseItem);
|
||||
if (event) {
|
||||
rv = event->GetDuration(getter_AddRefs(duration));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
PRUint32 count = aMaxCount;
|
||||
if (!count)
|
||||
count = dates.Count();
|
||||
if (count) {
|
||||
calIItemOccurrence **occArray = (calIItemOccurrence **) nsMemory::Alloc(sizeof(calIItemOccurrence*) * count);
|
||||
for (int i = 0; i < (int) count; i++) {
|
||||
nsCOMPtr<calIItemOccurrence> occ = do_CreateInstance (CAL_ITEM_OCCURRENCE_CONTRACTID);
|
||||
|
||||
nsCOMPtr<calIDateTime> endDate;
|
||||
dates[i]->Clone(getter_AddRefs(endDate));
|
||||
|
||||
if (event) {
|
||||
endDate->AddDuration(duration);
|
||||
}
|
||||
|
||||
occ->Initialize (mBaseItem, dates[i], endDate);
|
||||
|
||||
NS_ADDREF(occArray[i] = occ);
|
||||
}
|
||||
|
||||
*aItems = occArray;
|
||||
} else {
|
||||
*aItems = nsnull;
|
||||
}
|
||||
*aCount = count;
|
||||
return NS_OK;
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** 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 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 ***** */
|
||||
|
||||
#ifndef CALRECURRENCEINFO_H_
|
||||
#define CALRECURRENCEINFO_H_
|
||||
|
||||
#include "calIRecurrenceInfo.h"
|
||||
|
||||
#include "calIItemBase.h"
|
||||
|
||||
#include "calIRecurrenceItem.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
class calRecurrenceInfo : public calIRecurrenceInfo
|
||||
{
|
||||
public:
|
||||
calRecurrenceInfo();
|
||||
|
||||
// nsISupports interface
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// calIRecurrenceInfo interface
|
||||
NS_DECL_CALIRECURRENCEINFO
|
||||
protected:
|
||||
PRBool mImmutable;
|
||||
|
||||
nsCOMPtr<calIItemBase> mBaseItem;
|
||||
nsCOMArray<calIRecurrenceItem> mRecurrenceItems;
|
||||
};
|
||||
|
||||
#endif /* CALRECURRENCEINFO_H_ */
|
646
calendar/base/src/calRecurrenceInfo.js
Normal file
646
calendar/base/src/calRecurrenceInfo.js
Normal file
@ -0,0 +1,646 @@
|
||||
/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** 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 lightning code.
|
||||
*
|
||||
* 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):
|
||||
* 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 ***** */
|
||||
|
||||
function calRecurrenceInfo() {
|
||||
this.mRecurrenceItems = new Array();
|
||||
this.mExceptions = new Array();
|
||||
}
|
||||
|
||||
function calDebug() {
|
||||
dump.apply(null, arguments);
|
||||
}
|
||||
|
||||
var calRecurrenceInfoClassInfo = {
|
||||
getInterfaces: function (count) {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calIRecurrenceInfo,
|
||||
Components.interfaces.nsIClassInfo
|
||||
];
|
||||
count.value = ifaces.length;
|
||||
return ifaces;
|
||||
},
|
||||
|
||||
getHelperForLanguage: function (language) {
|
||||
return null;
|
||||
},
|
||||
|
||||
contractID: "@mozilla.org/calendar/recurrence-info;1",
|
||||
classDescription: "Calendar Recurrence Info",
|
||||
classID: Components.ID("{04027036-5884-4a30-b4af-f2cad79f6edf}"),
|
||||
implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
|
||||
flags: 0
|
||||
};
|
||||
|
||||
calRecurrenceInfo.prototype = {
|
||||
// QI with CI
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Components.interfaces.nsISupports) ||
|
||||
aIID.equals(Components.interfaces.calIRecurrenceInfo))
|
||||
return this;
|
||||
|
||||
if (aIID.equals(Components.interfaces.nsIClassInfo))
|
||||
return calRecurrenceInfoClassInfo;
|
||||
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
//
|
||||
// Mutability bits
|
||||
//
|
||||
mImmutable: false,
|
||||
get isMutable() { return !this.mImmutable; },
|
||||
makeImmutable: function() {
|
||||
if (this.mImmutable)
|
||||
return;
|
||||
|
||||
for each (ritem in this.mRecurrenceItems) {
|
||||
if (ritem.isMutable)
|
||||
ritem.makeImmutable();
|
||||
}
|
||||
|
||||
for each (ex in this.mExceptions) {
|
||||
if (ex.item.isMutable)
|
||||
ex.item.makeImmutable();
|
||||
}
|
||||
|
||||
this.mImmutable = true;
|
||||
},
|
||||
|
||||
clone: function() {
|
||||
var cloned = new calRecurrenceInfo();
|
||||
cloned.mBaseItem = this.mBaseItem;
|
||||
|
||||
var clonedItems = [];
|
||||
for each (ritem in this.mRecurrenceItems)
|
||||
clonedItems.push(ritem.clone());
|
||||
cloned.mRecurrenceItems = clonedItems;
|
||||
|
||||
var clonedExceptions = [];
|
||||
for each (exitem in this.mExceptions) {
|
||||
var c = exitem.item.cloneShallow(this.mBaseItem);
|
||||
clonedExceptions.push( { id: exitem.id, item: c } );
|
||||
}
|
||||
cloned.mExceptions = clonedExceptions;
|
||||
|
||||
return cloned;
|
||||
},
|
||||
|
||||
//
|
||||
// calIRecurrenceInfo impl
|
||||
//
|
||||
mBaseItem: null,
|
||||
|
||||
get item() {
|
||||
return this.mBaseItem;
|
||||
},
|
||||
|
||||
set item(value) {
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
this.mBaseItem = value;
|
||||
},
|
||||
|
||||
mRecurrenceItems: null,
|
||||
|
||||
get isFinite() {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
for each (ritem in this.mRecurrenceItems) {
|
||||
if (!ritem.isFinite)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
getRecurrenceItems: function(aCount) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
aCount.value = this.mRecurrenceItems.length;
|
||||
return this.mRecurrenceItems;
|
||||
},
|
||||
|
||||
setRecurrenceItems: function(aCount, aItems) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
// should we clone these?
|
||||
this.mRecurrenceItems = aItems;
|
||||
},
|
||||
|
||||
countRecurrenceItems: function() {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
return this.mRecurrenceItems.length;
|
||||
},
|
||||
|
||||
getRecurrenceItemAt: function(aIndex) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (aIndex < 0 || aIndex >= mRecurrenceItems.length)
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
|
||||
return this.mRecurrenceItems[aIndex];
|
||||
},
|
||||
|
||||
appendRecurrenceItem: function(aItem) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
this.mRecurrenceItems.push(aItem);
|
||||
},
|
||||
|
||||
deleteRecurrenceItemAt: function(aIndex) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
if (aIndex < 0 || aIndex >= this.mRecurrenceItems.length)
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
|
||||
this.mRecurrenceItems.splice(aIndex, 1);
|
||||
},
|
||||
|
||||
insertRecurrenceItemAt: function(aItem, aIndex) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
if (aIndex < 0 || aIndex >= this.mRecurrenceItems.length)
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
|
||||
this.mRecurrenceItems.splice(aIndex, 0, aItem);
|
||||
},
|
||||
|
||||
clearRecurrenceItems: function() {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
this.mRecurrenceItems = new Array();
|
||||
},
|
||||
|
||||
//
|
||||
// calculations
|
||||
//
|
||||
|
||||
getNextOccurrenceDate: function (aTime) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
var startDate = this.mBaseItem.getRecurrenceStartDate();
|
||||
var dates = [];
|
||||
|
||||
for each (ritem in this.mRecurrenceItems) {
|
||||
var date = ritem.getNextOccurrence(startDate, aTime);
|
||||
if (!date)
|
||||
continue;
|
||||
|
||||
if (ritem.isNegative)
|
||||
dates = dates.filter(function (d) { return (d.compare(date) != 0); });
|
||||
else
|
||||
dates = dates.push(date);
|
||||
}
|
||||
|
||||
// if no dates, there's no next
|
||||
if (dates.length == 0)
|
||||
return null;
|
||||
|
||||
// find the earliest date
|
||||
var earliestDate = dates[0];
|
||||
dates.forEach(function (d) { if (d.compare(earliestDate) < 0) earliestDate = d; });
|
||||
|
||||
return earliestDate;
|
||||
},
|
||||
|
||||
getNextOccurrence: function (aTime) {
|
||||
var earliestDate = this.getNextOccurrenceDate (aTime);
|
||||
if (!earliestDate)
|
||||
return null;
|
||||
|
||||
if (this.mExceptions) {
|
||||
// scan exceptions for any dates earlier than
|
||||
// earliestDate (but still after aTime)
|
||||
this.mExceptions.forEach (function (ex) {
|
||||
var dtstart = ex.item.getProperty("DTSTART");
|
||||
if (aTime.compare(dtstart) <= 0 &&
|
||||
earliestDate.compare(dtstart) > 0)
|
||||
{
|
||||
earliestDate = dtstart;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var startDate = earliestDate.clone();
|
||||
var endDate = null;
|
||||
|
||||
if (this.mBaseItem.hasProperty("DTEND")) {
|
||||
endDate = earliestDate.clone();
|
||||
endDate.addDuration(this.mBaseItem.duration);
|
||||
}
|
||||
|
||||
var proxy = this.mBaseItem.createProxy();
|
||||
proxy.setRecurrenceId(earliestDate);
|
||||
|
||||
proxy.setProperty("DTSTART", startDate);
|
||||
if (endDate)
|
||||
proxy.setProperty("DTEND", endDate);
|
||||
|
||||
return proxy;
|
||||
},
|
||||
|
||||
// internal helper function;
|
||||
calculateDates: function (aRangeStart, aRangeEnd,
|
||||
aMaxCount, aIncludeExceptions, aReturnRIDs)
|
||||
{
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
var startDate = this.mBaseItem.recurrenceStartDate;
|
||||
var dates = [];
|
||||
|
||||
for each (ritem in this.mRecurrenceItems) {
|
||||
var cur_dates;
|
||||
|
||||
// if both range start and end are specified, we ask for all of the occurrences,
|
||||
// to make sure we catch all possible exceptions. If aRangeEnd isn't specified,
|
||||
// then we have to ask for aMaxCount, and hope for the best.
|
||||
if (aRangeStart && aRangeEnd)
|
||||
cur_dates = ritem.getOccurrences(startDate, aRangeStart, aRangeEnd, 0, {});
|
||||
else
|
||||
cur_dates = ritem.getOccurrences(startDate, aRangeStart, aRangeEnd, aMaxCount, {});
|
||||
|
||||
if (cur_dates.length == 0)
|
||||
continue;
|
||||
|
||||
if (ritem.isNegative) {
|
||||
// if this is negative, we look for any of the given dates
|
||||
// in the existing set, and remove them if they're
|
||||
// present.
|
||||
|
||||
// XXX: i'm pretty sure negative dates can't really have exceptions
|
||||
// (like, you can't make a date "real" by defining an RECURRENCE-ID which
|
||||
// is an EXDATE, and then giving it a real DTSTART) -- so we don't
|
||||
// check exceptions here
|
||||
cur_dates.forEach (function (dateToRemove) {
|
||||
dates = dates.filter(function (d) { return d.compare(dateToRemove) != 0; });
|
||||
});
|
||||
} else {
|
||||
// if positive, we just add these date to the existing set,
|
||||
// but only if they're not already there
|
||||
var datesToAdd = [];
|
||||
var rinfo = this;
|
||||
cur_dates.forEach (function (dateToAdd) {
|
||||
if (!dates.some(function (d) { return d.compare(dateToAdd) == 0; })) {
|
||||
if (aIncludeExceptions && rinfo.mExceptions)
|
||||
{
|
||||
// only add if there's no exception for this;
|
||||
// we'll test all exception dates later on
|
||||
if (!rinfo.getExceptionFor(dateToAdd, false))
|
||||
dates.push(dateToAdd);
|
||||
} else {
|
||||
dates.push(dateToAdd);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Now toss in exceptions into this list; we just scan them all.
|
||||
if (aIncludeExceptions && this.mExceptions) {
|
||||
this.mExceptions.forEach(function(ex) {
|
||||
var dtstart = ex.item.getProperty("DTSTART");
|
||||
var dateToReturn;
|
||||
if (aReturnRIDs)
|
||||
dateToReturn = ex.id;
|
||||
else
|
||||
dateToReturn = dtstart;
|
||||
// is our startdate within the range?
|
||||
if ((!aRangeStart || aRangeStart.compare(dtstart) <= 0) &&
|
||||
(!aRangeEnd || aRangeEnd.compare(dtstart) > 0))
|
||||
{
|
||||
dates.push(dateToReturn);
|
||||
return;
|
||||
}
|
||||
|
||||
// is our end date within the range?
|
||||
var dtend = ex.item.getProperty("DTEND");
|
||||
if ((!aRangeStart || aRangeStart.compare(dtend) <= 0) &&
|
||||
(!aRangeEnd || aRangeEnd.compare(dtend) > 0))
|
||||
{
|
||||
dates.push(dateToReturn);
|
||||
return;
|
||||
}
|
||||
|
||||
// is the range in the middle of a long event?
|
||||
if (aRangeStart && aRangeEnd &&
|
||||
aRangeStart.compare(dtstart) >= 0 &&
|
||||
aRangeEnd.compare(dtend) <= 0)
|
||||
{
|
||||
dates.push(dateToReturn);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// now sort the list
|
||||
dates.sort(function (a,b) { return a.compare(b); });
|
||||
|
||||
// chop anything over aMaxCount, if specified
|
||||
if (aMaxCount && dates.length > aMaxCount)
|
||||
dates = dates.splice(aMaxCount, dates.length - aMaxCount);
|
||||
|
||||
return dates;
|
||||
},
|
||||
|
||||
getOccurrenceDates: function (aRangeStart, aRangeEnd,
|
||||
aMaxCount, aCount)
|
||||
{
|
||||
var dates = this.calculateDates(aRangeStart, aRangeEnd, aMaxCount, true, false);
|
||||
aCount.value = dates.length;
|
||||
return dates;
|
||||
},
|
||||
|
||||
getOccurrences: function (aRangeStart, aRangeEnd,
|
||||
aMaxCount,
|
||||
aCount)
|
||||
{
|
||||
var dates = this.calculateDates(aRangeStart, aRangeEnd, aMaxCount, true, true);
|
||||
if (dates.length == 0) {
|
||||
aCount.value = 0;
|
||||
return [];
|
||||
}
|
||||
|
||||
var count = aMaxCount;
|
||||
if (!count)
|
||||
count = dates.length;
|
||||
|
||||
var results = [];
|
||||
|
||||
for (var i = 0; i < count; i++) {
|
||||
var proxy = this.getOccurrenceFor(dates[i]);
|
||||
results.push(proxy);
|
||||
}
|
||||
|
||||
aCount.value = results.length;
|
||||
return results;
|
||||
},
|
||||
|
||||
getOccurrenceFor: function (aRecurrenceId) {
|
||||
var proxy = this.getExceptionFor(aRecurrenceId, false);
|
||||
if (!proxy) {
|
||||
var duration = null;
|
||||
if (this.mBaseItem.hasProperty("DTEND"))
|
||||
duration = this.mBaseItem.duration;
|
||||
|
||||
proxy = this.mBaseItem.createProxy();
|
||||
proxy.recurrenceId = aRecurrenceId;
|
||||
proxy.setProperty("DTSTART", aRecurrenceId.clone());
|
||||
if (duration) {
|
||||
var enddate = aRecurrenceId.clone();
|
||||
enddate.addDuration(duration);
|
||||
proxy.setProperty("DTEND", enddate);
|
||||
}
|
||||
if (!this.mBaseItem.isMutable)
|
||||
proxy.makeImmutable();
|
||||
}
|
||||
return proxy;
|
||||
},
|
||||
|
||||
removeOccurrenceAt: function (aRecurrenceId) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
var d = Components.classes["@mozilla.org/calendar/recurrence-date;1"].createInstance(Components.interfaces.calIRecurrenceDate);
|
||||
d.isNegative = true;
|
||||
d.date = aRecurrenceId.clone();
|
||||
|
||||
return this.appendRecurrenceItem(d);
|
||||
},
|
||||
|
||||
restoreOccurrenceAt: function (aRecurrenceId) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (this.mImmutable)
|
||||
throw Components.results.NS_ERROR_OBJECT_IS_IMMUTABLE;
|
||||
|
||||
for (var i = 0; i < this.mRecurrenceItems.length; i++) {
|
||||
if (this.mRecurrenceItems[i] instanceof Components.interfaces.calIRecurrenceDate) {
|
||||
var rd = this.mRecurrenceItems[i].QueryInterface(Components.interfaces.calIRecurrenceDate);
|
||||
if (rd.isNegative && rd.date.compare(aRecurrenceId) == 0) {
|
||||
return this.deleteRecurrenceItemAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
},
|
||||
|
||||
//
|
||||
// exceptions
|
||||
//
|
||||
|
||||
//
|
||||
// Some notes:
|
||||
//
|
||||
// The way I read ICAL, RECURRENCE-ID is used to specify a
|
||||
// particular instance of a recurring event, according to the
|
||||
// RRULEs/RDATEs/etc. specified in the base event. If one of
|
||||
// these is to be changed ("an exception"), then it can be
|
||||
// referenced via the UID of the original event, and a
|
||||
// RECURRENCE-ID of the start time of the instance to change.
|
||||
// This, to me, means that an event where one of the instances has
|
||||
// changed to a different time has a RECURRENCE-ID of the original
|
||||
// start time, and a DTSTART/DTEND representing the new time.
|
||||
//
|
||||
// ITIP, however, seems to want something different -- you're
|
||||
// supposed to use UID/RECURRENCE-ID to select from the current
|
||||
// set of occurrences of an event. If you change the DTSTART for
|
||||
// an instance, you're supposed to use the old (original) DTSTART
|
||||
// as the RECURRENCE-ID, and put the new time as the DTSTART.
|
||||
// However, after that change, to refer to that instance in the
|
||||
// future, you have to use the modified DTSTART as the
|
||||
// RECURRENCE-ID. This madness is described in ITIP end of
|
||||
// section 3.7.1.
|
||||
//
|
||||
// This implementation does the first approach (RECURRENCE-ID will
|
||||
// never change even if DTSTART for that instance changes), which
|
||||
// I think is the right thing to do for CalDAV; I don't know what
|
||||
// we'll do for incoming ITIP events though.
|
||||
//
|
||||
|
||||
mExceptions: null,
|
||||
|
||||
modifyException: function (anItem) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
// the item must be an occurrence
|
||||
if (anItem.parentItem == anItem)
|
||||
throw Components.results.NS_ERROR_UNEXPECTED;
|
||||
|
||||
if (anItem.parentItem.calendar != this.mBaseItem.calendar &&
|
||||
anItem.parentItem.id != this.mBaseItem.id)
|
||||
{
|
||||
calDebug ("recurrenceInfo::addException: item parentItem != this.mBaseItem (calendar/id)!\n");
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (anItem.recurrenceId == null) {
|
||||
calDebug ("recurrenceInfo::addException: item with null recurrenceId!\n");
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
var itemtoadd;
|
||||
if (anItem.isMutable) {
|
||||
itemtoadd = anItem.cloneShallow(this.mBaseItem);
|
||||
itemtoadd.makeImmutable();
|
||||
} else {
|
||||
itemtoadd = anItem;
|
||||
}
|
||||
|
||||
// we're going to assume that the recurrenceId is valid here,
|
||||
// because presumably the item came from one of our functions
|
||||
|
||||
// remove any old one, if present
|
||||
this.removeExceptionFor(anItem.recurrenceId);
|
||||
|
||||
this.mExceptions.push( { id: itemtoadd.recurrenceId, item: itemtoadd } );
|
||||
},
|
||||
|
||||
createExceptionFor: function (aRecurrenceId) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
// XX should it be an error to createExceptionFor
|
||||
// an already-existing recurrenceId?
|
||||
var existing = this.getExceptionFor(aRecurrenceId, false);
|
||||
if (existing)
|
||||
return existing;
|
||||
|
||||
// check if aRecurrenceId is valid.
|
||||
|
||||
// this is a bit of a hack; we know that ranges are defined as [start, end),
|
||||
// so we do a search on aRecurrenceId and aRecurrenceId.seconds + 1.
|
||||
var rangeStart = aRecurrenceId;
|
||||
var rangeEnd = aRecurrenceId.clone();
|
||||
rangeEnd.second += 1;
|
||||
rangeEnd.normalize();
|
||||
|
||||
var dates = this.getOccurrenceDates (rangeStart, rangeEnd, 1, {});
|
||||
var found = false;
|
||||
for each (d in dates) {
|
||||
if (d.compare(aRecurrenceId) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// not found; the recurrence id is invalid
|
||||
if (!found)
|
||||
throw Components.results.NS_ERROR_INVALID_ARG;
|
||||
|
||||
var rid = aRecurrenceId.clone();
|
||||
rid.makeImmutable();
|
||||
|
||||
var newex = this.mBaseItem.createProxy();
|
||||
newex.recurrenceId = rid;
|
||||
|
||||
this.mExceptions.push({id: rid, item: newex});
|
||||
|
||||
return newex;
|
||||
},
|
||||
|
||||
getExceptionFor: function (aRecurrenceId, aCreate) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
for each (ex in this.mExceptions) {
|
||||
if (ex.id.compare(aRecurrenceId) == 0)
|
||||
return ex.item;
|
||||
}
|
||||
|
||||
if (aCreate) {
|
||||
return this.createExceptionFor(aRecurrenceId);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
removeExceptionFor: function (aRecurrenceId) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
this.mExceptions = this.mExceptions.filter (function(ex) {
|
||||
return (ex.id.compare(aRecurrenceId) != 0);
|
||||
});
|
||||
},
|
||||
|
||||
getExceptionIds: function (aCount) {
|
||||
if (!this.mBaseItem)
|
||||
throw Components.results.NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
var ids = this.mExceptions.map (function(ex) {
|
||||
return ex.id;
|
||||
});
|
||||
|
||||
aCount.value = ids.length;
|
||||
return ids;
|
||||
},
|
||||
};
|
@ -50,7 +50,7 @@ extern "C" {
|
||||
#include "ical.h"
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS2(calRecurrenceRule, calIRecurrenceItem, calIRecurrenceRule)
|
||||
NS_IMPL_ISUPPORTS2_CI(calRecurrenceRule, calIRecurrenceItem, calIRecurrenceRule)
|
||||
|
||||
calRecurrenceRule::calRecurrenceRule()
|
||||
: mImmutable(PR_FALSE),
|
||||
@ -85,6 +85,21 @@ calRecurrenceRule::MakeImmutable()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceRule::Clone(calIRecurrenceItem **aResult)
|
||||
{
|
||||
calRecurrenceRule *crc = new calRecurrenceRule;
|
||||
if (!crc)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
crc->mIsNegative = mIsNegative;
|
||||
crc->mIsByCount = mIsByCount;
|
||||
*(crc->mIcalRecur) = *mIcalRecur;
|
||||
|
||||
NS_ADDREF(*aResult = crc);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute boolean isNegative; */
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceRule::GetIsNegative(PRBool *_retval)
|
||||
@ -105,18 +120,19 @@ calRecurrenceRule::SetIsNegative(PRBool aIsNegative)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute boolean isFinite; */
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceRule::Clone(calIRecurrenceItem **aResult)
|
||||
calRecurrenceRule::GetIsFinite(PRBool *_retval)
|
||||
{
|
||||
calRecurrenceRule *crc = new calRecurrenceRule;
|
||||
if (!crc)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
|
||||
crc->mIsNegative = mIsNegative;
|
||||
crc->mIsByCount = mIsByCount;
|
||||
*(crc->mIcalRecur) = *mIcalRecur;
|
||||
|
||||
NS_ADDREF(*aResult = crc);
|
||||
if ((mIsByCount && mIcalRecur->count == 0) ||
|
||||
(!mIsByCount && icaltime_is_null_time(mIcalRecur->until)))
|
||||
{
|
||||
*_retval = PR_FALSE;
|
||||
} else {
|
||||
*_retval = PR_TRUE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -169,6 +185,9 @@ calRecurrenceRule::GetCount(PRInt32 *aRecurCount)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRecurCount);
|
||||
|
||||
if (!mIsByCount)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (mIcalRecur->count == 0 && icaltime_is_null_time(mIcalRecur->until)) {
|
||||
*aRecurCount = -1;
|
||||
} else if (mIcalRecur->count) {
|
||||
@ -203,6 +222,9 @@ calRecurrenceRule::GetEndDate(calIDateTime * *aRecurEnd)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRecurEnd);
|
||||
|
||||
if (mIsByCount)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!icaltime_is_null_time(mIcalRecur->until)) {
|
||||
calDateTime *cdt = new calDateTime(&mIcalRecur->until);
|
||||
if (!cdt)
|
||||
@ -389,7 +411,6 @@ calDateTimeComparator (calIDateTime *aElement1,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* void getOccurrences(in calIDateTime aStartTime, in calIDateTime aEndTime, out unsigned long aCount, [array, size_is (aCount), retval] out calIItemOccurrence aItems); */
|
||||
NS_IMETHODIMP
|
||||
calRecurrenceRule::GetOccurrences(calIDateTime *aStartTime,
|
||||
calIDateTime *aRangeStart,
|
||||
|
@ -47,17 +47,29 @@ function calTodo() {
|
||||
this.wrappedJSObject = this;
|
||||
this.initItemBase();
|
||||
this.initTodo();
|
||||
|
||||
this.todoPromotedProps = {
|
||||
"DTSTART": true,
|
||||
"DTEND": true,
|
||||
"DTSTAMP": true,
|
||||
"DUE": true,
|
||||
"COMPLETED": true,
|
||||
"PERCENT-COMPLETE": true,
|
||||
__proto__: this.itemBasePromotedProps
|
||||
};
|
||||
}
|
||||
|
||||
// var trickery to suppress lib-as-component errors from loader
|
||||
var calItemBase;
|
||||
|
||||
calTodoClassInfo = {
|
||||
var calTodoClassInfo = {
|
||||
getInterfaces: function (count) {
|
||||
var ifaces = [
|
||||
Components.interfaces.nsISupports,
|
||||
Components.interfaces.calIItemBase,
|
||||
Components.interfaces.calITodo
|
||||
Components.interfaces.calITodo,
|
||||
Components.interfaces.calIInternalShallowCopy,
|
||||
Components.interfaces.nsIClassInfo
|
||||
];
|
||||
count.value = ifaces.length;
|
||||
return ifaces;
|
||||
@ -78,7 +90,8 @@ calTodo.prototype = {
|
||||
__proto__: calItemBase ? (new calItemBase()) : {},
|
||||
|
||||
QueryInterface: function (aIID) {
|
||||
if (aIID.equals(Components.interfaces.calITodo))
|
||||
if (aIID.equals(Components.interfaces.calITodo) ||
|
||||
aIID.equals(Components.interfaces.calIInternalShallowCopy))
|
||||
return this;
|
||||
|
||||
if (aIID.equals(Components.interfaces.nsIClassInfo))
|
||||
@ -94,13 +107,32 @@ calTodo.prototype = {
|
||||
this.mPercentComplete = 0;
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
cloneShallow: function (aNewParent) {
|
||||
var m = new calTodo();
|
||||
this.cloneItemBaseInto(m);
|
||||
this.cloneItemBaseInto(m, aNewParent);
|
||||
m.mEntryDate = this.mEntryDate.clone();
|
||||
m.mDueDate = this.mDueDate.clone();
|
||||
m.mCompletedDate = this.mCompletedDate.clone();
|
||||
m.mPercentComplete = this.mPercentComplete;
|
||||
return m;
|
||||
},
|
||||
|
||||
clone: function () {
|
||||
var m;
|
||||
|
||||
if (this.parentItem != this) {
|
||||
var clonedParent = this.mParentItem.clone();
|
||||
m = clonedParent.recurrenceInfo.getExceptionFor (this.recurrenceId, true);
|
||||
} else {
|
||||
m = this.cloneShallow(null);
|
||||
}
|
||||
|
||||
return m;
|
||||
},
|
||||
|
||||
createProxy: function () {
|
||||
var m = new calTodo();
|
||||
m.initializeProxy(this);
|
||||
|
||||
return m;
|
||||
},
|
||||
@ -165,6 +197,8 @@ calTodo.prototype = {
|
||||
return icalcomp;
|
||||
},
|
||||
|
||||
todoPromotedProps: null,
|
||||
|
||||
set icalComponent(todo) {
|
||||
this.modify();
|
||||
if (todo.componentType != "VTODO") {
|
||||
@ -177,19 +211,14 @@ calTodo.prototype = {
|
||||
this.mapPropsFromICS(todo, this.icsEventPropMap);
|
||||
this.mIsAllDay = this.mStartDate && this.mStartDate.isDate;
|
||||
|
||||
var promotedProps = {
|
||||
"DTSTART": true,
|
||||
"DTEND": true,
|
||||
"DTSTAMP": true,
|
||||
"DUE": true,
|
||||
"COMPLETED": true,
|
||||
"PERCENT-COMPLETE": true,
|
||||
__proto__: this.itemBasePromotedProps
|
||||
};
|
||||
this.importUnpromotedProperties(todo, promotedProps);
|
||||
this.importUnpromotedProperties(todo, todoPromotedProps);
|
||||
// Importing didn't really change anything
|
||||
this.mDirty = false;
|
||||
},
|
||||
|
||||
isPropertyPromoted: function (name) {
|
||||
return (this.todoPromotedProps[name]);
|
||||
},
|
||||
};
|
||||
|
||||
// var decl to prevent spurious error messages when loaded as component
|
||||
|
@ -94,7 +94,7 @@ function rebuildAgendaView(invalidate)
|
||||
if (e instanceof Synthetic)
|
||||
dump(" " + e.title + "\n");
|
||||
else
|
||||
dump(" " + e.item.title + " @ " + e.occurrenceStartDate + "\n");
|
||||
dump(" " + e.title + " @ " + e.occurrenceStartDate + "\n");
|
||||
});
|
||||
*/
|
||||
this.forceTreeRebuild();
|
||||
@ -143,12 +143,13 @@ function getCellText(row, column)
|
||||
if (column.id == "col-agenda-item") {
|
||||
if (event instanceof Synthetic)
|
||||
return event.title;
|
||||
return event.item.title;
|
||||
return event.title;
|
||||
}
|
||||
|
||||
if (event instanceof Synthetic)
|
||||
return "";
|
||||
return event.occurrenceStartDate.toString();
|
||||
var start = event.startDate || event.entryDate;
|
||||
return start.toString();
|
||||
};
|
||||
|
||||
agendaTreeView.getLevel =
|
||||
@ -223,10 +224,7 @@ function hasNextSibling(row, afterIndex)
|
||||
agendaTreeView.findPeriodForItem =
|
||||
function findPeriodForItem(item)
|
||||
{
|
||||
var start = item.occurrenceStartDate;
|
||||
if (start.compare(this.today.start) < 0 || start.compare(this.soon.end) > 0)
|
||||
return null;
|
||||
|
||||
var start = item.startDate || item.entryDate;
|
||||
if (start.compare(this.today.end) <= 0)
|
||||
return this.today;
|
||||
|
||||
@ -236,7 +234,7 @@ function findPeriodForItem(item)
|
||||
if (start.compare(this.soon.end) <= 0)
|
||||
return this.soon;
|
||||
|
||||
void(item.item.title + " @ " + start + " not in range " +
|
||||
void(item.title + " @ " + start + " not in range " +
|
||||
"(" + this.today.start + " - " + this.soon.end + ")\n");
|
||||
|
||||
return null;
|
||||
@ -248,7 +246,7 @@ function addItem(item)
|
||||
var when = this.findPeriodForItem(item);
|
||||
if (!when)
|
||||
return;
|
||||
void(item.item.title + " @ " + item.occurrenceStartDate + " -> " + when.title + "\n");
|
||||
void(item.title + " @ " + item.occurrenceStartDate + " -> " + when.title + "\n");
|
||||
when.events.push(item);
|
||||
this.calendarUpdateComplete();
|
||||
};
|
||||
@ -263,11 +261,16 @@ function deleteItem(item)
|
||||
}
|
||||
|
||||
void("deleting item " + item + " from " + when.title + "\n");
|
||||
void("before: " + when.events.map(function (e) { return e.item.title; }).join(" ") + "\n");
|
||||
void("before: " + when.events.map(function (e) { return e.title; }).join(" ") + "\n");
|
||||
when.events = when.events.filter(function (e) {
|
||||
return !e.equals(item);
|
||||
});
|
||||
void("after: " + when.events.map(function (e) { return e.item.title; }).join(" ") + "\n");
|
||||
if (e.id != item.id)
|
||||
return true;
|
||||
if (e.recurrenceId && item.recurrenceId &&
|
||||
e.recurrenceId.compare(item.recurrenceId) != 0)
|
||||
return true;
|
||||
return false;
|
||||
});
|
||||
void("after: " + when.events.map(function (e) { return e.title; }).join(" ") + "\n");
|
||||
this.rebuildAgendaView(true);
|
||||
};
|
||||
|
||||
@ -276,7 +279,9 @@ function calendarUpdateComplete()
|
||||
{
|
||||
[this.today, this.tomorrow, this.soon].forEach(function(when) {
|
||||
function compare(a, b) {
|
||||
return a.occurrenceStartDate.compare(b.occurrenceStartDate);
|
||||
var ad = a.startDate || a.entryDate;
|
||||
var bd = b.startDate || b.entryDate;
|
||||
return ad.compare(bd);
|
||||
}
|
||||
when.events.sort(compare);
|
||||
});
|
||||
|
@ -113,29 +113,28 @@ var ltnCalendarViewController = {
|
||||
},
|
||||
|
||||
modifyOccurrence: function (aOccurrence, aNewStartTime, aNewEndTime) {
|
||||
if (aOccurrence.recurrenceInfo) {
|
||||
dump ("*** Don't know what to do in modifyOccurrence for a recurring event!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// if we can modify this thing directly (e.g. just the time changed),
|
||||
// then do so; otherwise pop up the dialog
|
||||
if (aNewStartTime && aNewEndTime && !aNewStartTime.isDate && !aNewEndTime.isDate) {
|
||||
var newEvent = aOccurrence.item.clone();
|
||||
newEvent.startDate = aNewStartTime;
|
||||
newEvent.endDate = aNewEndTime;
|
||||
newEvent.calendar.modifyItem(newEvent, aOccurrence.item, null);
|
||||
var instance = aOccurrence.clone();
|
||||
|
||||
instance.startDate = aNewStartTime;
|
||||
instance.endDate = aNewEndTime;
|
||||
|
||||
instance.calendar.modifyItem(instance, aOccurrence, null);
|
||||
} else {
|
||||
modifyEventWithDialog(aOccurrence.item);
|
||||
modifyEventWithDialog(aOccurrence);
|
||||
}
|
||||
},
|
||||
|
||||
deleteOccurrence: function (aOccurrence) {
|
||||
dump ("+++ deleteOccurrence\n");
|
||||
if (aOccurrence.recurrenceInfo) {
|
||||
dump ("*** Don't know what do in deleteOccurrence for a recurring event!\n");
|
||||
return;
|
||||
if (aOccurrence.parentItem) {
|
||||
var event = aOccurrence.parentItem.clone();
|
||||
event.recurrenceInfo.removeOccurrenceAt(aOccurrence.recurrenceId);
|
||||
event.calendar.modifyItem(event, aOccurrence, null);
|
||||
} else {
|
||||
aOccurrence.calendar.deleteItem(aOccurrence, null);
|
||||
}
|
||||
|
||||
aOccurrence.item.calendar.deleteItem(aOccurrence.item, null);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2,13 +2,33 @@
|
||||
function ltnCreateInstance(cid, iface) {
|
||||
if (!iface)
|
||||
iface = "nsISupports";
|
||||
return Components.classes[cid].createInstance(Components.interfaces[iface]);
|
||||
try {
|
||||
return Components.classes[cid].createInstance(Components.interfaces[iface]);
|
||||
} catch(e) {
|
||||
dump("#### ltnCreateInstance failed for: " + cid + "\n");
|
||||
var frame = Components.stack;
|
||||
for (var i = 0; frame && (i < 4); i++) {
|
||||
dump(i + ": " + frame + "\n");
|
||||
frame = frame.caller;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function ltnGetService(cid, iface) {
|
||||
if (!iface)
|
||||
iface = "nsISupports";
|
||||
return Components.classes[cid].getService(Components.interfaces[iface]);
|
||||
try {
|
||||
return Components.classes[cid].getService(Components.interfaces[iface]);
|
||||
} catch(e) {
|
||||
dump("#### ltnGetService failed for: " + cid + "\n");
|
||||
var frame = Components.stack;
|
||||
for (var i = 0; frame && (i < 4); i++) {
|
||||
dump(i + ": " + frame + "\n");
|
||||
frame = frame.caller;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
var atomSvc;
|
||||
|
@ -86,7 +86,6 @@ function showCalendar(jumpToToday)
|
||||
var d = Components.classes['@mozilla.org/calendar/datetime;1'].createInstance(Components.interfaces.calIDateTime);
|
||||
d.jsDate = new Date();
|
||||
d = d.getInTimezone(calendarDefaultTimezone());
|
||||
|
||||
view.showDate(d);
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,8 @@
|
||||
|
||||
<vbox flex="1">
|
||||
<hbox>
|
||||
<minimonth id="ltnMinimonthLeft" onchange="ltnMinimonthPick('left', this);"/>
|
||||
<minimonth id="ltnMinimonthRight" onchange="ltnMinimonthPick('right', this);"/>
|
||||
<minimonth id="ltnMinimonthLeft" onchange="ltnMinimonthPick('left', this);" flex="1"/>
|
||||
<minimonth id="ltnMinimonthRight" onchange="ltnMinimonthPick('right', this);" flex="1"/>
|
||||
</hbox>
|
||||
|
||||
<tabbox flex="1">
|
||||
|
@ -61,12 +61,10 @@ function calMemoryCalendar() {
|
||||
|
||||
function makeOccurrence(item, start, end)
|
||||
{
|
||||
var occ = Components.classes["@mozilla.org/calendar/item-occurrence;1"].
|
||||
createInstance(Components.interfaces.calIItemOccurrence);
|
||||
// XXX poor form
|
||||
occ.wrappedJSObject.item = item;
|
||||
occ.wrappedJSObject.occurrenceStartDate = start;
|
||||
occ.wrappedJSObject.occurrenceEndDate = end;
|
||||
var occ = item.createProxy();
|
||||
occ.recurrenceId = start;
|
||||
occ.startDate = start;
|
||||
occ.endDate = end;
|
||||
return occ;
|
||||
}
|
||||
|
||||
@ -122,21 +120,15 @@ calMemoryCalendar.prototype = {
|
||||
|
||||
// void addObserver( in calIObserver observer );
|
||||
addObserver: function (aObserver, aItemFilter) {
|
||||
for each (obs in this.mObservers) {
|
||||
if (obs == aObserver)
|
||||
return;
|
||||
}
|
||||
if (this.mObservers.any(function(o) { return (o == aObserver); }))
|
||||
return;
|
||||
|
||||
this.mObservers.push(aObserver);
|
||||
},
|
||||
|
||||
// void removeObserver( in calIObserver observer );
|
||||
removeObserver: function (aObserver) {
|
||||
var newObservers = Array();
|
||||
for each (obs in this.mObservers) {
|
||||
if (obs != aObserver)
|
||||
newObservers.push(obs);
|
||||
}
|
||||
var newObservers = this.mObservers.filter(function(o) { return (o != aObserver); });
|
||||
this.mObservers = newObservers;
|
||||
},
|
||||
|
||||
@ -243,7 +235,7 @@ calMemoryCalendar.prototype = {
|
||||
modifiedItem.id,
|
||||
modifiedItem);
|
||||
// notify observers
|
||||
this.observeModifyItem(aOldItem, modifiedItem);
|
||||
this.observeModifyItem(modifiedItem, aOldItem);
|
||||
},
|
||||
|
||||
// void deleteItem( in calIItemBase aItem, in calIOperationListener aListener );
|
||||
@ -376,7 +368,7 @@ calMemoryCalendar.prototype = {
|
||||
// figure out the return interface type
|
||||
var typeIID = null;
|
||||
if (itemReturnOccurrences) {
|
||||
typeIID = calIItemOccurrence;
|
||||
typeIID = calIItemBase;
|
||||
} else {
|
||||
if (wantEvents && wantTodos) {
|
||||
typeIID = calIItemBase;
|
||||
@ -425,9 +417,7 @@ calMemoryCalendar.prototype = {
|
||||
{
|
||||
// there might be some recurrences here that we need to handle
|
||||
var recs = item.recurrenceInfo.getOccurrences (aRangeStart, aRangeEnd, 0, {});
|
||||
for (var i = 0; i < recs.length; i++) {
|
||||
itemsFound.push(recs[i]);
|
||||
}
|
||||
itemsFound = concat(itemsFound, recs);
|
||||
} else if (itemEndTime >= startTime) {
|
||||
// no occurrences
|
||||
if (itemReturnOccurrences)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,97 +0,0 @@
|
||||
|
||||
CREATE TABLE cal_calendar_schema_version (
|
||||
version INTEGER
|
||||
);
|
||||
|
||||
CREATE TABLE cal_items (
|
||||
cal_id INTEGER, -- REFERENCES cal_calendars.id,
|
||||
-- 0: event, 1: todo
|
||||
item_type INTEGER,
|
||||
|
||||
-- ItemBase bits
|
||||
id STRING,
|
||||
time_created INTEGER,
|
||||
last_modified INTEGER,
|
||||
title STRING,
|
||||
priority INTEGER,
|
||||
privacy STRING,
|
||||
|
||||
ical_status STRING,
|
||||
|
||||
-- CAL_ITEM_FLAG_PRIVATE = 1
|
||||
-- CAL_ITEM_FLAG_HAS_ATTENDEES = 2
|
||||
-- CAL_ITEM_FLAG_HAS_PROPERTIES = 4
|
||||
-- CAL_ITEM_FLAG_EVENT_ALLDAY = 8
|
||||
-- CAL_ITEM_FLAG_HAS_RECURRENCE = 16
|
||||
flags INTEGER,
|
||||
|
||||
-- Event bits
|
||||
event_start INTEGER,
|
||||
event_end INTEGER,
|
||||
event_stamp INTEGER,
|
||||
|
||||
-- Todo bits
|
||||
todo_entry INTEGER,
|
||||
todo_due INTEGER,
|
||||
todo_completed INTEGER,
|
||||
todo_complete INTEGER,
|
||||
|
||||
-- internal bits
|
||||
alarm_id INTEGER -- REFERENCES cal_alarms.id ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE cal_attendees (
|
||||
item_id STRING,
|
||||
attendee_id STRING,
|
||||
common_name STRING,
|
||||
rsvp INTEGER,
|
||||
role STRING,
|
||||
status STRING,
|
||||
type STRING
|
||||
);
|
||||
|
||||
CREATE TABLE cal_alarms (
|
||||
id INTEGER PRIMARY KEY,
|
||||
|
||||
alarm_data BLOB
|
||||
);
|
||||
|
||||
CREATE TABLE cal_recurrence (
|
||||
item_id STRING,
|
||||
recur_index INTEGER, -- the index in the recurrence array of this thing
|
||||
recur_type STRING, -- values from calIRecurrenceInfo; if null, date-based.
|
||||
|
||||
is_negative BOOLEAN,
|
||||
|
||||
--
|
||||
-- these are for date-based recurrence
|
||||
--
|
||||
|
||||
-- comma-separated list of dates
|
||||
dates STRING,
|
||||
|
||||
--
|
||||
-- these are for rule-based recurrence
|
||||
--
|
||||
count INTEGER,
|
||||
end_date INTEGER,
|
||||
interval INTEGER,
|
||||
|
||||
-- components, comma-separated list or null
|
||||
second STRING,
|
||||
minute STRING,
|
||||
hour STRING,
|
||||
day STRING,
|
||||
monthday STRING,
|
||||
yearday STRING,
|
||||
weekno STRING,
|
||||
month STRING,
|
||||
setpos STRING
|
||||
);
|
||||
|
||||
CREATE TABLE cal_properties (
|
||||
item_id STRING,
|
||||
|
||||
key STRING,
|
||||
value BLOB
|
||||
);
|
@ -263,7 +263,7 @@
|
||||
this.mEditorDate = aDate;
|
||||
|
||||
if (this.mSelected) {
|
||||
this.mSelected.setAttribute("selected", "");
|
||||
this.mSelected.removeAttribute("selected");
|
||||
this.mSelected = null;
|
||||
}
|
||||
|
||||
@ -308,7 +308,7 @@
|
||||
if (aDate.getMonth() != date.getMonth()) {
|
||||
day.setAttribute("othermonth", "true");
|
||||
} else {
|
||||
day.setAttribute("othermonth", "");
|
||||
day.removeAttribute("othermonth");
|
||||
}
|
||||
|
||||
// highlight the current date
|
||||
@ -438,7 +438,7 @@
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (this.mSelected) {
|
||||
this.mSelected.setAttribute("selected", "");
|
||||
this.mSelected.removeAttribute("selected");
|
||||
}
|
||||
this.mSelected = aDay;
|
||||
aDay.setAttribute("selected", "true");
|
||||
|
@ -227,7 +227,7 @@ function loadCalendarEventDialog()
|
||||
|
||||
|
||||
// ALARMS ------------------------------------------------------------
|
||||
if (!event.hasAlarm) {
|
||||
if (event.alarmTime == null) {
|
||||
menuListSelectItem("alarm-type", "none");
|
||||
} else {
|
||||
setElementValue("alarm-length-field", event.getProperty("alarmLength"));
|
||||
@ -558,8 +558,6 @@ function onOKCommand()
|
||||
// ALARMS ------------------------------------------------------------
|
||||
var alarmType = getElementValue("alarm-type");
|
||||
if (alarmType != "" && alarmType != "none") {
|
||||
event.hasAlarm = true;
|
||||
|
||||
var alarmLength = getElementValue("alarm-length-field");
|
||||
var alarmUnits = getElementValue("alarm-length-units");
|
||||
var alarmRelated = getElementValue("alarm-trigger-relation");
|
||||
|
@ -263,6 +263,8 @@ mozStorageStatement::Reset()
|
||||
PR_LOG(gStorageLog, PR_LOG_DEBUG, ("Resetting statement: '%s'", nsPromiseFlatCString(mStatementString).get()));
|
||||
|
||||
sqlite3_reset(mDBStatement);
|
||||
sqlite3_clear_bindings(mDBStatement);
|
||||
|
||||
mExecuting = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
|
@ -315,7 +315,7 @@ mozStorageStatementWrapper::Call(nsIXPConnectWrappedNative *wrapper, JSContext *
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (!JSValStorageStatementBinder(cx, mStatement, &i, 1, argv[i])) {
|
||||
*_retval = PR_FALSE;
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
@ -522,7 +522,7 @@ mozStorageStatementRow::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContex
|
||||
double dval = sqlite3_column_double(NativeStatement(), i);
|
||||
if (!JS_NewNumberValue(cx, dval, vp)) {
|
||||
*_retval = PR_FALSE;
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else if (ctype == SQLITE_TEXT) {
|
||||
JSString *str = JS_NewUCStringCopyN(cx,
|
||||
@ -530,7 +530,7 @@ mozStorageStatementRow::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContex
|
||||
sqlite3_column_bytes16(NativeStatement(), i)/2);
|
||||
if (!str) {
|
||||
*_retval = PR_FALSE;
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
*vp = STRING_TO_JSVAL(str);
|
||||
} else if (ctype == SQLITE_BLOB) {
|
||||
@ -539,7 +539,7 @@ mozStorageStatementRow::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContex
|
||||
sqlite3_column_bytes(NativeStatement(), i));
|
||||
if (!str) {
|
||||
*_retval = PR_FALSE;
|
||||
return NS_OK;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
} else if (ctype == SQLITE_NULL) {
|
||||
*vp = JSVAL_NULL;
|
||||
@ -788,10 +788,12 @@ mozStorageStatementParams::SetProperty(nsIXPConnectWrappedNative *wrapper, JSCon
|
||||
}
|
||||
} else {
|
||||
*_retval = PR_FALSE;
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
if (*_retval)
|
||||
return NS_OK;
|
||||
else
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* void preCreate (in nsISupports nativeObj, in JSContextPtr cx, in JSObjectPtr globalObj, out JSObjectPtr parentObj); */
|
||||
|
Loading…
Reference in New Issue
Block a user