|
1 /* |
|
2 * Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Storage class for day and week views. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // INCLUDES |
|
20 #include "calendayinfo.h" |
|
21 #include "calenagendautils.h" |
|
22 #include "calenconstants.h" |
|
23 #include "calendateutils.h" |
|
24 |
|
25 namespace |
|
26 { |
|
27 const int KUntimedDefaultSlot(16); |
|
28 } |
|
29 |
|
30 /*! |
|
31 \brief CalenDayInfo::CalenDayInfo |
|
32 */ |
|
33 CalenDayInfo::CalenDayInfo(TSlotsInHour aSlotsInHour) : |
|
34 iFirstUntimedSlot(KUntimedDefaultSlot), iSlotsInHour(aSlotsInHour) |
|
35 { |
|
36 iSelectedSlot = KFSCalStartingHour * iSlotsInHour; |
|
37 iSelectedRegion = KErrNotFound; |
|
38 iSelectedColumn = 0; |
|
39 iSelectedAlldayEvent = KErrNotFound; |
|
40 iEarliestEndSlot = KErrNotFound; |
|
41 iLastStartSlot = KErrNotFound; |
|
42 } |
|
43 |
|
44 /*! |
|
45 \brief Destructor |
|
46 */ |
|
47 CalenDayInfo::~CalenDayInfo() |
|
48 { |
|
49 for (int i = 0; i < iRegionList.count(); i++) { |
|
50 iRegionList[i].Close(); |
|
51 } |
|
52 iRegionList.clear(); |
|
53 iUntimedEvents.clear();//Close(); |
|
54 iTodoEvents.clear();//Close(); |
|
55 iAlldayEvents.clear();//Close(); |
|
56 } |
|
57 |
|
58 /*! |
|
59 \brief CalenDayInfo::Reset |
|
60 */ |
|
61 void CalenDayInfo::Reset() |
|
62 { |
|
63 for (int i = 0; i < iRegionList.count(); i++) { |
|
64 iRegionList[i].Close(); |
|
65 } |
|
66 iRegionList.clear();//Reset(); |
|
67 iUntimedEvents.clear();//Reset(); |
|
68 iTodoEvents.clear();//Reset(); |
|
69 iAlldayEvents.clear();//Reset(); |
|
70 |
|
71 iUntimedSlotCount = 0; |
|
72 iFirstUntimedSlot = KFSCalStartingHour * iSlotsInHour; |
|
73 |
|
74 iSelectedSlot = KFSCalStartingHour * iSlotsInHour; |
|
75 iSelectedRegion = KErrNotFound; |
|
76 iSelectedColumn = 0; |
|
77 iSelectedAlldayEvent = KErrNotFound; |
|
78 iEarliestEndSlot = KErrNotFound; |
|
79 iLastStartSlot = KErrNotFound; |
|
80 } |
|
81 |
|
82 /*! |
|
83 \brief CalenDayInfo::InsertTimedEvent |
|
84 */ |
|
85 void CalenDayInfo::InsertTimedEvent(const SCalenApptInfo& aItemInfo) |
|
86 { |
|
87 |
|
88 int startIndex = SlotIndexForStartTime(aItemInfo.iStartTime); |
|
89 int endIndex = SlotIndexForEndTime(aItemInfo.iEndTime); |
|
90 if (endIndex == startIndex) { |
|
91 endIndex++; |
|
92 } |
|
93 if (iRegionList.count() > 0) { |
|
94 // the timed events must be added in order |
|
95 ASSERT( startIndex >= iLastStartSlot ); |
|
96 } |
|
97 |
|
98 CalenTimedEventInfo info; |
|
99 info.iStartSlot = startIndex; |
|
100 info.iEndSlot = endIndex; |
|
101 info.iId = aItemInfo.iId; |
|
102 info.iStatus = aItemInfo.iStatus; |
|
103 // info.iReplicationStatus = aItemInfo.iReplicationStatus; |
|
104 iLastStartSlot = startIndex; |
|
105 if (iEarliestEndSlot == KErrNotFound || endIndex < iEarliestEndSlot) { |
|
106 iEarliestEndSlot = endIndex; |
|
107 } |
|
108 |
|
109 bool added(false); |
|
110 if (iRegionList.count() > 0) { |
|
111 // Since events are added in order, the event either overlaps the |
|
112 // last region or doesn't overlap any region at all |
|
113 CalenTimeRegion& region = iRegionList[iRegionList.count() - 1]; |
|
114 if (region.Overlaps(info)) { |
|
115 region.AddEvent(info); |
|
116 added = true; |
|
117 } |
|
118 } |
|
119 |
|
120 if (!added) { |
|
121 // If it didn't overlap the last region, add a new region for this event. |
|
122 iRegionList.append(CalenTimeRegion()); |
|
123 CalenTimeRegion& region = iRegionList[iRegionList.count() - 1]; |
|
124 region.AddEvent(info); |
|
125 |
|
126 // Do rounding of the region ends |
|
127 if (iRegionList.count() >= 2) { |
|
128 // Check if the previous region end time can be rounded down |
|
129 CalenTimeRegion& prevRegion = iRegionList[iRegionList.count() - 2]; |
|
130 int end = RoundHourDown(prevRegion.iEndSlot); |
|
131 if (end <= region.iStartSlot) { |
|
132 prevRegion.iEndSlot = end; |
|
133 } |
|
134 // Check if the start time of the new region can be rounded up |
|
135 int start = RoundHourUp(region.iStartSlot); |
|
136 if (start >= prevRegion.iEndSlot) { |
|
137 region.iStartSlot = start; |
|
138 } |
|
139 } |
|
140 else { |
|
141 // No previous region, round the start time up |
|
142 region.iStartSlot = RoundHourUp(region.iStartSlot); |
|
143 } |
|
144 } |
|
145 } |
|
146 |
|
147 /*! |
|
148 \brief CalenDayInfo::InsertAlldayEvent |
|
149 */ |
|
150 void CalenDayInfo::InsertAlldayEvent(const SCalenApptInfo& aItemInfo) |
|
151 { |
|
152 CalenTimedEventInfo info; |
|
153 info.iStartSlot = 0; |
|
154 info.iEndSlot = iSlotsInHour * KCalenHoursInDay + iUntimedSlotCount; |
|
155 info.iId = aItemInfo.iId; |
|
156 info.iStatus = aItemInfo.iStatus; |
|
157 // info.iReplicationStatus = aItemInfo.iReplicationStatus; |
|
158 |
|
159 iAlldayEvents.append(info); |
|
160 } |
|
161 |
|
162 /*! |
|
163 \brief CalenDayInfo::IsAllDayEvent |
|
164 */ |
|
165 bool CalenDayInfo::IsAlldayEvent(QDateTime aStart, QDateTime aEnd) |
|
166 { |
|
167 bool isAllDay(false); |
|
168 |
|
169 if (!CalenDateUtils::onSameDay(aStart, aEnd)) { |
|
170 QDateTime startMidnight = CalenDateUtils::beginningOfDay(aStart); |
|
171 QDateTime endMidnight = CalenDateUtils::beginningOfDay(aEnd); |
|
172 |
|
173 if ((aStart == startMidnight) && (aEnd == endMidnight)) { |
|
174 isAllDay = true; |
|
175 } |
|
176 } |
|
177 return isAllDay; |
|
178 } |
|
179 |
|
180 /*! |
|
181 \brief CalenDayInfo::IsAllDayEvent |
|
182 Allday event is an event starting and ending at midnight, |
|
183 with a duration of n*24h. |
|
184 */ |
|
185 /* |
|
186 bool CalenDayInfo::IsAlldayEvent(const CCalInstance& aInstance) |
|
187 { |
|
188 bool isAllDay(false); |
|
189 |
|
190 // If getting the start or end time fails, return false. |
|
191 QDateTime start; |
|
192 QDateTime end; |
|
193 TRAPD( error, |
|
194 { |
|
195 start = aInstance.StartTimeL().TimeLocalL(); |
|
196 end = aInstance.EndTimeL().TimeLocalL(); |
|
197 }); |
|
198 |
|
199 if (error == KErrNone && !CalenDateUtils::onSameDay(start, end)) { |
|
200 QDateTime startMidnight = CalenDateUtils::beginningOfDay(start); |
|
201 QDateTime endMidnight = CalenDateUtils::beginningOfDay(end); |
|
202 |
|
203 if ((start == startMidnight) && (end == endMidnight)) { |
|
204 isAllDay = true; |
|
205 } |
|
206 } |
|
207 |
|
208 if (error != KErrNone) { |
|
209 CEikonEnv::Static()->HandleError(error);//codescanner::eikonenvstatic |
|
210 } |
|
211 |
|
212 return isAllDay; |
|
213 } |
|
214 */ |
|
215 |
|
216 /*! |
|
217 \brief CalenDayInfo::AlldayCount |
|
218 */ |
|
219 int CalenDayInfo::AlldayCount() |
|
220 { |
|
221 return iAlldayEvents.count(); |
|
222 } |
|
223 |
|
224 /*! |
|
225 \brief CalenDayInfo::TodoCount |
|
226 */ |
|
227 int CalenDayInfo::TodoCount() |
|
228 { |
|
229 return iTodoEvents.count(); |
|
230 } |
|
231 |
|
232 /*! |
|
233 \brief CalenDayInfo::GetLocation |
|
234 */ |
|
235 void CalenDayInfo::GetLocation( |
|
236 const SCalenApptInfo& aItemInfo, |
|
237 int& aStartSlot, |
|
238 int& aEndSlot, |
|
239 int& aColumnIndex, |
|
240 int& aColumns) |
|
241 { |
|
242 int startIndex = SlotIndexForStartTime(aItemInfo.iStartTime); |
|
243 int endIndex = SlotIndexForEndTime(aItemInfo.iEndTime); |
|
244 if (endIndex == startIndex) { |
|
245 endIndex++; |
|
246 } |
|
247 |
|
248 aStartSlot = startIndex; |
|
249 aEndSlot = endIndex; |
|
250 |
|
251 CalenSlotInterval interval; |
|
252 interval.iStartSlot = startIndex; |
|
253 interval.iEndSlot = endIndex; |
|
254 |
|
255 bool found(false); |
|
256 // Scan through all allday events and see if it matches any of them |
|
257 for (int i = 0; i < iAlldayEvents.count() && !found; i++) { |
|
258 if (aItemInfo.iId == iAlldayEvents[i].iId) { |
|
259 aColumns = iAlldayEvents.count(); |
|
260 aColumnIndex = i; |
|
261 found = true; |
|
262 } |
|
263 } |
|
264 |
|
265 // Scan through all regions and see if the event overlaps any region. |
|
266 // If it overlaps a region, the event must be in that region. |
|
267 for (int i = 0; i < iRegionList.count() && !found; i++) { |
|
268 CalenTimeRegion& region = iRegionList[i]; |
|
269 if (region.Overlaps(interval)) { |
|
270 // Scan through all columns and look for the event |
|
271 aColumns = region.iColumns.count(); |
|
272 for (int j = 0; j < aColumns && !found; j++) { |
|
273 if (region.iColumns[j].ContainsEvent(aItemInfo.iId)) { |
|
274 aColumnIndex = j; |
|
275 found = true; |
|
276 } |
|
277 } |
|
278 // the event should be in this region if it overlaps the region |
|
279 ASSERT( found ); |
|
280 } |
|
281 } |
|
282 // the event should have been found somewhere |
|
283 ASSERT( found ); |
|
284 } |
|
285 |
|
286 /*! |
|
287 \brief CalenDayInfo::GetSelectedSlot |
|
288 */ |
|
289 void CalenDayInfo::GetSelectedSlot(int& aSlot, int& aRegion, int& aColumnIndex, int& aColumns) |
|
290 { |
|
291 |
|
292 aSlot = iSelectedSlot; |
|
293 aColumnIndex = iSelectedColumn; |
|
294 if (iSelectedRegion >= 0) { |
|
295 aColumns = iRegionList[iSelectedRegion].iColumns.count(); |
|
296 aRegion = iSelectedRegion; |
|
297 } |
|
298 else { |
|
299 aColumns = 0; |
|
300 aRegion = KErrNotFound; |
|
301 } |
|
302 } |
|
303 |
|
304 /*! |
|
305 \brief CalenDayInfo::FindRegion |
|
306 */ |
|
307 int CalenDayInfo::FindRegion(const CalenSlotInterval& aInterval, int aDirection) |
|
308 { |
|
309 // Setup the start and end region indices for iterating |
|
310 int start, end; |
|
311 if (aDirection > 0) { |
|
312 start = 0; |
|
313 end = iRegionList.count(); |
|
314 } |
|
315 else { |
|
316 start = iRegionList.count() - 1; |
|
317 end = -1; |
|
318 } |
|
319 |
|
320 int region = KErrNotFound; |
|
321 |
|
322 // Iterate over the regions, in the order given, looking for a region |
|
323 // overlapping this interval |
|
324 for (int i = start; i != end && region < 0; i += aDirection) { |
|
325 if (iRegionList[i].Overlaps(aInterval)) { |
|
326 region = i; |
|
327 } |
|
328 } |
|
329 return region; |
|
330 } |
|
331 |
|
332 /*! |
|
333 \brief Find an event within the given interval of the current column, |
|
334 searching in the given direction. |
|
335 */ |
|
336 int CalenDayInfo::FindEvent(const CalenSlotInterval& aInterval, int aDirection) |
|
337 { |
|
338 ASSERT( iSelectedRegion >= 0 && iSelectedRegion < iRegionList.count() ); |
|
339 |
|
340 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
341 int index = KErrNotFound; |
|
342 |
|
343 if (iSelectedColumn < region.iColumns.count()) { |
|
344 CalenTimeColumn& column = region.iColumns[iSelectedColumn]; |
|
345 int start, end; |
|
346 if (aDirection > 0) { |
|
347 start = 0; |
|
348 end = column.iEventArray.count(); |
|
349 } |
|
350 else { |
|
351 start = column.iEventArray.count() - 1; |
|
352 end = -1; |
|
353 } |
|
354 |
|
355 // Iterate over the events in the chosen column in the order given, |
|
356 // looking for an event overlapping this interval |
|
357 for (int i = start; i != end && index < 0; i += aDirection) { |
|
358 if (column.iEventArray[i].Overlaps(aInterval)) { |
|
359 index = i; |
|
360 } |
|
361 } |
|
362 } |
|
363 return index; |
|
364 } |
|
365 |
|
366 /*! |
|
367 \brief CalenDayInfo::IsEventSelected |
|
368 */ |
|
369 bool CalenDayInfo::IsEventSelected() const |
|
370 { |
|
371 bool selected(false); |
|
372 if (iSelectedAlldayEvent >= 0) { |
|
373 selected = true; |
|
374 } |
|
375 else |
|
376 if (iSelectedRegion >= 0 && iSelectedColumn < iRegionList[iSelectedRegion].iColumns.count() |
|
377 && iSelectedColumnEventIndex >= 0) { |
|
378 selected = true; |
|
379 } |
|
380 else |
|
381 if (IsExtraSlot(iSelectedSlot) && iSelectedSlot - iFirstUntimedSlot |
|
382 >= iEmptyUntimedSlots) { |
|
383 selected = true; |
|
384 } |
|
385 else { |
|
386 // if no event is selected, the selection slot must be a hour starting slot or an extra slot |
|
387 ASSERT( IsHourStartSlot( iSelectedSlot ) || IsExtraSlot( iSelectedSlot ) ); |
|
388 selected = false; |
|
389 } |
|
390 return selected; |
|
391 } |
|
392 |
|
393 /*! |
|
394 \brief CalenDayInfo::IsMultipleEventsSelected |
|
395 */ |
|
396 bool CalenDayInfo::IsMultipleEventsSelected() const |
|
397 { |
|
398 bool isMultiple(false); |
|
399 if (iSelectedAlldayEvent >= 0) { |
|
400 // If an allday event is selected, disregard the value of |
|
401 // iSelectedSlot |
|
402 isMultiple = false; |
|
403 } |
|
404 else |
|
405 if (IsExtraSlot(iSelectedSlot)) { |
|
406 int index = iSelectedSlot - iFirstUntimedSlot - iEmptyUntimedSlots; |
|
407 isMultiple = (index == 0) && iTodoEvents.count() > 1; |
|
408 } |
|
409 return isMultiple; |
|
410 } |
|
411 |
|
412 /*! |
|
413 \brief CalenDayInfo::IsAlldayEventSelected |
|
414 */ |
|
415 bool CalenDayInfo::IsAlldayEventSelected() const |
|
416 { |
|
417 bool selected(false); |
|
418 if (iSelectedAlldayEvent >= 0) { |
|
419 ASSERT( iSelectedAlldayEvent < iAlldayEvents.count() ); |
|
420 selected = true; |
|
421 } |
|
422 return selected; |
|
423 } |
|
424 |
|
425 /*! |
|
426 \brief CalenDayInfo::UntimedEvent |
|
427 */ |
|
428 TCalenInstanceId CalenDayInfo::UntimedEvent(int aIndex) |
|
429 { |
|
430 TCalenInstanceId id; |
|
431 if (iTodoEvents.count() > 0 && aIndex == 0) { |
|
432 id = iTodoEvents[0]; |
|
433 } |
|
434 else { |
|
435 // If we have one or more todo items, the first slot is used for them |
|
436 // (but not more than one slot) |
|
437 if (iTodoEvents.count() > 0) { |
|
438 aIndex--; |
|
439 } |
|
440 |
|
441 if (aIndex >= 0 && aIndex < iUntimedEvents.count()) { |
|
442 id = iUntimedEvents[aIndex]; |
|
443 } |
|
444 else { |
|
445 // should not happen |
|
446 User::Invariant(); |
|
447 } |
|
448 } |
|
449 |
|
450 return id; |
|
451 } |
|
452 |
|
453 /*! |
|
454 \brief CalenDayInfo::AlldayEvent |
|
455 */ |
|
456 const CalenTimedEventInfo& CalenDayInfo::AlldayEvent(int aIndex) |
|
457 { |
|
458 ASSERT( aIndex >= 0 && aIndex < iAlldayEvents.count() ); |
|
459 return iAlldayEvents[aIndex]; |
|
460 } |
|
461 |
|
462 /*! |
|
463 \brief CalenDayInfo::SelectedEvent |
|
464 */ |
|
465 TCalenInstanceId CalenDayInfo::SelectedEvent() |
|
466 { |
|
467 TCalenInstanceId id; |
|
468 if (iSelectedAlldayEvent >= 0) { |
|
469 ASSERT( iSelectedAlldayEvent < iAlldayEvents.count() ); |
|
470 id = iAlldayEvents[iSelectedAlldayEvent].iId; |
|
471 } |
|
472 else |
|
473 if (iSelectedRegion >= 0) { |
|
474 ASSERT( iSelectedRegion < iRegionList.count() ); |
|
475 |
|
476 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
477 if (iSelectedColumn < region.iColumns.count()) { |
|
478 CalenTimeColumn& column = region.iColumns[iSelectedColumn]; |
|
479 if (iSelectedColumnEventIndex >= 0 && iSelectedColumnEventIndex |
|
480 < column.iEventArray.count()) { |
|
481 CalenTimedEventInfo& info = column.iEventArray[iSelectedColumnEventIndex]; |
|
482 id = info.iId; |
|
483 } |
|
484 else { |
|
485 // should not happen, no event selected in the column |
|
486 User::Invariant(); |
|
487 } |
|
488 } |
|
489 else { |
|
490 // should not happen, the empty column was selected |
|
491 User::Invariant(); |
|
492 } |
|
493 } |
|
494 else |
|
495 if (IsExtraSlot(iSelectedSlot)) { |
|
496 int index = iSelectedSlot - iFirstUntimedSlot - iEmptyUntimedSlots; |
|
497 id = UntimedEvent(index); |
|
498 } |
|
499 else { |
|
500 // should not happen |
|
501 User::Invariant(); |
|
502 } |
|
503 |
|
504 return id; |
|
505 } |
|
506 |
|
507 /*! |
|
508 \brief CalenDayInfo::SelectEvent |
|
509 Return KErrNotFound if not found, otherwise KErrNone |
|
510 */ |
|
511 int CalenDayInfo::SelectEvent(const TCalenInstanceId& aId) |
|
512 { |
|
513 // Id can be of allday event, untimed event or other events |
|
514 |
|
515 // Look for this event id in all event data structures and set |
|
516 // the state accordingly if it was found |
|
517 |
|
518 for (int i(0); i < iAlldayEvents.count(); i++) { |
|
519 TCalenInstanceId id = iAlldayEvents[i].iId; |
|
520 if (id == aId) { |
|
521 iSelectedAlldayEvent = i; |
|
522 iSelectedRegion = KErrNotFound; |
|
523 return KErrNone; |
|
524 } |
|
525 } |
|
526 |
|
527 for (int i(0); i < iTodoEvents.count(); i++) { |
|
528 TCalenInstanceId id = iTodoEvents[i]; |
|
529 if (id == aId) { |
|
530 iSelectedAlldayEvent = KErrNotFound; |
|
531 iSelectedRegion = KErrNotFound; |
|
532 iSelectedSlot = iFirstUntimedSlot + iEmptyUntimedSlots; |
|
533 return KErrNone; |
|
534 } |
|
535 } |
|
536 |
|
537 for (int i(0); i < iUntimedEvents.count(); i++) { |
|
538 TCalenInstanceId id = iUntimedEvents[i]; |
|
539 if (id == aId) { |
|
540 iSelectedAlldayEvent = KErrNotFound; |
|
541 iSelectedRegion = KErrNotFound; |
|
542 iSelectedSlot = iFirstUntimedSlot + iEmptyUntimedSlots + i; |
|
543 if (iTodoEvents.count() > 0) { |
|
544 iSelectedSlot++; |
|
545 } |
|
546 return KErrNone; |
|
547 } |
|
548 } |
|
549 |
|
550 for (int i(0); i < iRegionList.count(); i++) { |
|
551 CalenTimeRegion& region = iRegionList[i]; |
|
552 for (int col(0); col < region.iColumns.count(); col++) { |
|
553 for (int ind(0); ind < region.iColumns[col].iEventArray.count(); ind++) { |
|
554 if (region.iColumns[col].iEventArray[ind].iId == aId) { |
|
555 iSelectedAlldayEvent = KErrNotFound; |
|
556 iSelectedRegion = i; |
|
557 iSelectedColumn = col; |
|
558 iSelectedColumnEventIndex = ind; |
|
559 SetSelectionInEvent(EMoveDirectionDown); |
|
560 return KErrNone; |
|
561 } |
|
562 } |
|
563 } |
|
564 } |
|
565 |
|
566 return KErrNotFound; |
|
567 } |
|
568 |
|
569 /*! |
|
570 \brief CalenDayInfo::EnterRegionFromBelow |
|
571 */ |
|
572 void CalenDayInfo::EnterRegionFromBelow() |
|
573 { |
|
574 ASSERT( iSelectedRegion >= 0 && iSelectedRegion < iRegionList.count() ); |
|
575 iSelectedColumn = KErrNotFound; |
|
576 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
577 int latestEnd = region.iStartSlot; |
|
578 // Look for the column with the latest end |
|
579 for (int i = 0; i < region.iColumns.count(); i++) { |
|
580 CalenTimeColumn& column = region.iColumns[i]; |
|
581 ASSERT( column.iEventArray.count()> 0 ); |
|
582 if (column.iEndSlot > latestEnd) { |
|
583 // found a column with an event touching the end of the region |
|
584 latestEnd = column.iEndSlot; |
|
585 iSelectedColumn = i; |
|
586 iSelectedColumnEventIndex = column.iEventArray.count() - 1; |
|
587 SetSelectionInEvent(EMoveDirectionUp); |
|
588 } |
|
589 } |
|
590 ASSERT( iSelectedColumn >= 0 ); |
|
591 } |
|
592 |
|
593 /*! |
|
594 \brief CalenDayInfo::EnterRegionFromAbove |
|
595 */ |
|
596 void CalenDayInfo::EnterRegionFromAbove() |
|
597 { |
|
598 ASSERT( iSelectedRegion >= 0 && iSelectedRegion < iRegionList.count() ); |
|
599 iSelectedColumn = KErrNotFound; |
|
600 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
601 int earliestStart = region.iEndSlot; |
|
602 // Look for the column with the earliest start |
|
603 for (int i = 0; i < region.iColumns.count(); i++) { |
|
604 CalenTimeColumn& column = region.iColumns[i]; |
|
605 ASSERT( column.iEventArray.count()> 0 ); |
|
606 if (column.iStartSlot < earliestStart) { |
|
607 // found a column with an event |
|
608 earliestStart = column.iStartSlot; |
|
609 iSelectedColumn = i; |
|
610 iSelectedColumnEventIndex = 0; |
|
611 SetSelectionInEvent(EMoveDirectionDown); |
|
612 } |
|
613 } |
|
614 ASSERT( iSelectedColumn >= 0 ); |
|
615 } |
|
616 |
|
617 /*! |
|
618 \brief CalenDayInfo::NextFocusArea |
|
619 Determines how large area to scan for new events/regions when moving in |
|
620 the given direction. If no events are found in this area, focus an |
|
621 empty slot instead |
|
622 */ |
|
623 CalenSlotInterval CalenDayInfo::NextFocusArea(const CalenSlotInterval& aInterval, int aDirection) |
|
624 { |
|
625 // NOTE: the comments are written with the visual layout in mind. |
|
626 // upwards == up in the display, towards earlier times |
|
627 // downwards == down in the display, towards later times |
|
628 CalenSlotInterval target; |
|
629 target.iEndSlot = 0; |
|
630 target.iStartSlot = 0; |
|
631 |
|
632 if (IsExtraSlot(aInterval.iStartSlot)) { |
|
633 // Special case logic for moving within the extra slots. |
|
634 |
|
635 // The index within the extra slot area |
|
636 int extraIndex = aInterval.iStartSlot - iFirstUntimedSlot; |
|
637 // Generally, move just one slot at a time in this area |
|
638 int newIndex = extraIndex + aDirection; |
|
639 |
|
640 if (newIndex < iEmptyUntimedSlots) { |
|
641 // Moved upwards past the first slot, return |
|
642 // the whole last hour before the untimed slot area |
|
643 target.iEndSlot = iFirstUntimedSlot; |
|
644 target.iStartSlot = target.iEndSlot - iSlotsInHour; |
|
645 } |
|
646 else |
|
647 if (newIndex >= iUntimedSlotCount) { |
|
648 // Moved downwards past the last untimed slot, return |
|
649 // the whole first hour after the untimed slot area |
|
650 target.iStartSlot = iFirstUntimedSlot + iUntimedSlotCount; |
|
651 target.iEndSlot = target.iStartSlot + iSlotsInHour; |
|
652 } |
|
653 else { |
|
654 // Moved normally within the untimed slot area |
|
655 target.iStartSlot = aInterval.iStartSlot + aDirection; |
|
656 target.iEndSlot = target.iStartSlot + 1; |
|
657 } |
|
658 return target; |
|
659 } |
|
660 |
|
661 // Helper interval for the whole untimed area |
|
662 CalenSlotInterval untimedInterval; |
|
663 untimedInterval.iStartSlot = iFirstUntimedSlot; |
|
664 untimedInterval.iEndSlot = untimedInterval.iStartSlot + iUntimedSlotCount; |
|
665 |
|
666 if (aDirection < 0) { |
|
667 // Moving upwards |
|
668 // Create a target interval of one hour upwards |
|
669 target.iEndSlot = aInterval.iStartSlot; |
|
670 target.iStartSlot = aInterval.iStartSlot - iSlotsInHour; |
|
671 |
|
672 if (iUntimedSlotCount > 0 && untimedInterval.Overlaps(target)) { |
|
673 // The target interval overlaps the untimed area |
|
674 if (iUntimedSlotCount > iEmptyUntimedSlots) { |
|
675 // Make the interval start at the last untimed slot |
|
676 target.iStartSlot = untimedInterval.iEndSlot - 1; |
|
677 } |
|
678 else { |
|
679 // Untimed area containing no actual events. |
|
680 // Include one whole hour before the untimed area. |
|
681 target.iStartSlot = iFirstUntimedSlot - iSlotsInHour; |
|
682 } |
|
683 return target; |
|
684 } |
|
685 |
|
686 // Round the start slot upwards to an even hour |
|
687 target.iStartSlot = RoundHourUp(target.iStartSlot); |
|
688 } |
|
689 else { |
|
690 // Moving downwards |
|
691 // Create a target interval of one hour downwards |
|
692 target.iStartSlot = aInterval.iEndSlot; |
|
693 target.iEndSlot = aInterval.iEndSlot + iSlotsInHour; |
|
694 |
|
695 if (iUntimedSlotCount > 0 && untimedInterval.Overlaps(target)) { |
|
696 // The target interval overlaps the untimed area |
|
697 |
|
698 // Assumption: There can't be any regions before the untimed area |
|
699 if (iUntimedSlotCount > iEmptyUntimedSlots) { |
|
700 // Make the interval end at the first untimed slot containing |
|
701 // an event |
|
702 target.iStartSlot = untimedInterval.iStartSlot + iEmptyUntimedSlots; |
|
703 target.iEndSlot = target.iStartSlot + 1; |
|
704 } |
|
705 else { |
|
706 // Untimed area containing no actual events. |
|
707 // Include one whole hour after the untimed area. |
|
708 target.iStartSlot = untimedInterval.iStartSlot + iUntimedSlotCount; |
|
709 target.iEndSlot = target.iStartSlot + iSlotsInHour; |
|
710 } |
|
711 return target; |
|
712 } |
|
713 |
|
714 target.iEndSlot = RoundHourDown(target.iEndSlot); |
|
715 } |
|
716 |
|
717 return target; |
|
718 } |
|
719 |
|
720 /*! |
|
721 \brief CalenDayInfo::NextEmptyFocusSlot |
|
722 If no events are found in an empty area scanned, focus this slot instead |
|
723 */ |
|
724 int CalenDayInfo::NextEmptyFocusSlot(const CalenSlotInterval& aInterval, int aDirection) |
|
725 { |
|
726 // NOTE: the comments are written with the visual layout in mind. |
|
727 // upwards == up in the display, towards earlier times |
|
728 // downwards == down in the display, towards later times |
|
729 |
|
730 int target(0); |
|
731 |
|
732 // If the next focus area logic says we should go to an untimed slot, |
|
733 // skip the rest of this method |
|
734 CalenSlotInterval testInterval = NextFocusArea(aInterval, aDirection); |
|
735 if (IsExtraSlot(testInterval.iStartSlot)) { |
|
736 target = testInterval.iStartSlot; |
|
737 } |
|
738 else { |
|
739 if (aDirection < 0) { |
|
740 // Moving upwards, target slot is the start of the area returned by |
|
741 // NextFocusArea. This always is an even hour. |
|
742 target = testInterval.iStartSlot; |
|
743 ASSERT( IsHourStartSlot( target ) ); |
|
744 } |
|
745 else { |
|
746 target = testInterval.iStartSlot; |
|
747 if (!IsHourStartSlot(target)) { |
|
748 // If the interval doesn't start on an even hour, round downwards. |
|
749 target = RoundHourDown(target); |
|
750 } |
|
751 } |
|
752 } |
|
753 |
|
754 return target; |
|
755 } |
|
756 |
|
757 /*! |
|
758 \brief CalenDayInfo::EmptySelectionInterval |
|
759 Create an interval representation of the current focus area |
|
760 */ |
|
761 CalenSlotInterval CalenDayInfo::EmptySelectionInterval() |
|
762 { |
|
763 CalenSlotInterval target; |
|
764 target.iEndSlot = 0; |
|
765 target.iStartSlot = 0; |
|
766 |
|
767 if (IsExtraSlot(iSelectedSlot)) { |
|
768 // Return an interval consisting of one single slot |
|
769 target.iStartSlot = iSelectedSlot; |
|
770 target.iEndSlot = target.iStartSlot + 1; |
|
771 } |
|
772 else { |
|
773 // Round the start slot to an even hour if it isn't. |
|
774 // NOTE: This actually updates the selection state! |
|
775 // Only call this method if no event actually is selected. |
|
776 if (!IsHourStartSlot(iSelectedSlot)) { |
|
777 iSelectedSlot = RoundHourUp(iSelectedSlot); |
|
778 } |
|
779 target.iStartSlot = iSelectedSlot; |
|
780 target.iEndSlot = iSelectedSlot + iSlotsInHour; |
|
781 } |
|
782 |
|
783 return target; |
|
784 } |
|
785 |
|
786 /*! |
|
787 \brief CalenDayInfo::SelectedInterval |
|
788 */ |
|
789 CalenSlotInterval CalenDayInfo::SelectedInterval() |
|
790 { |
|
791 CalenSlotInterval selection; |
|
792 selection.iStartSlot = selection.iEndSlot = 0; |
|
793 |
|
794 if (iSelectedAlldayEvent >= 0) { |
|
795 selection.iStartSlot = 0; |
|
796 selection.iEndSlot = iSlotsInHour * KCalenHoursInDay + iUntimedSlotCount; |
|
797 } |
|
798 else |
|
799 if (iSelectedRegion >= 0) { |
|
800 |
|
801 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
802 if (iSelectedColumn < region.iColumns.count()) { |
|
803 CalenTimeColumn& column = region.iColumns[iSelectedColumn]; |
|
804 if (iSelectedColumnEventIndex >= 0 && iSelectedColumnEventIndex |
|
805 < column.iEventArray.count()) { |
|
806 CalenTimedEventInfo& info = column.iEventArray[iSelectedColumnEventIndex]; |
|
807 // gets only the CalenSlotInterval part from the CalenTimedEventInfo struct |
|
808 selection = info; |
|
809 } |
|
810 } |
|
811 } |
|
812 |
|
813 if (selection.IsEmpty()) { |
|
814 // No selection was set in the cases above, no event is selected, thus |
|
815 // use the empty area selection interval instead. |
|
816 selection = EmptySelectionInterval(); |
|
817 } |
|
818 return selection; |
|
819 } |
|
820 |
|
821 /*! |
|
822 \brief CalenDayInfo::SetSelectionInRegion |
|
823 Sets selection within a region |
|
824 */ |
|
825 bool CalenDayInfo::SetSelectionInRegion(int aRegion, int aColumn, int aSlot) |
|
826 { |
|
827 bool selected(false); |
|
828 StoreOrigSelection(); |
|
829 //validate given values |
|
830 if (aRegion >= 0 && aRegion < iRegionList.count()) {//ASSERT( iSelectedRegion >= 0 && iSelectedRegion < iRegionList.count() ); |
|
831 CalenSlotInterval interval; |
|
832 //TODO: round aSlot hour to full hour down???? |
|
833 interval.iStartSlot = aSlot; |
|
834 interval.iEndSlot = interval.iStartSlot + 1; |
|
835 |
|
836 CalenTimeRegion& region = iRegionList[aRegion]; |
|
837 if (region.Overlaps(interval)) { |
|
838 if (aColumn >= 0 && aColumn < region.iColumns.count()) { |
|
839 bool eventFound(false); |
|
840 CalenTimeColumn& column = region.iColumns[aColumn]; |
|
841 if (column.Overlaps(interval)) { |
|
842 ASSERT( column.iEventArray.count()> 0 ); |
|
843 for (int i = 0; i < column.iEventArray.count(); i++) { |
|
844 CalenTimedEventInfo& event = column.iEventArray[i]; |
|
845 if (event.Overlaps(interval)) { |
|
846 iSelectedColumnEventIndex = i; |
|
847 |
|
848 iSelectedAlldayEvent = KErrNotFound; |
|
849 iSelectedRegion = aRegion; |
|
850 iSelectedColumn = aColumn; |
|
851 iSelectedSlot = aSlot; |
|
852 selected = true; |
|
853 eventFound = true; |
|
854 break; |
|
855 } |
|
856 |
|
857 } |
|
858 } |
|
859 |
|
860 if (!eventFound) { |
|
861 iSelectedAlldayEvent = KErrNotFound; |
|
862 iSelectedRegion = aRegion; |
|
863 iSelectedColumn = aColumn; |
|
864 iSelectedSlot = aSlot; |
|
865 iSelectedColumnEventIndex = KErrNotFound; |
|
866 selected = true; |
|
867 } |
|
868 } |
|
869 else |
|
870 if (aColumn == iRegionList[aRegion].iColumns.count()) {//empty selection on right selected |
|
871 iSelectedAlldayEvent = KErrNotFound; |
|
872 iSelectedRegion = aRegion; |
|
873 iSelectedColumn = aColumn; |
|
874 iSelectedSlot = aSlot; |
|
875 iSelectedColumnEventIndex = KErrNotFound; |
|
876 selected = true; |
|
877 } |
|
878 } |
|
879 } |
|
880 |
|
881 return selected; |
|
882 } |
|
883 |
|
884 /*! |
|
885 \brief CalenDayInfo::MoveOutFromRegion |
|
886 */ |
|
887 void CalenDayInfo::MoveOutFromRegion(int aDirection) |
|
888 { |
|
889 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
890 CalenSlotInterval targetInterval = NextFocusArea(region, aDirection); |
|
891 int next = iSelectedRegion + aDirection; |
|
892 // Check what the next region would be and if we should move into that |
|
893 // or into an empty area |
|
894 if (next >= 0 && next < iRegionList.count()) { |
|
895 if (iRegionList[next].Overlaps(targetInterval)) { |
|
896 iSelectedRegion = next; |
|
897 if (aDirection < 0) { |
|
898 EnterRegionFromBelow(); |
|
899 } |
|
900 else { |
|
901 EnterRegionFromAbove(); |
|
902 } |
|
903 } |
|
904 else { |
|
905 iSelectedRegion = KErrNotFound; |
|
906 iSelectedSlot = NextEmptyFocusSlot(region, aDirection); |
|
907 } |
|
908 } |
|
909 else { |
|
910 iSelectedRegion = KErrNotFound; |
|
911 iSelectedSlot = NextEmptyFocusSlot(region, aDirection); |
|
912 } |
|
913 } |
|
914 |
|
915 /*! |
|
916 \brief CalenDayInfo::MoveInColumn |
|
917 */ |
|
918 void CalenDayInfo::MoveInColumn(int aDirection) |
|
919 { |
|
920 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
921 if (iSelectedColumn < region.iColumns.count()) { |
|
922 CalenTimeColumn& column = region.iColumns[iSelectedColumn]; |
|
923 if (iSelectedColumnEventIndex >= 0) { |
|
924 // We currently have an event in a column selected |
|
925 CalenSlotInterval curInterval = column.iEventArray[iSelectedColumnEventIndex]; |
|
926 CalenSlotInterval targetInterval = NextFocusArea(curInterval, aDirection); |
|
927 |
|
928 int next = iSelectedColumnEventIndex + aDirection; |
|
929 // Check if the target interval overlaps the next event in this column |
|
930 if (next >= 0 && next < column.iEventArray.count()) { |
|
931 if (column.iEventArray[next].Overlaps(targetInterval)) { |
|
932 iSelectedColumnEventIndex = next; |
|
933 SetSelectionInEvent(aDirection); |
|
934 } |
|
935 else { |
|
936 iSelectedColumnEventIndex = KErrNotFound; |
|
937 iSelectedSlot = NextEmptyFocusSlot(curInterval, aDirection); |
|
938 } |
|
939 } |
|
940 else { |
|
941 // There's no next event in this column, focus an empty area instead. |
|
942 iSelectedColumnEventIndex = KErrNotFound; |
|
943 iSelectedSlot = NextEmptyFocusSlot(curInterval, aDirection); |
|
944 } |
|
945 } |
|
946 else { |
|
947 // No event selected in the current column, find the target interval |
|
948 // and check if there's any event there |
|
949 CalenSlotInterval curInterval = EmptySelectionInterval(); |
|
950 CalenSlotInterval targetInterval = NextFocusArea(curInterval, aDirection); |
|
951 iSelectedColumnEventIndex = FindEvent(targetInterval, aDirection); |
|
952 if (iSelectedColumnEventIndex >= 0) { |
|
953 SetSelectionInEvent(aDirection); |
|
954 } |
|
955 else { |
|
956 iSelectedSlot = NextEmptyFocusSlot(curInterval, aDirection); |
|
957 } |
|
958 } |
|
959 |
|
960 // If the new selection lies outside of the region, move out from the region. |
|
961 CalenSlotInterval selection = SelectedInterval(); |
|
962 if (selection.iStartSlot < region.iStartSlot || selection.iEndSlot > region.iEndSlot) { |
|
963 MoveOutFromRegion(aDirection); |
|
964 } |
|
965 |
|
966 } |
|
967 else { |
|
968 // The empty column was selected, just move up/down in that column |
|
969 iSelectedSlot = NextEmptyFocusSlot(EmptySelectionInterval(), aDirection); |
|
970 |
|
971 // When moving in the empty column, move out from the region only if |
|
972 // the selection moved completely out from the region. |
|
973 CalenSlotInterval selection = SelectedInterval(); |
|
974 if (!selection.Overlaps(region)) { |
|
975 // The target selection is completely outside of the current region |
|
976 int next = iSelectedRegion + aDirection; |
|
977 if (next >= 0 && next < iRegionList.count() && iRegionList[next].Overlaps(selection)) { |
|
978 // The target selection overlaps the next region, move into that, |
|
979 // stay within the rightmost empty column |
|
980 iSelectedRegion = next; |
|
981 iSelectedColumn = iRegionList[next].iColumns.count(); |
|
982 iSelectedColumnEventIndex = KErrNotFound; |
|
983 } |
|
984 else { |
|
985 // Move out from the current region |
|
986 iSelectedRegion = KErrNotFound; |
|
987 iSelectedColumn = KErrNotFound; |
|
988 iSelectedColumnEventIndex = KErrNotFound; |
|
989 // iSelectedSlot was update above, keep the same value |
|
990 } |
|
991 } |
|
992 |
|
993 } |
|
994 |
|
995 } |
|
996 |
|
997 /*! |
|
998 \brief CalenDayInfo::MoveInAlldayEvent |
|
999 */ |
|
1000 bool CalenDayInfo::MoveInAlldayEvent(TScrollDirection aDirection) |
|
1001 { |
|
1002 ASSERT( iSelectedAlldayEvent >= 0 ); |
|
1003 bool moved(true); |
|
1004 switch (aDirection) { |
|
1005 case EScrollUp: { |
|
1006 // don't do anything |
|
1007 } |
|
1008 break; |
|
1009 case EScrollDown: { |
|
1010 // don't do anything |
|
1011 } |
|
1012 break; |
|
1013 case EScrollLeft: { |
|
1014 if (iSelectedAlldayEvent > 0) { |
|
1015 // there are more allday events to the left, select next |
|
1016 iSelectedAlldayEvent--; |
|
1017 } |
|
1018 else { |
|
1019 // move to previous day |
|
1020 moved = false; |
|
1021 } |
|
1022 } |
|
1023 break; |
|
1024 case EScrollRight: { |
|
1025 if (iSelectedAlldayEvent < iAlldayEvents.count() - 1) { |
|
1026 // there are more allday events to the right, select next |
|
1027 iSelectedAlldayEvent++; |
|
1028 } |
|
1029 else { |
|
1030 iSelectedAlldayEvent = KErrNotFound; |
|
1031 // find a region to select |
|
1032 if (iSelectedRegion >= 0) { |
|
1033 // keep using the old selection state |
|
1034 } |
|
1035 else { |
|
1036 // find a new suitable selection |
|
1037 |
|
1038 // if iSelectedSlot was moved to the empty untimed slot area, |
|
1039 // move it down to a real slot |
|
1040 |
|
1041 if (iSelectedSlot >= iFirstUntimedSlot && iSelectedSlot < iFirstUntimedSlot |
|
1042 + iEmptyUntimedSlots) { |
|
1043 iSelectedSlot = iFirstUntimedSlot + iEmptyUntimedSlots; |
|
1044 } |
|
1045 |
|
1046 CalenSlotInterval interval = EmptySelectionInterval(); |
|
1047 |
|
1048 iSelectedRegion = FindRegion(interval, EMoveDirectionDown); |
|
1049 int firstRegion = iSelectedRegion; |
|
1050 bool found(false); |
|
1051 // Iterate over all regions overlapping this interval, see |
|
1052 // if any of them has events in this column |
|
1053 while (iSelectedRegion >= 0 && iSelectedRegion < iRegionList.count() |
|
1054 && iRegionList[iSelectedRegion].Overlaps(interval) && !found) { |
|
1055 |
|
1056 ASSERT( iSelectedRegion < iRegionList.count() ); |
|
1057 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
1058 |
|
1059 ASSERT( region.iColumns.count()> 0 ); |
|
1060 iSelectedColumn = 0; |
|
1061 CalenTimeColumn& column = region.iColumns[iSelectedColumn]; |
|
1062 |
|
1063 iSelectedColumnEventIndex = FindEvent(interval, EMoveDirectionDown); |
|
1064 if (iSelectedColumnEventIndex >= 0) { |
|
1065 ASSERT( iSelectedColumnEventIndex < column.iEventArray.count() ); |
|
1066 // Keep using the old selected slot also here, just |
|
1067 // update it to make sure it's within the actual event |
|
1068 UpdateSelectionInEvent(); |
|
1069 found = true; |
|
1070 } |
|
1071 else { |
|
1072 // Check the next region |
|
1073 iSelectedRegion++; |
|
1074 } |
|
1075 } |
|
1076 |
|
1077 if (!found) { |
|
1078 iSelectedRegion = firstRegion; |
|
1079 iSelectedColumn = 0; |
|
1080 iSelectedSlot = interval.iStartSlot; |
|
1081 } |
|
1082 |
|
1083 } |
|
1084 } |
|
1085 } |
|
1086 break; |
|
1087 default: |
|
1088 // Do nothing |
|
1089 break; |
|
1090 } |
|
1091 |
|
1092 return moved; |
|
1093 } |
|
1094 |
|
1095 /*! |
|
1096 \brief CalenDayInfo::MoveBetweenColumns |
|
1097 */ |
|
1098 void CalenDayInfo::MoveBetweenColumns(TScrollDirection aDirection) |
|
1099 { |
|
1100 // Moving to another column |
|
1101 CalenSlotInterval selection = SelectedInterval(); |
|
1102 if (IsEventSelected()) { |
|
1103 // If moving from an event, just use the selected |
|
1104 // slot pos within the event, not the whole event |
|
1105 // interval. |
|
1106 selection.iStartSlot = iSelectedSlot; |
|
1107 selection.iEndSlot = selection.iStartSlot + iSlotsInHour; |
|
1108 // Crop the selection to be within the event |
|
1109 selection.Intersect(SelectedInterval()); |
|
1110 } |
|
1111 |
|
1112 switch (aDirection) { |
|
1113 case EScrollLeft: { |
|
1114 iSelectedColumn--; |
|
1115 break; |
|
1116 } |
|
1117 case EScrollRight: { |
|
1118 iSelectedColumn++; |
|
1119 break; |
|
1120 } |
|
1121 default: |
|
1122 // Do nothing |
|
1123 break; |
|
1124 } |
|
1125 |
|
1126 // First try finding events exactly in the selection area |
|
1127 iSelectedColumnEventIndex = FindEvent(selection, EMoveDirectionDown); |
|
1128 if (iSelectedColumnEventIndex >= 0) { |
|
1129 // An event was found in the given interval |
|
1130 // Keep using the old selection position, just update it to make |
|
1131 // sure it's within the event |
|
1132 UpdateSelectionInEvent(); |
|
1133 } |
|
1134 else { |
|
1135 // No event found in the interval |
|
1136 |
|
1137 // Expand the interval to even hour endings |
|
1138 selection.iStartSlot = RoundHourUp(selection.iStartSlot); |
|
1139 selection.iEndSlot = RoundHourDown(selection.iEndSlot); |
|
1140 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
1141 // Crop the selection to the current region |
|
1142 selection.Intersect(region); |
|
1143 |
|
1144 // Try again with the possibly larger interval |
|
1145 iSelectedColumnEventIndex = FindEvent(selection, EMoveDirectionDown); |
|
1146 if (iSelectedColumnEventIndex >= 0) { |
|
1147 // An event was found in the given interval |
|
1148 // Keep using the old selection position, just update it to make |
|
1149 // sure it's within the event |
|
1150 UpdateSelectionInEvent(); |
|
1151 } |
|
1152 else { |
|
1153 // Still no events found. Select an empty interval if possible. |
|
1154 |
|
1155 if (!IsHourStartSlot(selection.iStartSlot)) { |
|
1156 // The starting slot isn't a hour start slot. Rounding directly |
|
1157 // would move the interval outside of the region. See if we can |
|
1158 // round the starting slot down instead and still be within |
|
1159 // the region. |
|
1160 int start = RoundHourDown(selection.iStartSlot); |
|
1161 if (start + iSlotsInHour <= region.iEndSlot) { |
|
1162 // Ok, an empty selection fits within the region. |
|
1163 iSelectedSlot = start; |
|
1164 } |
|
1165 } |
|
1166 else |
|
1167 if (!IsHourStartSlot(selection.iEndSlot)) { |
|
1168 // The ending slot isn't a hour start slot. Rounding directly |
|
1169 // could move the interval outside of the region. See if we can |
|
1170 // round the upwards instead and still be within |
|
1171 // the region. |
|
1172 int start = RoundHourUp(selection.iEndSlot - iSlotsInHour); |
|
1173 if (start >= region.iStartSlot) { |
|
1174 // Ok, an empty selection fits within the region. |
|
1175 iSelectedSlot = start; |
|
1176 } |
|
1177 } |
|
1178 |
|
1179 // Make sure the selected interval really is a valid |
|
1180 // empty interval selection (this forces rounding if needed) |
|
1181 selection = EmptySelectionInterval(); |
|
1182 |
|
1183 // Check the final target interval once more. |
|
1184 iSelectedColumnEventIndex = FindEvent(selection, EMoveDirectionDown); |
|
1185 if (iSelectedColumnEventIndex >= 0) { |
|
1186 // An event was found in the given interval |
|
1187 UpdateSelectionInEvent(); |
|
1188 } |
|
1189 else { |
|
1190 // No even found, use the empty selection |
|
1191 |
|
1192 // If not within the region, move out |
|
1193 if (selection.iStartSlot < region.iStartSlot) { |
|
1194 MoveOutFromRegion(EMoveDirectionUp); |
|
1195 } |
|
1196 else |
|
1197 if (selection.iEndSlot > region.iEndSlot) { |
|
1198 MoveOutFromRegion(EMoveDirectionDown); |
|
1199 } |
|
1200 } |
|
1201 } |
|
1202 |
|
1203 } |
|
1204 |
|
1205 } |
|
1206 |
|
1207 /*! |
|
1208 \brief CalenDayInfo::MoveInRegion |
|
1209 */ |
|
1210 bool CalenDayInfo::MoveInRegion(TScrollDirection aDirection) |
|
1211 { |
|
1212 ASSERT( iSelectedAlldayEvent < 0 && iSelectedRegion >= 0 ); |
|
1213 bool moved(true); |
|
1214 switch (aDirection) { |
|
1215 case EScrollUp: { |
|
1216 MoveInColumn(EMoveDirectionUp); |
|
1217 } |
|
1218 break; |
|
1219 case EScrollDown: { |
|
1220 MoveInColumn(EMoveDirectionDown); |
|
1221 } |
|
1222 break; |
|
1223 |
|
1224 case EScrollLeft: { |
|
1225 ASSERT( iSelectedRegion < iRegionList.count() ); |
|
1226 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
1227 ASSERT( iSelectedColumn >= 0 && iSelectedColumn <= region.iColumns.count() ); |
|
1228 if (iSelectedColumn == 0) { |
|
1229 if (iAlldayEvents.count() > 0) { |
|
1230 // remember the last selection state |
|
1231 iSelectedAlldayEvent = iAlldayEvents.count() - 1; |
|
1232 } |
|
1233 else { |
|
1234 // move to previous day |
|
1235 moved = false; |
|
1236 } |
|
1237 } |
|
1238 else { |
|
1239 MoveBetweenColumns(aDirection); |
|
1240 } |
|
1241 } |
|
1242 break; |
|
1243 |
|
1244 case EScrollRight: { |
|
1245 ASSERT( iSelectedRegion < iRegionList.count() ); |
|
1246 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
1247 if (iSelectedColumn < region.iColumns.count() - 1) { |
|
1248 MoveBetweenColumns(aDirection); |
|
1249 } |
|
1250 else |
|
1251 if (iSelectedColumn == region.iColumns.count() - 1) { |
|
1252 // In the last column, moving to the empty column |
|
1253 iSelectedColumn++; |
|
1254 iSelectedColumnEventIndex = KErrNotFound; |
|
1255 |
|
1256 // Round the selection to an empty interval |
|
1257 EmptySelectionInterval(); |
|
1258 } |
|
1259 else { |
|
1260 // in the last, empty column |
|
1261 // move to next day |
|
1262 moved = false; |
|
1263 } |
|
1264 } |
|
1265 break; |
|
1266 |
|
1267 default: |
|
1268 // Do nothing |
|
1269 break; |
|
1270 } |
|
1271 |
|
1272 return moved; |
|
1273 } |
|
1274 |
|
1275 /*! |
|
1276 \brief CalenDayInfo::MoveInEmptyArea |
|
1277 */ |
|
1278 bool CalenDayInfo::MoveInEmptyArea(TScrollDirection aDirection) |
|
1279 { |
|
1280 ASSERT( iSelectedAlldayEvent < 0 && iSelectedRegion < 0 ); |
|
1281 bool moved(true); |
|
1282 switch (aDirection) { |
|
1283 case EScrollUp: { |
|
1284 CalenSlotInterval curInterval = EmptySelectionInterval(); |
|
1285 CalenSlotInterval targetInterval = NextFocusArea(curInterval, EMoveDirectionUp); |
|
1286 iSelectedRegion = FindRegion(targetInterval, EMoveDirectionUp); |
|
1287 if (iSelectedRegion >= 0) { |
|
1288 EnterRegionFromBelow(); |
|
1289 } |
|
1290 else { |
|
1291 iSelectedSlot = NextEmptyFocusSlot(curInterval, EMoveDirectionUp); |
|
1292 } |
|
1293 |
|
1294 } |
|
1295 break; |
|
1296 case EScrollDown: { |
|
1297 CalenSlotInterval curInterval = EmptySelectionInterval(); |
|
1298 CalenSlotInterval targetInterval = NextFocusArea(curInterval, EMoveDirectionDown); |
|
1299 iSelectedRegion = FindRegion(targetInterval, EMoveDirectionDown); |
|
1300 if (iSelectedRegion >= 0) { |
|
1301 EnterRegionFromAbove(); |
|
1302 } |
|
1303 else { |
|
1304 iSelectedSlot = NextEmptyFocusSlot(curInterval, EMoveDirectionDown); |
|
1305 } |
|
1306 } |
|
1307 break; |
|
1308 case EScrollLeft: { |
|
1309 if (iAlldayEvents.count() > 0) { |
|
1310 iSelectedAlldayEvent = iAlldayEvents.count() - 1; |
|
1311 } |
|
1312 else { |
|
1313 // move to previous day |
|
1314 moved = false; |
|
1315 } |
|
1316 } |
|
1317 break; |
|
1318 case EScrollRight: { |
|
1319 // move to next day |
|
1320 moved = false; |
|
1321 } |
|
1322 break; |
|
1323 default: |
|
1324 // Do nothing |
|
1325 break; |
|
1326 } |
|
1327 |
|
1328 return moved; |
|
1329 } |
|
1330 |
|
1331 /*! |
|
1332 \brief CalenDayInfo::MoveSelection |
|
1333 */ |
|
1334 bool CalenDayInfo::MoveSelection(TScrollDirection aDirection) |
|
1335 { |
|
1336 bool moved(true); |
|
1337 StoreOrigSelection(); |
|
1338 if (iSelectedAlldayEvent >= 0) { |
|
1339 // focused on an allday event |
|
1340 moved = MoveInAlldayEvent(aDirection); |
|
1341 } |
|
1342 else |
|
1343 if (iSelectedRegion >= 0) { |
|
1344 // focused on some event region |
|
1345 moved = MoveInRegion(aDirection); |
|
1346 } |
|
1347 else { |
|
1348 // focused on an empty, plain area |
|
1349 moved = MoveInEmptyArea(aDirection); |
|
1350 } |
|
1351 if (!ValidateSelection()) { |
|
1352 moved = false; |
|
1353 } |
|
1354 return moved; |
|
1355 } |
|
1356 |
|
1357 /*! |
|
1358 \brief CalenDayInfo::MoveSelectionInEvent |
|
1359 */ |
|
1360 void CalenDayInfo::MoveSelectionInEvent(TScrollDirection aDirection) |
|
1361 { |
|
1362 ASSERT( IsEventSelected() ); |
|
1363 |
|
1364 switch (aDirection) { |
|
1365 case EScrollUp: { |
|
1366 iSelectedSlot -= KFSCalSlotsInHour; |
|
1367 } |
|
1368 break; |
|
1369 case EScrollDown: { |
|
1370 iSelectedSlot += KFSCalSlotsInHour; |
|
1371 } |
|
1372 break; |
|
1373 |
|
1374 default: |
|
1375 // Do nothing |
|
1376 break; |
|
1377 } |
|
1378 |
|
1379 UpdateSelectionInEvent(); |
|
1380 |
|
1381 if (iSelectedAlldayEvent >= 0) { |
|
1382 // if an allday event is selected, invalidate |
|
1383 // the old region/event selection |
|
1384 iSelectedRegion = KErrNotFound; |
|
1385 } |
|
1386 } |
|
1387 |
|
1388 /*! |
|
1389 \brief CalenDayInfo::UpdateSelectionInEvent |
|
1390 */ |
|
1391 void CalenDayInfo::UpdateSelectionInEvent() |
|
1392 { |
|
1393 ASSERT( IsEventSelected() ); |
|
1394 CalenSlotInterval event = SelectedInterval(); |
|
1395 |
|
1396 if (iSelectedSlot < event.iStartSlot) { |
|
1397 iSelectedSlot = event.iStartSlot; |
|
1398 } |
|
1399 if (iSelectedSlot >= event.iEndSlot) { |
|
1400 iSelectedSlot = event.iEndSlot - 1; |
|
1401 } |
|
1402 |
|
1403 } |
|
1404 |
|
1405 /*! |
|
1406 \brief CalenDayInfo::SetSelectionInEvent |
|
1407 */ |
|
1408 void CalenDayInfo::SetSelectionInEvent(int aDirection) |
|
1409 { |
|
1410 CalenSlotInterval event = SelectedInterval(); |
|
1411 if (aDirection > 0) { |
|
1412 iSelectedSlot = event.iStartSlot; |
|
1413 } |
|
1414 else { |
|
1415 iSelectedSlot = event.iEndSlot - 1; |
|
1416 } |
|
1417 } |
|
1418 |
|
1419 /*! |
|
1420 \brief CalenDayInfo::StoreOrigSelection |
|
1421 */ |
|
1422 void CalenDayInfo::StoreOrigSelection() |
|
1423 { |
|
1424 iOrigSelectedAlldayEvent = iSelectedAlldayEvent; |
|
1425 iOrigSelectedRegion = iSelectedRegion; |
|
1426 iOrigSelectedColumn = iSelectedColumn; |
|
1427 iOrigSelectedSlot = iSelectedSlot; |
|
1428 iOrigSelectedColumnEventIndex = iSelectedColumnEventIndex; |
|
1429 } |
|
1430 |
|
1431 /*! |
|
1432 \brief CalenDayInfo::ValidateSelection |
|
1433 */ |
|
1434 bool CalenDayInfo::ValidateSelection() |
|
1435 { |
|
1436 bool validate(true); |
|
1437 if (iSelectedSlot < 0 || iSelectedSlot >= iSlotsInHour * KCalenHoursInDay + iUntimedSlotCount) { |
|
1438 // tried to move outside of the day |
|
1439 // revert to the original coords |
|
1440 iSelectedAlldayEvent = iOrigSelectedAlldayEvent; |
|
1441 iSelectedRegion = iOrigSelectedRegion; |
|
1442 iSelectedColumn = iOrigSelectedColumn; |
|
1443 iSelectedSlot = iOrigSelectedSlot; |
|
1444 iSelectedColumnEventIndex = iOrigSelectedColumnEventIndex; |
|
1445 validate = false; |
|
1446 } |
|
1447 return validate; |
|
1448 } |
|
1449 |
|
1450 /*! |
|
1451 \brief CalenDayInfo::SelectSlot |
|
1452 */ |
|
1453 void CalenDayInfo::SelectSlot(int aSlot) |
|
1454 { |
|
1455 // Check for special case: empty untimed slot is selected |
|
1456 if (aSlot >= iFirstUntimedSlot && aSlot < iFirstUntimedSlot + iEmptyUntimedSlots) { |
|
1457 aSlot = iFirstUntimedSlot + iEmptyUntimedSlots; |
|
1458 } |
|
1459 |
|
1460 iSelectedAlldayEvent = KErrNotFound; |
|
1461 iSelectedSlot = aSlot; |
|
1462 CalenSlotInterval interval = EmptySelectionInterval(); |
|
1463 iSelectedRegion = FindRegion(interval, EMoveDirectionDown); |
|
1464 if (iSelectedRegion >= 0) { |
|
1465 CalenTimeRegion& region = iRegionList[iSelectedRegion]; |
|
1466 int regCount(region.iColumns.count()); |
|
1467 for (int i = 0; i < regCount; i++) { |
|
1468 CalenTimeColumn& column = region.iColumns[i]; |
|
1469 int colCount(column.iEventArray.count()); |
|
1470 for (int j = 0; j < colCount; j++) { |
|
1471 if (column.iEventArray[j].Overlaps(interval)) { |
|
1472 iSelectedColumn = i; |
|
1473 iSelectedColumnEventIndex = j; |
|
1474 iSelectedSlot = aSlot; |
|
1475 UpdateSelectionInEvent(); |
|
1476 return; |
|
1477 } |
|
1478 } |
|
1479 } |
|
1480 // Regions can have empty areas where there aren't any events, |
|
1481 // due to rounding of the ends of the region to whole hours. |
|
1482 // A region cannot, however, have a empty complete whole hour. |
|
1483 // Therefore, this cannot occur. |
|
1484 User::Invariant(); |
|
1485 } |
|
1486 } |
|
1487 |
|
1488 /*! |
|
1489 \brief CalenDayInfo::RegionList |
|
1490 */ |
|
1491 const QList<CalenTimeRegion>& CalenDayInfo::RegionList() const |
|
1492 { |
|
1493 return iRegionList; |
|
1494 } |
|
1495 |
|
1496 /*! |
|
1497 \brief CalenDayInfo::GetEventIntervals |
|
1498 */ |
|
1499 void CalenDayInfo::GetEventIntervals(QList<CalenEventInterval>& aArray) const |
|
1500 { |
|
1501 int regCount(iRegionList.count()); |
|
1502 for (int i = 0; i < regCount; i++) { |
|
1503 const CalenTimeRegion& region = iRegionList[i]; |
|
1504 for (int j = 0; j < region.iIntervals.count(); j++) { |
|
1505 aArray.append(region.iIntervals[j]); |
|
1506 } |
|
1507 } |
|
1508 } |
|
1509 |
|
1510 /*! |
|
1511 \brief CalenDayInfo::InsertUntimedEventL |
|
1512 */ |
|
1513 /* |
|
1514 void CalenDayInfo::InsertUntimedEventL(const CCalInstance& aInstance) |
|
1515 { |
|
1516 if (CalenAgendaUtils::IsTimedEntryL(aInstance.Entry().EntryTypeL())) { |
|
1517 // timed entry added as untimed event |
|
1518 User::Invariant(); |
|
1519 } |
|
1520 |
|
1521 TCalenInstanceId id = TCalenInstanceId::CreateL(aInstance); |
|
1522 InsertUntimedEvent(aInstance.Entry().EntryTypeL(), id); |
|
1523 } |
|
1524 */ |
|
1525 |
|
1526 /*! |
|
1527 \brief CalenDayInfo::InsertUntimedEvent |
|
1528 */ |
|
1529 void CalenDayInfo::InsertUntimedEvent(AgendaEntry::Type aType, const TCalenInstanceId& aId) |
|
1530 { |
|
1531 if (aType == AgendaEntry::TypeTodo) { |
|
1532 iTodoEvents.append(aId); |
|
1533 } |
|
1534 else { |
|
1535 iUntimedEvents.append(aId); |
|
1536 } |
|
1537 } |
|
1538 |
|
1539 /*! |
|
1540 \brief CalenDayInfo::SuggestedUntimedSlotPos |
|
1541 */ |
|
1542 int CalenDayInfo::SuggestedUntimedSlotPos() |
|
1543 { |
|
1544 int slot = KFSCalStartingHour * iSlotsInHour; |
|
1545 if (iRegionList.count() > 0) { |
|
1546 CalenTimeRegion& region = iRegionList[0]; |
|
1547 if (region.iStartSlot < slot) { |
|
1548 slot = RoundHourUp(region.iStartSlot); |
|
1549 } |
|
1550 } |
|
1551 return slot; |
|
1552 } |
|
1553 |
|
1554 /*! |
|
1555 \brief CalenDayInfo::NeededUntimedSlotCount |
|
1556 */ |
|
1557 int CalenDayInfo::NeededUntimedSlotCount() |
|
1558 { |
|
1559 int count = iUntimedEvents.count(); |
|
1560 if (iTodoEvents.count() > 0) { |
|
1561 count++; |
|
1562 } |
|
1563 return count; |
|
1564 } |
|
1565 |
|
1566 /*! |
|
1567 \brief CalenDayInfo::NeededUntimedSlotCount |
|
1568 */ |
|
1569 int CalenDayInfo::UpdateUntimedPos(int aSlot, int aUntimedCount) |
|
1570 { |
|
1571 int newValue = NeededUntimedSlotCount(); |
|
1572 |
|
1573 // If this method is called many times, first undo the previous modifications |
|
1574 int regCount(iRegionList.count()); |
|
1575 for (int i = 0; i < regCount; i++) { |
|
1576 iRegionList[i].AddOffset(-iUntimedSlotCount, iFirstUntimedSlot); |
|
1577 } |
|
1578 if (iSelectedSlot >= iFirstUntimedSlot) { |
|
1579 iSelectedSlot -= iUntimedSlotCount; |
|
1580 } |
|
1581 |
|
1582 // Reset the untimed slot count |
|
1583 iUntimedSlotCount = 0; |
|
1584 |
|
1585 // Get the default values |
|
1586 iFirstUntimedSlot = SuggestedUntimedSlotPos(); |
|
1587 iUntimedSlotCount = newValue; |
|
1588 |
|
1589 // If parameters were given, use them instead of the defaults |
|
1590 if (aSlot >= 0) { |
|
1591 ASSERT( aSlot <= iFirstUntimedSlot ); |
|
1592 ASSERT( iUntimedSlotCount <= aUntimedCount ); |
|
1593 |
|
1594 iFirstUntimedSlot = aSlot; |
|
1595 iUntimedSlotCount = aUntimedCount; |
|
1596 } |
|
1597 |
|
1598 iEmptyUntimedSlots = iUntimedSlotCount - NeededUntimedSlotCount(); |
|
1599 |
|
1600 // Add the new offset to all regions and update the selected slot |
|
1601 regCount = iRegionList.count(); |
|
1602 for (int i = 0; i < regCount; i++) { |
|
1603 iRegionList[i].AddOffset(iUntimedSlotCount, iFirstUntimedSlot); |
|
1604 } |
|
1605 if (iSelectedSlot >= iFirstUntimedSlot) { |
|
1606 iSelectedSlot += iUntimedSlotCount; |
|
1607 } |
|
1608 int eventCount(iAlldayEvents.count()); |
|
1609 for (int i = 0; i < eventCount; i++) { |
|
1610 iAlldayEvents[i].iEndSlot = iSlotsInHour * KCalenHoursInDay + iUntimedSlotCount; |
|
1611 } |
|
1612 |
|
1613 // Do rounding of the end of the last region. This should be done when no |
|
1614 // more events will be added, but there's no real harm if new events are |
|
1615 // added after this. |
|
1616 if (iRegionList.count() > 0) { |
|
1617 // Round the end of the last region down |
|
1618 CalenTimeRegion& lastRegion = iRegionList[iRegionList.count() - 1]; |
|
1619 lastRegion.iEndSlot = RoundHourDown(lastRegion.iEndSlot); |
|
1620 } |
|
1621 |
|
1622 return iFirstUntimedSlot; |
|
1623 } |
|
1624 |
|
1625 /*! |
|
1626 \brief Returns the index of the first occupied slot |
|
1627 */ |
|
1628 int CalenDayInfo::FirstOccupiedSlot() |
|
1629 { |
|
1630 |
|
1631 int firstNonemptySlot(KErrNotFound); |
|
1632 |
|
1633 if (iUntimedSlotCount > 0) { |
|
1634 firstNonemptySlot = iFirstUntimedSlot; |
|
1635 } |
|
1636 else { |
|
1637 if (iRegionList.count() > 0) { |
|
1638 CalenTimeRegion& region = iRegionList[0]; |
|
1639 firstNonemptySlot = region.iStartSlot; |
|
1640 } |
|
1641 } |
|
1642 |
|
1643 return firstNonemptySlot; |
|
1644 } |
|
1645 |
|
1646 /*! |
|
1647 \brief Returns the index of the last occupied slot |
|
1648 */ |
|
1649 int CalenDayInfo::LastOccupiedSlot() |
|
1650 { |
|
1651 int lastNonemptySlot(KErrNotFound); |
|
1652 if (iRegionList.count() > 0) { |
|
1653 int lastIndex = iRegionList.count() - 1; |
|
1654 CalenTimeRegion& region = iRegionList[lastIndex]; |
|
1655 lastNonemptySlot = region.iEndSlot; |
|
1656 } |
|
1657 else { |
|
1658 if (iUntimedSlotCount > 0) { |
|
1659 lastNonemptySlot = iFirstUntimedSlot + iUntimedSlotCount - 1; |
|
1660 } |
|
1661 } |
|
1662 return lastNonemptySlot; |
|
1663 } |
|
1664 |
|
1665 /*! |
|
1666 \brief Returns the index of the earliest end slot |
|
1667 */ |
|
1668 int CalenDayInfo::EarliestEndSlot() |
|
1669 { |
|
1670 int earliestEndSlot(KErrNotFound); |
|
1671 int untimedEventCount = iUntimedSlotCount - iEmptyUntimedSlots; |
|
1672 if (untimedEventCount > 0) { |
|
1673 earliestEndSlot = iFirstUntimedSlot + iEmptyUntimedSlots; |
|
1674 // add 1, since end slot is actually the one that is right after.. |
|
1675 earliestEndSlot++; |
|
1676 } |
|
1677 else { |
|
1678 if (iRegionList.count() > 0) { |
|
1679 earliestEndSlot = iEarliestEndSlot + iEmptyUntimedSlots; |
|
1680 } |
|
1681 } |
|
1682 return earliestEndSlot; |
|
1683 } |
|
1684 |
|
1685 /*! |
|
1686 \brief Returns the index of the last start slot |
|
1687 */ |
|
1688 int CalenDayInfo::LastStartSlot() |
|
1689 { |
|
1690 int lastStartSlot(KErrNotFound); |
|
1691 |
|
1692 if (iRegionList.count() > 0) { |
|
1693 lastStartSlot = iLastStartSlot + iUntimedSlotCount; |
|
1694 } |
|
1695 else { |
|
1696 if (iUntimedSlotCount - iEmptyUntimedSlots > 0) { |
|
1697 lastStartSlot = iFirstUntimedSlot + iUntimedSlotCount - 1; |
|
1698 } |
|
1699 } |
|
1700 return lastStartSlot; |
|
1701 } |
|
1702 |
|
1703 /*! |
|
1704 \brief Returns the index of a slot where this event should start drawing, |
|
1705 based on the start time |
|
1706 */ |
|
1707 int CalenDayInfo::SlotIndexForStartTime(QDateTime aStartTime) |
|
1708 { |
|
1709 // For example, 1/2 hour accuracy (iSlotsInHour == 2): |
|
1710 // Start drawing with the previus half hour: 9:15 -> 9:00, 9:59-> 9:30. |
|
1711 |
|
1712 |
|
1713 // TDateTime dt = aStartTime.DateTime(); |
|
1714 // int minutes = dt.Minute(); |
|
1715 // int hours = dt.Hour(); |
|
1716 int minutes = aStartTime.time().minute();//dt.Minute(); |
|
1717 int hours = aStartTime.time().hour();//dt.Hour(); |
|
1718 |
|
1719 // calculate index based on the hour. |
|
1720 int slotIndex = hours * iSlotsInHour; |
|
1721 |
|
1722 switch (iSlotsInHour) { |
|
1723 case EOne: // do nothing |
|
1724 break; |
|
1725 case ETwo: { |
|
1726 if (minutes >= 30) { |
|
1727 slotIndex++; |
|
1728 } |
|
1729 } |
|
1730 break; |
|
1731 case EThree: { |
|
1732 if (minutes >= 20) { |
|
1733 slotIndex++; |
|
1734 } |
|
1735 if (minutes >= 40) { |
|
1736 slotIndex++; |
|
1737 } |
|
1738 } |
|
1739 break; |
|
1740 case EFour: // followthrough |
|
1741 default: { |
|
1742 if (minutes >= 15) { |
|
1743 slotIndex++; |
|
1744 } |
|
1745 if (minutes >= 30) { |
|
1746 slotIndex++; |
|
1747 } |
|
1748 if (minutes >= 45) { |
|
1749 slotIndex++; |
|
1750 } |
|
1751 |
|
1752 } |
|
1753 } |
|
1754 |
|
1755 if (slotIndex >= iFirstUntimedSlot) { |
|
1756 slotIndex += iUntimedSlotCount; |
|
1757 } |
|
1758 return slotIndex; |
|
1759 } |
|
1760 |
|
1761 /*! |
|
1762 \brief Returns the index of a slot where this event should end drawing, |
|
1763 based on the end time |
|
1764 */ |
|
1765 int CalenDayInfo::SlotIndexForEndTime(QDateTime aEndTime) |
|
1766 { |
|
1767 // For example, 1/2 hour accuracy (iSlotsInHour == 2): |
|
1768 // End drawing with the next half hour: 9:10 -> 9:30, 9:59-> 10:00. |
|
1769 |
|
1770 // TDateTime dt = aEndTime.DateTime(); |
|
1771 // int minutes = dt.Minute(); |
|
1772 // int hours = dt.Hour(); |
|
1773 int minutes = aEndTime.time().minute(); |
|
1774 int hours = aEndTime.time().hour(); |
|
1775 |
|
1776 // calculate index based on the hour. |
|
1777 int slotIndex = hours * iSlotsInHour; |
|
1778 |
|
1779 switch (iSlotsInHour) { |
|
1780 case EOne: { |
|
1781 if (minutes > 0) { |
|
1782 slotIndex++; |
|
1783 } |
|
1784 } |
|
1785 |
|
1786 break; |
|
1787 case ETwo: { |
|
1788 if (minutes > 0) { |
|
1789 slotIndex++; |
|
1790 } |
|
1791 if (minutes > 30) { |
|
1792 slotIndex++; |
|
1793 } |
|
1794 } |
|
1795 break; |
|
1796 case EThree: { |
|
1797 if (minutes > 0) { |
|
1798 slotIndex++; |
|
1799 } |
|
1800 if (minutes > 20) { |
|
1801 slotIndex++; |
|
1802 } |
|
1803 if (minutes > 40) { |
|
1804 slotIndex++; |
|
1805 } |
|
1806 } |
|
1807 break; |
|
1808 case EFour: // followthrough |
|
1809 default: { |
|
1810 if (minutes > 0) { |
|
1811 slotIndex++; |
|
1812 } |
|
1813 |
|
1814 if (minutes > 15) { |
|
1815 slotIndex++; |
|
1816 } |
|
1817 if (minutes > 30) { |
|
1818 slotIndex++; |
|
1819 } |
|
1820 if (minutes > 45) { |
|
1821 slotIndex++; |
|
1822 } |
|
1823 |
|
1824 } |
|
1825 } |
|
1826 |
|
1827 if (slotIndex >= iFirstUntimedSlot) { |
|
1828 slotIndex += iUntimedSlotCount; |
|
1829 } |
|
1830 |
|
1831 return slotIndex; |
|
1832 |
|
1833 } |
|
1834 |
|
1835 /*! |
|
1836 \brief CalenDayInfo::IsHourStartSlot |
|
1837 */ |
|
1838 bool CalenDayInfo::IsHourStartSlot(const int& aSlotIndex) const |
|
1839 { |
|
1840 bool isHourStartSlot(false); |
|
1841 if (IsExtraSlot(aSlotIndex)) { |
|
1842 isHourStartSlot = false; |
|
1843 } |
|
1844 else { |
|
1845 int hourIndex(aSlotIndex); |
|
1846 if (aSlotIndex >= iFirstUntimedSlot + iUntimedSlotCount) { |
|
1847 hourIndex -= iUntimedSlotCount; |
|
1848 } |
|
1849 int hour = hourIndex / iSlotsInHour; |
|
1850 int startIndOfHour = hour * iSlotsInHour; |
|
1851 if (hourIndex - startIndOfHour > 0) { |
|
1852 isHourStartSlot = false; |
|
1853 } |
|
1854 else { |
|
1855 isHourStartSlot = true; |
|
1856 } |
|
1857 } |
|
1858 return isHourStartSlot; |
|
1859 |
|
1860 } |
|
1861 |
|
1862 /*! |
|
1863 \brief CalenDayInfo::IsExtraSlot |
|
1864 */ |
|
1865 bool CalenDayInfo::IsExtraSlot(const int& aSlotIndex) const |
|
1866 { |
|
1867 return (aSlotIndex >= iFirstUntimedSlot) && (aSlotIndex < (iFirstUntimedSlot |
|
1868 + iUntimedSlotCount)); |
|
1869 } |
|
1870 |
|
1871 /*! |
|
1872 \brief CalenDayInfo::HourFromSlotIndex |
|
1873 Returns the corresponding hour, or KErrNone if index is not hour slot index |
|
1874 */ |
|
1875 int CalenDayInfo::HourFromSlotIndex(const int& aSlotInd) const |
|
1876 { |
|
1877 |
|
1878 int hour(KErrNotFound); |
|
1879 |
|
1880 if (!IsExtraSlot(aSlotInd)) { |
|
1881 |
|
1882 if (aSlotInd < 0) { |
|
1883 // round downwards, to the previous starting hour |
|
1884 // e.g. iSlotsInHour = 2, aSlotInd = -1, hour = -1, |
|
1885 // which by SlotIndexFromHour corresponds to slot -2 |
|
1886 hour = (aSlotInd - iSlotsInHour + 1) / iSlotsInHour; |
|
1887 } |
|
1888 else |
|
1889 if (aSlotInd < iFirstUntimedSlot) { |
|
1890 hour = aSlotInd / iSlotsInHour; |
|
1891 } |
|
1892 else |
|
1893 if (aSlotInd >= iFirstUntimedSlot + iUntimedSlotCount) { |
|
1894 hour = (aSlotInd - iUntimedSlotCount) / iSlotsInHour; |
|
1895 } |
|
1896 } |
|
1897 return hour; |
|
1898 } |
|
1899 |
|
1900 /*! |
|
1901 \brief CalenDayInfo::SlotIndexFromHour |
|
1902 Returns the corresponding hour, or KErrNone if index is not hour slot index |
|
1903 */ |
|
1904 int CalenDayInfo::SlotIndexFromHour(int aHour) |
|
1905 { |
|
1906 |
|
1907 int slotIndex(KErrNotFound); |
|
1908 |
|
1909 if (aHour >= iFirstUntimedSlot / iSlotsInHour) { |
|
1910 slotIndex = aHour * iSlotsInHour + iUntimedSlotCount; |
|
1911 } |
|
1912 else { |
|
1913 slotIndex = aHour * iSlotsInHour; |
|
1914 } |
|
1915 |
|
1916 return slotIndex; |
|
1917 } |
|
1918 |
|
1919 /*! |
|
1920 \brief CalenDayInfo::RoundHourUp |
|
1921 Rounds the slot number up (towards earlier hours) to an even hour |
|
1922 */ |
|
1923 int CalenDayInfo::RoundHourUp(int aSlot) |
|
1924 { |
|
1925 if (!IsExtraSlot(aSlot)) { |
|
1926 aSlot = SlotIndexFromHour(HourFromSlotIndex(aSlot)); |
|
1927 } |
|
1928 return aSlot; |
|
1929 } |
|
1930 |
|
1931 /*! |
|
1932 \brief CalenDayInfo::RoundHourDown |
|
1933 Rounds the slot number down (towards later hours) to an even hour |
|
1934 */ |
|
1935 int CalenDayInfo::RoundHourDown(int aSlot) |
|
1936 { |
|
1937 if (!IsExtraSlot(aSlot) && !IsHourStartSlot(aSlot)) { |
|
1938 aSlot = SlotIndexFromHour(HourFromSlotIndex(aSlot + iSlotsInHour)); |
|
1939 } |
|
1940 return aSlot; |
|
1941 } |
|
1942 |
|
1943 /*! |
|
1944 \brief CalenSlotInterval::Overlaps |
|
1945 */ |
|
1946 bool CalenSlotInterval::Overlaps(const CalenSlotInterval& aInterval) const |
|
1947 { |
|
1948 return aInterval.iStartSlot < iEndSlot && aInterval.iEndSlot > iStartSlot; |
|
1949 } |
|
1950 |
|
1951 /*! |
|
1952 \brief CalenSlotInterval::AddOffset |
|
1953 */ |
|
1954 void CalenSlotInterval::AddOffset(int aOffset, int aPos) |
|
1955 { |
|
1956 if (iStartSlot >= aPos) { |
|
1957 iStartSlot += aOffset; |
|
1958 } |
|
1959 if (iEndSlot >= aPos) { |
|
1960 iEndSlot += aOffset; |
|
1961 } |
|
1962 } |
|
1963 |
|
1964 /*! |
|
1965 \brief CalenSlotInterval::Union |
|
1966 */ |
|
1967 void CalenSlotInterval::Union(const CalenSlotInterval& aInterval) |
|
1968 { |
|
1969 if (!aInterval.IsEmpty()) { |
|
1970 iStartSlot = Min(iStartSlot, aInterval.iStartSlot); |
|
1971 iEndSlot = Max(iEndSlot, aInterval.iEndSlot); |
|
1972 } |
|
1973 } |
|
1974 |
|
1975 /*! |
|
1976 \brief CalenSlotInterval::Adjacent |
|
1977 */ |
|
1978 bool CalenSlotInterval::Adjacent(const CalenSlotInterval& aInterval) const |
|
1979 { |
|
1980 bool adjacent(false); |
|
1981 if (Overlaps(aInterval)) { |
|
1982 adjacent = true; |
|
1983 } |
|
1984 else { |
|
1985 adjacent = iStartSlot == aInterval.iEndSlot || iEndSlot == aInterval.iStartSlot; |
|
1986 } |
|
1987 return adjacent; |
|
1988 } |
|
1989 |
|
1990 /*! |
|
1991 \brief CalenSlotInterval::IsEmpty |
|
1992 */ |
|
1993 bool CalenSlotInterval::IsEmpty() const |
|
1994 { |
|
1995 return iStartSlot >= iEndSlot; |
|
1996 } |
|
1997 |
|
1998 /*! |
|
1999 \brief CalenSlotInterval::Intersect |
|
2000 */ |
|
2001 void CalenSlotInterval::Intersect(const CalenSlotInterval& aInterval) |
|
2002 { |
|
2003 if (aInterval.IsEmpty()) { |
|
2004 iEndSlot = iStartSlot; |
|
2005 } |
|
2006 else { |
|
2007 iStartSlot = Max(iStartSlot, aInterval.iStartSlot); |
|
2008 iEndSlot = Min(iEndSlot, aInterval.iEndSlot); |
|
2009 } |
|
2010 } |
|
2011 |
|
2012 /*! |
|
2013 \brief CalenSlotInterval::Subtract |
|
2014 */ |
|
2015 void CalenSlotInterval::Subtract(const CalenSlotInterval& aInterval, CalenSlotInterval& aSecondPart) |
|
2016 { |
|
2017 aSecondPart.iStartSlot = aSecondPart.iEndSlot = 0; |
|
2018 if (!aInterval.IsEmpty() && Overlaps(aInterval)) { |
|
2019 if (aInterval.iStartSlot <= iStartSlot) { |
|
2020 iStartSlot = aInterval.iEndSlot; |
|
2021 } |
|
2022 else |
|
2023 if (aInterval.iEndSlot >= iEndSlot) { |
|
2024 iEndSlot = aInterval.iStartSlot; |
|
2025 } |
|
2026 else { |
|
2027 aSecondPart.iStartSlot = aInterval.iEndSlot; |
|
2028 aSecondPart.iEndSlot = iEndSlot; |
|
2029 iEndSlot = aInterval.iStartSlot; |
|
2030 } |
|
2031 } |
|
2032 } |
|
2033 |
|
2034 /*! |
|
2035 \brief CalenSlotInterval::operator> |
|
2036 */ |
|
2037 bool CalenSlotInterval::operator>(const CalenSlotInterval& aInterval) const |
|
2038 { |
|
2039 return iStartSlot > aInterval.iStartSlot; |
|
2040 } |
|
2041 |
|
2042 /*! |
|
2043 \brief CalenTimeColumn::Close |
|
2044 */ |
|
2045 void CalenTimeColumn::Close() |
|
2046 { |
|
2047 iEventArray.clear(); |
|
2048 } |
|
2049 |
|
2050 /*! |
|
2051 \brief CalenTimeColumn::AddEvent |
|
2052 */ |
|
2053 void CalenTimeColumn::AddEvent(const CalenTimedEventInfo& aEvent) |
|
2054 { |
|
2055 ASSERT( aEvent.iStartSlot < aEvent.iEndSlot ); |
|
2056 ASSERT( CanFitEvent( aEvent ) ); |
|
2057 |
|
2058 if (iEventArray.count() == 0) { |
|
2059 iStartSlot = aEvent.iStartSlot; |
|
2060 } |
|
2061 iEndSlot = aEvent.iEndSlot; |
|
2062 iEventArray.append(aEvent); |
|
2063 } |
|
2064 |
|
2065 /*! |
|
2066 \brief CalenTimeColumn::CanFitEvent |
|
2067 */ |
|
2068 bool CalenTimeColumn::CanFitEvent(const CalenTimedEventInfo& aEvent) |
|
2069 { |
|
2070 return (aEvent.iStartSlot >= iEndSlot) || (iEventArray.count() == 0); |
|
2071 } |
|
2072 |
|
2073 /*! |
|
2074 \brief CalenTimeColumn::ContainsEvent |
|
2075 */ |
|
2076 bool CalenTimeColumn::ContainsEvent(const TCalenInstanceId& aId) |
|
2077 { |
|
2078 bool contains(false); |
|
2079 int eventCount(iEventArray.count()); |
|
2080 for (int i = 0; i < eventCount && !contains; i++) { |
|
2081 if (iEventArray[i].iId == aId) { |
|
2082 contains = true; |
|
2083 } |
|
2084 } |
|
2085 return contains; |
|
2086 } |
|
2087 |
|
2088 /*! |
|
2089 \brief CalenTimeColumn::AddOffset |
|
2090 */ |
|
2091 void CalenTimeColumn::AddOffset(int aOffset, int aPos) |
|
2092 { |
|
2093 if (aOffset != 0) { |
|
2094 CalenSlotInterval::AddOffset(aOffset, aPos); |
|
2095 int eventCount(iEventArray.count()); |
|
2096 for (int i = 0; i < eventCount; i++) { |
|
2097 iEventArray[i].AddOffset(aOffset, aPos); |
|
2098 } |
|
2099 } |
|
2100 } |
|
2101 |
|
2102 /*! |
|
2103 \brief CalenTimeRegion::Close |
|
2104 */ |
|
2105 void CalenTimeRegion::Close() |
|
2106 { |
|
2107 int colCount(iColumns.count()); |
|
2108 for (int i = 0; i < colCount; i++) { |
|
2109 iColumns[i].Close(); |
|
2110 } |
|
2111 iColumns.clear(); |
|
2112 iIntervals.clear(); |
|
2113 } |
|
2114 |
|
2115 /*! |
|
2116 \brief CalenTimeRegion::Overlaps |
|
2117 */ |
|
2118 bool CalenTimeRegion::Overlaps(const CalenSlotInterval& aInterval) const |
|
2119 { |
|
2120 // the base class implementation would be ok, but we might want the assertion here |
|
2121 ASSERT( iColumns.count()> 0 ); |
|
2122 return CalenSlotInterval::Overlaps(aInterval); |
|
2123 } |
|
2124 |
|
2125 /*! |
|
2126 \brief CalenTimeRegion::AddOffset |
|
2127 */ |
|
2128 void CalenTimeRegion::AddOffset(int aOffset, int aPos) |
|
2129 { |
|
2130 if (aOffset != 0) { |
|
2131 CalenSlotInterval::AddOffset(aOffset, aPos); |
|
2132 int colCount(iColumns.count()); |
|
2133 for (int i = 0; i < colCount; i++) { |
|
2134 iColumns[i].AddOffset(aOffset, aPos); |
|
2135 } |
|
2136 int intervalCount(iIntervals.count()); |
|
2137 for (int i = 0; i < intervalCount; i++) { |
|
2138 iIntervals[i].AddOffset(aOffset, aPos); |
|
2139 } |
|
2140 } |
|
2141 |
|
2142 } |
|
2143 |
|
2144 /*! |
|
2145 \brief CalenTimeRegion::AddEvent |
|
2146 */ |
|
2147 void CalenTimeRegion::AddEvent(const CalenTimedEventInfo& aEvent) |
|
2148 { |
|
2149 if (iColumns.count() == 0) { |
|
2150 // This is the first event added to this region |
|
2151 iStartSlot = aEvent.iStartSlot; |
|
2152 iEndSlot = aEvent.iEndSlot; |
|
2153 } |
|
2154 else { |
|
2155 // Check that the events actually are added in the correct order |
|
2156 ASSERT( aEvent.iStartSlot >= iStartSlot ); |
|
2157 ASSERT( aEvent.iStartSlot < iEndSlot ); |
|
2158 |
|
2159 if (aEvent.iEndSlot > iEndSlot) { |
|
2160 iEndSlot = aEvent.iEndSlot; |
|
2161 } |
|
2162 } |
|
2163 |
|
2164 AddInterval(aEvent); |
|
2165 |
|
2166 // If the event fits in one of the existing columns, add it to that one |
|
2167 bool added(false); |
|
2168 int colCount(iColumns.count()); |
|
2169 for (int i = 0; i < colCount && !added; i++) { |
|
2170 if (iColumns[i].CanFitEvent(aEvent)) { |
|
2171 iColumns[i].AddEvent(aEvent); |
|
2172 added = true; |
|
2173 } |
|
2174 } |
|
2175 |
|
2176 if (!added) { |
|
2177 // otherwise create a new column for it |
|
2178 iColumns.append(CalenTimeColumn()); |
|
2179 iColumns[iColumns.count() - 1].AddEvent(aEvent); |
|
2180 } |
|
2181 } |
|
2182 |
|
2183 /*! |
|
2184 \brief CalenTimeRegion::AddInterval |
|
2185 */ |
|
2186 void CalenTimeRegion::AddInterval(const CalenTimedEventInfo& aEvent) |
|
2187 { |
|
2188 /* |
|
2189 * Here are a few examples of different possible cases for this method. |
|
2190 * The first picture of each example shows the initial situation in the |
|
2191 * array, and the new event to be added. The transformations performed |
|
2192 * are shown with a few intermediate steps. |
|
2193 * |
|
2194 * nO = newOverlap, nE = newEvent |
|
2195 * |
|
2196 * Example one: |
|
2197 * |
|
2198 * ------------------ |
|
2199 * | newEvent | |
|
2200 * -------------------------------- |
|
2201 * ... | lastOverlap | tail | |
|
2202 * -------------------------- |
|
2203 * |
|
2204 * -------------- |
|
2205 * | newEvent | |
|
2206 * -------------------------------- |
|
2207 * ... | lastOverlap | tail | |
|
2208 * -------------------------- |
|
2209 * |
|
2210 * -------------- |
|
2211 * | nO | nE | |
|
2212 * -------------------------------- |
|
2213 * ... | lastOverlap | tail | |
|
2214 * -------------------------- |
|
2215 * |
|
2216 * Result: |
|
2217 * -------------------------------- |
|
2218 * ... | lastOverlap | nE | |
|
2219 * -------------------------------- |
|
2220 * |
|
2221 * |
|
2222 * Example two: |
|
2223 * ------------------ |
|
2224 * | newEvent | |
|
2225 * ------------------------------------------- |
|
2226 * ... | lastOverlap | tail | |
|
2227 * ------------------------------- |
|
2228 * |
|
2229 * ------------------ |
|
2230 * | nO | newEvent | |
|
2231 * ------------------------------------------- |
|
2232 * ... | lastOverlap | tail | |
|
2233 * ------------------------------- |
|
2234 * |
|
2235 * Result: |
|
2236 * ------------------------------------------- |
|
2237 * ... | lastOverlap | tail | nO | newEvent | |
|
2238 * ------------------------------------------- |
|
2239 * |
|
2240 * |
|
2241 * Example three: |
|
2242 * -------------- |
|
2243 * | newEvent | |
|
2244 * ----------------------------------------------------- |
|
2245 * ... | lastOverlap | tail | |
|
2246 * ----------------------------------------------------- |
|
2247 * |
|
2248 * -------------- |
|
2249 * | newOverlap | |
|
2250 * ----------------------------------------------------- |
|
2251 * ... | lastOverlap | tail | |
|
2252 * ----------------------------------------------------- |
|
2253 * |
|
2254 * -------------- |
|
2255 * | newOverlap | |
|
2256 * ----------------------------------------------------- |
|
2257 * ... | lastOverlap | tail | | tailPart2 | |
|
2258 * ----------------------------------------------------- |
|
2259 * |
|
2260 * Result: |
|
2261 * ----------------------------------------------------- |
|
2262 * ... | lastOverlap | tail | newOverlap | tailPart2 | |
|
2263 * ----------------------------------------------------- |
|
2264 */ |
|
2265 |
|
2266 // Fill out the new event |
|
2267 CalenEventInterval newEvent; |
|
2268 newEvent.iStartSlot = aEvent.iStartSlot; |
|
2269 newEvent.iEndSlot = aEvent.iEndSlot; |
|
2270 newEvent.iStatus = aEvent.iStatus; |
|
2271 // newEvent.iReplicationStatus = aEvent.iReplicationStatus; |
|
2272 newEvent.iOverlap = false; |
|
2273 |
|
2274 // a pointer to the last interval which is an overlap interval |
|
2275 CalenEventInterval* lastOverlap = NULL; |
|
2276 // If nonempty, this is the last interval after the last overlap |
|
2277 CalenEventInterval tail; |
|
2278 tail.iStartSlot = tail.iEndSlot = 0; |
|
2279 |
|
2280 // Find lastOverlap and tail. |
|
2281 if (iIntervals.count() >= 1) { |
|
2282 // lastInterval is a pointer to the last interval in the array |
|
2283 CalenEventInterval* lastInterval = &iIntervals[iIntervals.count() - 1]; |
|
2284 |
|
2285 // If this is an overlap interval, we haven't got any tail. |
|
2286 if (lastInterval->iOverlap) { |
|
2287 lastOverlap = lastInterval; |
|
2288 } |
|
2289 else { |
|
2290 tail = *lastInterval; |
|
2291 } |
|
2292 |
|
2293 // If there's at least two intervals, and the last one wasn't an overlap, |
|
2294 // the second last one must be an overlap. |
|
2295 if (iIntervals.count() >= 2 && !lastOverlap) { |
|
2296 lastOverlap = &iIntervals[iIntervals.count() - 2]; |
|
2297 ASSERT( lastOverlap->iOverlap ); |
|
2298 } |
|
2299 } |
|
2300 |
|
2301 // If we got a tail, remove it from the array (it will be readded |
|
2302 // at the end if needed) |
|
2303 if (!tail.IsEmpty()) { |
|
2304 iIntervals.removeAt(iIntervals.count() - 1); |
|
2305 } |
|
2306 |
|
2307 CalenEventInterval empty; |
|
2308 if (lastOverlap) { |
|
2309 // Remove the part which already is marked as an overlap |
|
2310 // from the new event. The new event can't start before the |
|
2311 // last overlap starts since events are added in order, therefore |
|
2312 // the second subtraction result interval will remain empty. |
|
2313 newEvent.Subtract(*lastOverlap, empty); |
|
2314 ASSERT( empty.IsEmpty() ); |
|
2315 } |
|
2316 |
|
2317 // Create a new interval, representing the overlap between the old tail |
|
2318 // and the new event |
|
2319 CalenEventInterval newOverlap = newEvent; |
|
2320 newOverlap.iOverlap = true; |
|
2321 newOverlap.Intersect(tail); |
|
2322 |
|
2323 CalenEventInterval tailPart2 = tail; // initialize iOverlap and iStatus from tail |
|
2324 // Remove the new overlap from the old tail, possibly creating two separate intervals. |
|
2325 tail.Subtract(newOverlap, tailPart2); |
|
2326 |
|
2327 // If the subtraction only yielded one single interval, but it's |
|
2328 // after newOverlap, make tailPart2 contain that and make tail empty. |
|
2329 if (tail > newOverlap) { |
|
2330 tailPart2 = tail; |
|
2331 tail.iEndSlot = tail.iStartSlot; |
|
2332 } |
|
2333 |
|
2334 // Remove the new overlap from the new event. Since we already removed the old |
|
2335 // overlap, this subtraction can't produce two intervals either. |
|
2336 newEvent.Subtract(newOverlap, empty); |
|
2337 ASSERT( empty.IsEmpty() ); |
|
2338 |
|
2339 // If the new overlap is adjacent to the old one, expand the old one |
|
2340 // and set the new overlap to be empty. |
|
2341 if (lastOverlap && newOverlap.Adjacent(*lastOverlap)) { |
|
2342 lastOverlap->Union(newOverlap); |
|
2343 newOverlap.iEndSlot = newOverlap.iStartSlot; |
|
2344 } |
|
2345 |
|
2346 // Add all the new intervals, if they're non-empty. |
|
2347 if (!tail.IsEmpty()) { |
|
2348 iIntervals.append(tail); |
|
2349 } |
|
2350 if (!newOverlap.IsEmpty()) { |
|
2351 iIntervals.append(newOverlap); |
|
2352 } |
|
2353 if (!tailPart2.IsEmpty()) { |
|
2354 iIntervals.append(tailPart2); |
|
2355 } |
|
2356 if (!newEvent.IsEmpty()) { |
|
2357 iIntervals.append(newEvent); |
|
2358 } |
|
2359 |
|
2360 } |
|
2361 |
|
2362 // End of File |