1 /* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 *
15 * The Original Code is Oracle Corporation code.
16 *
17 * The Initial Developer of the Original Code is
18 * Oracle Corporation
19 * Portions created by the Initial Developer are Copyright (C) 2004
20 * the Initial Developer. All Rights Reserved.
21 *
22 * Contributor(s):
23 * Vladimir Vukicevic <vladimir.vukicevic@oracle.com>
24 * Mike Shaver <shaver@off.net>
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40 //
41 // calEvent.js
42 //
43
44 //
45 // constructor
46 //
calEvent
47 function calEvent() {
48 this.wrappedJSObject = this;
49 this.initItemBase();
50
51 this.eventPromotedProps = {
52 "DTSTART": true,
53 "DTEND": true,
54 "DTSTAMP": true,
55 __proto__: this.itemBasePromotedProps
56 }
57 }
58
59 // var trickery to suppress lib-as-component errors from loader
60 var calItemBase;
61
62 var calEventClassInfo = {
getInterfaces
63 getInterfaces: function (count) {
64 var ifaces = [
65 Components.interfaces.nsISupports,
66 Components.interfaces.calIItemBase,
67 Components.interfaces.calIEvent,
68 Components.interfaces.calIInternalShallowCopy,
69 Components.interfaces.nsIClassInfo
70 ];
71 count.value = ifaces.length;
72 return ifaces;
73 },
74
getHelperForLanguage
75 getHelperForLanguage: function (language) {
76 return null;
77 },
78
79 contractID: "@mozilla.org/calendar/event;1",
80 classDescription: "Calendar Event",
81 classID: Components.ID("{974339d5-ab86-4491-aaaf-2b2ca177c12b}"),
82 implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
83 flags: 0
84 };
85
86 calEvent.prototype = {
87 __proto__: calItemBase.prototype,
88
QueryInterface
89 QueryInterface: function (aIID) {
90 if (aIID.equals(Components.interfaces.calIEvent) ||
91 aIID.equals(Components.interfaces.calIInternalShallowCopy))
92 return this;
93
94 if (aIID.equals(Components.interfaces.nsIClassInfo))
95 return calEventClassInfo;
96
97 return this.__proto__.__proto__.QueryInterface.call(this, aIID);
98 },
99
cloneShallow
100 cloneShallow: function (aNewParent) {
101 var m = new calEvent();
102 this.cloneItemBaseInto(m, aNewParent);
103
104 return m;
105 },
106
clone
107 clone: function () {
108 var m;
109
110 if (this.mParentItem) {
111 var clonedParent = this.mParentItem.clone();
112 m = clonedParent.recurrenceInfo.getOccurrenceFor (this.recurrenceId);
113 } else {
114 m = this.cloneShallow(null);
115 }
116
117 return m;
118 },
119
createProxy
120 createProxy: function () {
121 if (this.mIsProxy) {
122 calDebug("Tried to create a proxy for an existing proxy!\n");
123 throw Components.results.NS_ERROR_UNEXPECTED;
124 }
125
126 var m = new calEvent();
127 m.initializeProxy(this);
128
129 return m;
130 },
131
makeImmutable
132 makeImmutable: function () {
133 this.makeItemBaseImmutable();
134 },
135
get_duration
136 get duration() {
137 return this.endDate.subtractDate(this.startDate);
138 },
139
get_recurrenceStartDate
140 get recurrenceStartDate() {
141 return this.startDate;
142 },
143
144 icsEventPropMap: [
145 { cal: "DTSTART", ics: "startTime" },
146 { cal: "DTEND", ics: "endTime" }],
147
set_icalString
148 set icalString(value) {
149 this.icalComponent = icalFromString(value);
150 },
151
get_icalString
152 get icalString() {
153 var calcomp = getIcsService().createIcalComponent("VCALENDAR");
154 calSetProdidVersion(calcomp);
155 if (this.hasProperty("METHOD")) {
156 calcomp.method = this.getProperty("METHOD");
157 }
158 calcomp.addSubcomponent(this.icalComponent);
159 return calcomp.serializeToICS();
160 },
161
get_icalComponent
162 get icalComponent() {
163 var icssvc = getIcsService();
164 var icalcomp = icssvc.createIcalComponent("VEVENT");
165 this.fillIcalComponentFromBase(icalcomp);
166 this.mapPropsToICS(icalcomp, this.icsEventPropMap);
167
168 var bagenum = this.mProperties.enumerator;
169 while (bagenum.hasMoreElements()) {
170 var iprop = bagenum.getNext().
171 QueryInterface(Components.interfaces.nsIProperty);
172 try {
173 if (!this.eventPromotedProps[iprop.name]) {
174 var icalprop = icssvc.createIcalProperty(iprop.name);
175 icalprop.value = iprop.value;
176 var propBucket = this.mPropertyParams[iprop.name];
177 if (propBucket) {
178 for (paramName in propBucket) {
179 icalprop.setParameter(paramName,
180 propBucket[paramName]);
181 }
182 }
183 icalcomp.addProperty(icalprop);
184 }
185 } catch (e) {
186 dump("XXX failed to set " + iprop.name + " to " + iprop.value +
187 ": " + e + "\n");
188 }
189 }
190 return icalcomp;
191 },
192
193 eventPromotedProps: null,
194
set_icalComponent
195 set icalComponent(event) {
196 this.modify();
197 if (event.componentType != "VEVENT") {
198 event = event.getFirstSubcomponent("VEVENT");
199 if (!event)
200 throw Components.results.NS_ERROR_INVALID_ARG;
201 }
202
203 this.setItemBaseFromICS(event);
204 this.mapPropsFromICS(event, this.icsEventPropMap);
205
206 this.importUnpromotedProperties(event, this.eventPromotedProps);
207
208 // Importing didn't really change anything
209 this.mDirty = false;
210 },
211
isPropertyPromoted
212 isPropertyPromoted: function (name) {
213 return (this.eventPromotedProps[name]);
214 },
215
getOccurrencesBetween
216 getOccurrencesBetween: function(aStartDate, aEndDate, aCount) {
217 if (this.recurrenceInfo) {
218 return this.recurrenceInfo.getOccurrences(aStartDate, aEndDate, 0, aCount);
219 }
220
221 if (checkIfInRange(this, aStartDate, aEndDate)) {
222 aCount.value = 1;
223 return [this];
224 }
225
226 aCount.value = 0;
227 return [];
228 },
229
set_startDate
230 set startDate(value) {
231 this.modify();
232
233 // We're about to change the start date of an item which probably
234 // could break the associated calIRecurrenceInfo. We're calling
235 // the appropriate method here to adjust the internal structure in
236 // order to free clients from worrying about such details.
237 if (this.parentItem == this) {
238 var rec = this.recurrenceInfo;
239 if (rec) {
240 rec.onStartDateChange(value,this.startDate);
241 }
242 }
243
244 this.setProperty("DTSTART", value);
245 },
246
get_startDate
247 get startDate() {
248 return this.getProperty("DTSTART");
249 },
250
251 mEndDate: undefined,
get_endDate
252 get endDate() {
253 var endDate = this.mEndDate;
254 if (endDate === undefined) {
255 endDate = this.getProperty("DTEND");
256 if (!endDate) {
257 endDate = this.startDate.clone();
258 var dur = this.getProperty("DURATION");
259 if (dur) {
260 // If there is a duration set on the event, calculate the right end time.
261 var icalDur = Components.classes["@mozilla.org/calendar/duration;1"]
262 .createInstance(Components.interfaces.calIDuration);
263 icalDur.icalString = dur;
264 endDate.addDuration(icalDur);
265 } else {
266 // If the start time is a date-time the event ends on the same calendar
267 // date and time of day. If the start time is a date the events
268 // non-inclusive end is the end of the calendar date.
269 if (endDate.isDate) {
270 endDate.day += 1;
271 }
272 }
273 }
274 this.mEndDate = endDate;
275 }
276 return endDate;
277 },
278
set_endDate
279 set endDate(value) {
280 this.deleteProperty("DURATION"); // setting endDate once removes DURATION
281 this.setProperty("DTEND", value);
282 return (this.mEndDate = value);
283 }
284 };