kplato

kptcalendar.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 - 2006 Dag Andersen <danders@get2net.dk>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation;
7 version 2 of the License.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "kptcalendar.h"
21#include "kptduration.h"
22#include "kptdatetime.h"
23#include "kptproject.h"
24
25#include <tqdom.h>
26#include <tqptrlist.h>
27
28#include <tdelocale.h>
29#include <kdebug.h>
30
31namespace KPlato
32{
33
35CalendarDay::CalendarDay()
36 : m_date(),
37 m_state(0),
38 m_workingIntervals() {
39
40 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
41 m_workingIntervals.setAutoDelete(true);
42}
43
44CalendarDay::CalendarDay(int state)
45 : m_date(),
46 m_state(state),
47 m_workingIntervals() {
48
49 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
50 m_workingIntervals.setAutoDelete(true);
51}
52
53CalendarDay::CalendarDay(TQDate date, int state)
54 : m_date(date),
55 m_state(state),
56 m_workingIntervals() {
57
58 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
59 m_workingIntervals.setAutoDelete(true);
60}
61
62CalendarDay::CalendarDay(CalendarDay *day)
63 : m_workingIntervals() {
64
65 //kdDebug()<<k_funcinfo<<"("<<this<<") from ("<<day<<")"<<endl;
66 m_workingIntervals.setAutoDelete(true);
67 copy(*day);
68}
69
70CalendarDay::~CalendarDay() {
71 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
72}
73
74const CalendarDay &CalendarDay::copy(const CalendarDay &day) {
75 //kdDebug()<<k_funcinfo<<"("<<&day<<") date="<<day.date().toString()<<endl;
76 m_date = day.date();
77 m_state = day.state();
78 m_workingIntervals.clear();
79 TQPtrListIterator<TQPair<TQTime, TQTime> > it = day.workingIntervals();
80 for(; it.current(); ++it) {
81 m_workingIntervals.append(new TQPair<TQTime, TQTime>(it.current()->first, it.current()->second));
82 }
83 return *this;
84}
85
86bool CalendarDay::load(TQDomElement &element) {
87 //kdDebug()<<k_funcinfo<<endl;
88 bool ok=false;
89 m_state = TQString(element.attribute("state", "-1")).toInt(&ok);
90 if (m_state < 0)
91 return false;
92 //kdDebug()<<k_funcinfo<<" state="<<m_state<<endl;
93 TQString s = element.attribute("date");
94 if (s != "") {
95 m_date = TQDate::fromString(s, TQt::ISODate);
96 if (!m_date.isValid())
97 m_date = TQDate::fromString(s);
98 }
99 clearIntervals();
100 TQDomNodeList list = element.childNodes();
101 for (unsigned int i=0; i<list.count(); ++i) {
102 if (list.item(i).isElement()) {
103 TQDomElement e = list.item(i).toElement();
104 if (e.tagName() == "interval") {
105 //kdDebug()<<k_funcinfo<<"Interval start="<<e.attribute("start")<<" end="<<e.attribute("end")<<endl;
106 TQString st = e.attribute("start");
107 TQString en = e.attribute("end");
108 if (st != "" && en != "") {
109 TQTime start = TQTime::fromString(st);
110 TQTime end = TQTime::fromString(en);
111 addInterval(new TQPair<TQTime, TQTime>(start,end));
112 }
113 }
114 }
115 }
116 return true;
117}
118
119void CalendarDay::save(TQDomElement &element) const {
120 //kdDebug()<<k_funcinfo<<m_date.toString()<<endl;
121 if (m_state == Map::None)
122 return;
123 if (m_date.isValid()) {
124 element.setAttribute("date", m_date.toString(TQt::ISODate));
125 }
126 element.setAttribute("state", m_state);
127 if (m_workingIntervals.count() == 0)
128 return;
129
130 TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
131 for (; it.current(); ++it) {
132 TQDomElement me = element.ownerDocument().createElement("interval");
133 element.appendChild(me);
134 me.setAttribute("end", it.current()->second.toString());
135 me.setAttribute("start", it.current()->first.toString());
136 }
137}
138
139void CalendarDay::addInterval(TQPair<TQTime, TQTime> *interval) {
140 m_workingIntervals.append(interval);
141}
142
143TQTime CalendarDay::startOfDay() const {
144 TQTime t;
145 if (!m_workingIntervals.isEmpty()) {
146 TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
147 t = it.current()->first;
148 for (++it; it.current(); ++it) {
149 if (t > it.current()->first)
150 t = it.current()->first;
151 }
152 }
153 return t;
154}
155
156TQTime CalendarDay::endOfDay() const {
157 TQTime t;
158 if (!m_workingIntervals.isEmpty()) {
159 TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
160 t = it.current()->second;
161 for (++it; it.current(); ++it) {
162 if (t > it.current()->second)
163 t = it.current()->second;
164 }
165 }
166 return t;
167}
168
169bool CalendarDay::operator==(const CalendarDay *day) const {
170 return operator==(*day);
171}
172bool CalendarDay::operator==(const CalendarDay &day) const {
173 //kdDebug()<<k_funcinfo<<endl;
174 if (m_date.isValid() && day.date().isValid()) {
175 if (m_date != day.date()) {
176 //kdDebug()<<k_funcinfo<<m_date.toString()<<" != "<<day.date().toString()<<endl;
177 return false;
178 }
179 } else if (m_date.isValid() != day.date().isValid()) {
180 //kdDebug()<<k_funcinfo<<"one of the dates is not valid"<<endl;
181 return false;
182 }
183 if (m_state != day.state()) {
184 //kdDebug()<<k_funcinfo<<m_state<<" != "<<day.state()<<endl;
185 return false;
186 }
187 if (m_workingIntervals.count() != day.workingIntervals().count()) {
188 //kdDebug()<<k_funcinfo<<m_workingIntervals.count()<<" != "<<day.workingIntervals().count()<<endl;
189 return false;
190 }
191 TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
192 TQPtrListIterator<TQPair<TQTime, TQTime> > dit = day.workingIntervals();
193 for (; it.current(); ++it) {
194 bool res = false;
195 TQPair<TQTime, TQTime> *a = it.current();
196 for (dit.toFirst(); dit.current(); ++dit) {
197 TQPair<TQTime, TQTime> *b = dit.current();
198 if (a->first == b->first && a->second == b->second) {
199 res = true;
200 break;
201 }
202 }
203 if (res == false) {
204 //kdDebug()<<k_funcinfo<<"interval mismatch "<<a->first.toString()<<"-"<<a->second.toString()<<endl;
205 return false;
206 }
207 }
208 return true;
209}
210bool CalendarDay::operator!=(const CalendarDay *day) const {
211 return operator!=(*day);
212}
213bool CalendarDay::operator!=(const CalendarDay &day) const {
214 return !operator==(day);
215}
216
217Duration CalendarDay::effort(const TQTime &start, const TQTime &end) {
218 //kdDebug()<<k_funcinfo<<start.toString()<<" - "<<end.toString()<<endl;
219 Duration eff;
220 if (m_state != Map::Working) {
221 //kdDebug()<<k_funcinfo<<"Non working day"<<endl;
222 return eff;
223 }
224 TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
225 for (; it.current(); ++it) {
226 //kdDebug()<<k_funcinfo<<"Interval: "<<it.current()->first.toString()<<" - "<<it.current()->second.toString()<<endl;
227 if (end > it.current()->first && start < it.current()->second) {
228 DateTime dtStart(TQDate::currentDate(), start);
229 if (start < it.current()->first) {
230 dtStart.setTime(it.current()->first);
231 }
232 DateTime dtEnd(TQDate::currentDate(), end);
233 if (end > it.current()->second) {
234 dtEnd.setTime(it.current()->second);
235 }
236 eff += dtEnd - dtStart;
237 //kdDebug()<<k_funcinfo<<dtStart.time().toString()<<" - "<<dtEnd.time().toString()<<"="<<eff.toString(Duration::Format_Day)<<endl;
238 }
239 }
240 //kdDebug()<<k_funcinfo<<(m_date.isValid()?m_date.toString(TQt::ISODate):"Weekday")<<": "<<start.toString()<<" - "<<end.toString()<<": total="<<eff.toString(Duration::Format_Day)<<endl;
241 return eff;
242}
243
244TQPair<TQTime, TQTime> CalendarDay::interval(const TQTime &start, const TQTime &end) const {
245 //kdDebug()<<k_funcinfo<<endl;
246 TQTime t1, t2;
247 if (m_state == Map::Working) {
248 TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
249 for (; it.current(); ++it) {
250 if (start < it.current()->second && end > it.current()->first) {
251 t1 = start > it.current()->first ? start : it.current()->first;
252 t2 = end < it.current()->second ? end : it.current()->second;
253 //kdDebug()<<k_funcinfo<<t1.toString()<<" to "<<t2.toString()<<endl;
254 return TQPair<TQTime, TQTime>(t1, t2);
255 }
256 }
257 }
258 //kdError()<<k_funcinfo<<"No interval "<<m_date<<": "<<start<<","<<end<<endl;
259 return TQPair<TQTime, TQTime>(t1, t2);
260}
261
262bool CalendarDay::hasInterval() const {
263 return m_state == Map::Working && m_workingIntervals.count() > 0;
264}
265
266bool CalendarDay::hasInterval(const TQTime &start, const TQTime &end) const {
267 //kdDebug()<<k_funcinfo<<(m_date.isValid()?m_date.toString(TQt::ISODate):"Weekday")<<" "<<start.toString()<<" - "<<end.toString()<<endl;
268 if (m_state != Map::Working) {
269 return false;
270 }
271 TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
272 for (; it.current(); ++it) {
273 if (start < it.current()->second && end > it.current()->first) {
274 //kdDebug()<<k_funcinfo<<"true:"<<(m_date.isValid()?m_date.toString(TQt::ISODate):"Weekday")<<" "<<it.current()->first.toString()<<" - "<<it.current()->second.toString()<<endl;
275 return true;
276 }
277 }
278 return false;
279}
280
281Duration CalendarDay::duration() const {
282 Duration dur;
283 TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
284 for (; it.current(); ++it) {
285 DateTime start(TQDate::currentDate(), it.current()->first);
286 DateTime end(TQDate::currentDate(), it.current()->second);
287 dur += end - start;
288 }
289 return dur;
290}
291
293CalendarWeekdays::CalendarWeekdays()
294 : m_weekdays(),
295 m_workHours(40) {
296
297 //kdDebug()<<k_funcinfo<<"--->"<<endl;
298 for (int i=0; i < 7; ++i) {
299 m_weekdays.append(new CalendarDay());
300 }
301 m_weekdays.setAutoDelete(false);
302 //kdDebug()<<k_funcinfo<<"<---"<<endl;
303}
304
305CalendarWeekdays::CalendarWeekdays(CalendarWeekdays *weekdays)
306 : m_weekdays() {
307 //kdDebug()<<k_funcinfo<<"--->"<<endl;
308 copy(*weekdays);
309 //kdDebug()<<k_funcinfo<<"<---"<<endl;
310}
311
312CalendarWeekdays::~CalendarWeekdays() {
313 m_weekdays.setAutoDelete(true);
314 //kdDebug()<<k_funcinfo<<endl;
315}
316
317const CalendarWeekdays &CalendarWeekdays::copy(const CalendarWeekdays &weekdays) {
318 //kdDebug()<<k_funcinfo<<endl;
319 m_weekdays.setAutoDelete(true);
320 m_weekdays.clear();
321 m_weekdays.setAutoDelete(false);
322 TQPtrListIterator<CalendarDay> it = weekdays.weekdays();
323 for (; it.current(); ++it) {
324 m_weekdays.append(new CalendarDay(it.current()));
325 }
326 return *this;
327}
328
329bool CalendarWeekdays::load(TQDomElement &element) {
330 //kdDebug()<<k_funcinfo<<endl;
331 bool ok;
332 int dayNo = TQString(element.attribute("day","-1")).toInt(&ok);
333 if (dayNo < 0 || dayNo > 6) {
334 kdError()<<k_funcinfo<<"Illegal weekday: "<<dayNo<<endl;
335 return true; // we continue anyway
336 }
337 CalendarDay *day = m_weekdays.at(dayNo);
338 if (!day)
339 day = new CalendarDay();
340 if (!day->load(element))
341 day->setState(Map::None);
342 return true;
343}
344
345void CalendarWeekdays::save(TQDomElement &element) const {
346 //kdDebug()<<k_funcinfo<<endl;
347 TQPtrListIterator<CalendarDay> it = m_weekdays;
348 for (int i=0; it.current(); ++it) {
349 TQDomElement me = element.ownerDocument().createElement("weekday");
350 element.appendChild(me);
351 me.setAttribute("day", i++);
352 it.current()->save(me);
353 }
354}
355
356IntMap CalendarWeekdays::map() {
357 IntMap days;
358 for (unsigned int i=0; i < m_weekdays.count(); ++i) {
359 if (m_weekdays.at(i)->state() > 0)
360 days.insert(i+1, m_weekdays.at(i)->state()); //Note: day numbers 1..7
361 }
362 return days;
363}
364
365int CalendarWeekdays::state(const TQDate &date) const {
366 return state(date.dayOfWeek()-1);
367}
368
369int CalendarWeekdays::state(int weekday) const {
370 CalendarDay *day = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(weekday);
371 return day ? day->state() : Map::None;
372}
373
374void CalendarWeekdays::setState(int weekday, int state) {
375 CalendarDay *day = m_weekdays.at(weekday);
376 if (!day)
377 return;
378 day->setState(state);
379}
380
381const TQPtrList<TQPair<TQTime, TQTime> > &CalendarWeekdays::intervals(int weekday) const {
382 CalendarDay *day = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(weekday);
383 Q_ASSERT(day);
384 return day->workingIntervals();
385}
386
387void CalendarWeekdays::setIntervals(int weekday, TQPtrList<TQPair<TQTime, TQTime> >intervals) {
388 CalendarDay *day = m_weekdays.at(weekday);
389 if (day)
390 day->setIntervals(intervals);
391}
392
393void CalendarWeekdays::clearIntervals(int weekday) {
394 CalendarDay *day = m_weekdays.at(weekday);
395 if (day)
396 day->clearIntervals();
397}
398
399bool CalendarWeekdays::operator==(const CalendarWeekdays *wd) const {
400 if (m_weekdays.count() != wd->weekdays().count())
401 return false;
402 for (unsigned int i=0; i < m_weekdays.count(); ++i) {
403 // is there a better way to get around this const stuff?
404 CalendarDay *day1 = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(i);
405 CalendarDay *day2 = const_cast<TQPtrList<CalendarDay>&>(wd->weekdays()).at(i);
406 if (day1 != day2)
407 return false;
408 }
409 return true;
410}
411bool CalendarWeekdays::operator!=(const CalendarWeekdays *wd) const {
412 if (m_weekdays.count() != wd->weekdays().count())
413 return true;
414 for (unsigned int i=0; i < m_weekdays.count(); ++i) {
415 // is there a better way to get around this const stuff?
416 CalendarDay *day1 = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(i);
417 CalendarDay *day2 = const_cast<TQPtrList<CalendarDay>&>(wd->weekdays()).at(i);
418 if (day1 != day2)
419 return true;
420 }
421 return false;
422}
423
424Duration CalendarWeekdays::effort(const TQDate &date, const TQTime &start, const TQTime &end) {
425 //kdDebug()<<k_funcinfo<<"Day of week="<<date.dayOfWeek()-1<<endl;
426 CalendarDay *day = weekday(date.dayOfWeek()-1);
427 if (day && day->state() == Map::Working) {
428 return day->effort(start, end);
429 }
430 return Duration::zeroDuration;
431}
432
433TQPair<TQTime, TQTime> CalendarWeekdays::interval(const TQDate date, const TQTime &start, const TQTime &end) const {
434 //kdDebug()<<k_funcinfo<<endl;
435 CalendarDay *day = weekday(date.dayOfWeek()-1);
436 if (day && day->state() == Map::Working) {
437 if (day->hasInterval(start, end)) {
438 return day->interval(start, end);
439 }
440 }
441 return TQPair<TQTime, TQTime>(TQTime(), TQTime());
442}
443
444bool CalendarWeekdays::hasInterval(const TQDate date, const TQTime &start, const TQTime &end) const {
445 //kdDebug()<<k_funcinfo<<date.toString()<<": "<<start.toString()<<" - "<<end.toString()<<endl;
446 CalendarDay *day = weekday(date.dayOfWeek()-1);
447 return day && day->hasInterval(start, end);
448}
449
450bool CalendarWeekdays::hasInterval() const {
451 //kdDebug()<<k_funcinfo<<endl;
452 TQPtrListIterator<CalendarDay> it = m_weekdays;
453 for (; it.current(); ++it) {
454 if (it.current()->hasInterval())
455 return true;
456 }
457 return false;
458}
459
460CalendarDay *CalendarWeekdays::weekday(int day) const {
461 TQPtrListIterator<CalendarDay> it = m_weekdays;
462 for (int i=0; it.current(); ++it, ++i) {
463 if (i == day)
464 return it.current();
465 }
466 return 0;
467}
468
469Duration CalendarWeekdays::duration() const {
470 Duration dur;
471 TQPtrListIterator<CalendarDay> it = m_weekdays;
472 for (; it.current(); ++it) {
473 dur += it.current()->duration();
474 }
475 return dur;
476}
477
478Duration CalendarWeekdays::duration(int _weekday) const {
479 CalendarDay *day = weekday(_weekday);
480 if (day)
481 return day->duration();
482 return Duration();
483}
484
485TQTime CalendarWeekdays::startOfDay(int _weekday) const {
486 CalendarDay *day = weekday(_weekday);
487 if (day)
488 return day->startOfDay();
489 return TQTime();
490}
491
492TQTime CalendarWeekdays::endOfDay(int _weekday) const {
493 CalendarDay *day = weekday(_weekday);
494 if (day)
495 return day->endOfDay();
496 return TQTime();
497}
498
499
501
502Calendar::Calendar()
503 : m_parent(0),
504 m_project(0),
505 m_deleted(false) {
506
507 init();
508}
509
510Calendar::Calendar(TQString name, Calendar *parent)
511 : m_name(name),
512 m_parent(parent),
513 m_project(0),
514 m_deleted(false),
515 m_days() {
516
517 init();
518}
519
520Calendar::~Calendar() {
521 //kdDebug()<<k_funcinfo<<"deleting "<<m_name<<endl;
522 removeId();
523 delete m_weekdays;
524}
525Calendar::Calendar(Calendar *calendar)
526 : m_project(0),
527 m_days() {
528 m_days.setAutoDelete(true);
529 copy(*calendar);
530}
531
532const Calendar &Calendar::copy(Calendar &calendar) {
533 m_name = calendar.name();
534 m_parent = calendar.parent();
535 m_deleted = calendar.isDeleted();
536 m_id = calendar.id();
537
538 TQPtrListIterator<CalendarDay> it = calendar.days();
539 for (; it.current(); ++it) {
540 m_days.append(new CalendarDay(it.current()));
541 }
542 m_weekdays = new CalendarWeekdays(calendar.weekdays());
543 return *this;
544}
545
546void Calendar::init() {
547 m_days.setAutoDelete(true);
548 m_weekdays = new CalendarWeekdays();
549}
550
551void Calendar::setProject(Project *project) {
552 m_project = project;
553 generateId();
554}
555
556void Calendar::setDeleted(bool yes) {
557 if (yes) {
558 removeId();
559 } else {
560 setId(m_id);
561 }
562 m_deleted = yes;
563}
564bool Calendar::setId(TQString id) {
565 //kdDebug()<<k_funcinfo<<id<<endl;
566 if (id.isEmpty()) {
567 kdError()<<k_funcinfo<<"id is empty"<<endl;
568 m_id = id;
569 return false;
570 }
571 Calendar *c = findCalendar();
572 if (c == this) {
573 kdDebug()<<k_funcinfo<<"My id found, remove it"<<endl;
574 removeId();
575 } else if (c) {
576 //can happen when making a copy
577 kdError()<<k_funcinfo<<"My id '"<<m_id<<"' already used for different node: "<<c->name()<<endl;
578 }
579 if (findCalendar(id)) {
580 kdError()<<k_funcinfo<<"id '"<<id<<"' is already used for different node: "<<findCalendar(id)->name()<<endl;
581 m_id = TQString(); // hmmm
582 return false;
583 }
584 m_id = id;
585 insertId(id);
586 //kdDebug()<<k_funcinfo<<m_name<<": inserted id="<<id<<endl;
587 return true;
588}
589
590void Calendar::generateId() {
591 if (!m_id.isEmpty()) {
592 removeId();
593 }
594 for (int i=0; i<32000 ; ++i) {
595 m_id = m_id.setNum(i);
596 if (!findCalendar()) {
597 insertId(m_id);
598 return;
599 }
600 }
601 m_id = TQString();
602}
603
604bool Calendar::load(TQDomElement &element) {
605 //kdDebug()<<k_funcinfo<<element.text()<<endl;
606 //bool ok;
607 setId(element.attribute("id"));
608 m_parentId = element.attribute("parent");
609 m_name = element.attribute("name","");
610 //TODO parent
611
612 TQDomNodeList list = element.childNodes();
613 for (unsigned int i=0; i<list.count(); ++i) {
614 if (list.item(i).isElement()) {
615 TQDomElement e = list.item(i).toElement();
616 if (e.tagName() == "weekday") {
617 if (!m_weekdays->load(e))
618 return false;
619 }
620 if (e.tagName() == "day") {
621 CalendarDay *day = new CalendarDay();
622 if (day->load(e)) {
623 if (!day->date().isValid()) {
624 delete day;
625 kdError()<<k_funcinfo<<m_name<<": Failed to load calendarDay - Invalid date"<<endl;
626 } else {
627 CalendarDay *d = findDay(day->date());
628 if (d) {
629 // already exists, keep the new
630 removeDay(d);
631 kdWarning()<<k_funcinfo<<m_name<<" Load calendarDay - Date already exists"<<endl;
632 }
633 addDay(day);
634 }
635 } else {
636 delete day;
637 kdError()<<k_funcinfo<<"Failed to load calendarDay"<<endl;
638 return true; //false; don't throw away the whole calendar
639 }
640 }
641 }
642 }
643 return true;
644}
645
646void Calendar::save(TQDomElement &element) const {
647 //kdDebug()<<k_funcinfo<<m_name<<endl;
648 if (m_deleted)
649 return;
650
651 TQDomElement me = element.ownerDocument().createElement("calendar");
652 element.appendChild(me);
653 if (m_parent && !m_parent->isDeleted())
654 me.setAttribute("parent", m_parent->id());
655 me.setAttribute("name", m_name);
656 me.setAttribute("id", m_id);
657 m_weekdays->save(me);
658 TQPtrListIterator<CalendarDay> it = m_days;
659 for (; it.current(); ++it) {
660 TQDomElement e = me.ownerDocument().createElement("day");
661 me.appendChild(e);
662 it.current()->save(e);
663 }
664
665}
666
667CalendarDay *Calendar::findDay(const TQDate &date, bool skipNone) const {
668 //kdDebug()<<k_funcinfo<<date.toString()<<endl;
669 TQPtrListIterator<CalendarDay> it = m_days;
670 for (; it.current(); ++it) {
671 if (it.current()->date() == date) {
672 if (skipNone && it.current()->state() == Map::None) {
673 continue; // hmmm, break?
674 }
675 return it.current();
676 }
677 }
678 //kdDebug()<<k_funcinfo<<date.toString()<<" not found"<<endl;
679 return 0;
680}
681
682bool Calendar::hasParent(Calendar *cal) {
683 //kdDebug()<<k_funcinfo<<endl;
684 if (!m_parent)
685 return false;
686 if (m_parent == cal)
687 return true;
688 return m_parent->hasParent(cal);
689}
690
691Duration Calendar::effort(const TQDate &date, const TQTime &start, const TQTime &end) const {
692 //kdDebug()<<k_funcinfo<<m_name<<": "<<date.toString(TQt::ISODate)<<" "<<start.toString()<<" - "<<end.toString()<<endl;
693 if (start == end) {
695 }
696 TQTime _start = start;
697 TQTime _end = end;
698 if (start > end) {
699 _start = end;
700 _end = start;
701 }
702 // first, check my own day
703 CalendarDay *day = findDay(date, true);
704 if (day) {
705 if (day->state() == Map::Working) {
706 return day->effort(_start, _end);
707 } else if (day->state() == Map::NonWorking) {
709 } else {
710 kdError()<<k_funcinfo<<"Invalid state: "<<day->state()<<endl;
712 }
713 }
714 // check my own weekdays
715 if (m_weekdays) {
716 if (m_weekdays->state(date) == Map::Working) {
717 return m_weekdays->effort(date, _start, _end);
718 }
719 if (m_weekdays->state(date) == Map::NonWorking) {
721 }
722 }
723 if (m_parent && !m_parent->isDeleted()) {
724 return m_parent->effort(date, start, end);
725 }
726 // Check default calendar
727 return project()->defaultCalendar()->effort(date, start, end);
728}
729
730Duration Calendar::effort(const DateTime &start, const DateTime &end) const {
731 //kdDebug()<<k_funcinfo<<m_name<<": "<<start<<" to "<<end<<endl;
732 Duration eff;
733 if (!start.isValid() || !end.isValid() || end <= start) {
734 return eff;
735 }
736 TQDate date = start.date();
737 TQTime startTime = start.time();
738 TQTime endTime = end.time();
739 if (end.date() > date) {
740 endTime.setHMS(23, 59, 59, 999);
741 }
742 eff = effort(date, startTime, endTime); // first day
743 // Now get all the rest of the days
744 for (date = date.addDays(1); date <= end.date(); date = date.addDays(1)) {
745 if (date < end.date())
746 eff += effort(date, TQTime(), endTime); // whole days
747 else
748 eff += effort(date, TQTime(), end.time()); // last day
749 //kdDebug()<<k_funcinfo<<": eff now="<<eff.toString(Duration::Format_Day)<<endl;
750 }
751 //kdDebug()<<k_funcinfo<<start.date().toString()<<"- "<<end.date().toString()<<": total="<<eff.toString(Duration::Format_Day)<<endl;
752 return eff;
753}
754
755
756TQPair<TQTime, TQTime> Calendar::firstInterval(const TQDate &date, const TQTime &startTime, const TQTime &endTime) const {
757 CalendarDay *day = findDay(date, true);
758 if (day) {
759 return day->interval(startTime, endTime);
760 }
761 if (m_weekdays) {
762 if (m_weekdays->state(date) == Map::Working) {
763 return m_weekdays->interval(date, startTime, endTime);
764 }
765 if (m_weekdays->state(date) == Map::NonWorking) {
766 return TQPair<TQTime, TQTime>(TQTime(), TQTime());
767 }
768 }
769 if (m_parent && !m_parent->isDeleted()) {
770 return m_parent->firstInterval(date, startTime, endTime);
771 }
772 return project()->defaultCalendar()->firstInterval(date, startTime, endTime);
773}
774
775TQPair<DateTime, DateTime> Calendar::firstInterval(const DateTime &start, const DateTime &end) const {
776 //kdDebug()<<k_funcinfo<<start.toString()<<" - "<<end.toString()<<endl;
777 if (!start.isValid()) {
778 kdWarning()<<k_funcinfo<<"Invalid start time"<<endl;
779 return TQPair<DateTime, DateTime>(DateTime(), DateTime());
780 }
781 if (!end.isValid()) {
782 kdWarning()<<k_funcinfo<<"Invalid end time"<<endl;
783 return TQPair<DateTime, DateTime>(DateTime(), DateTime());
784 }
785 TQTime startTime;
786 TQTime endTime;
787 TQDate date = start.date();
788 int i=0;
789 for (; date <= end.date(); date = date.addDays(1)) {
790 if (date < end.date())
791 endTime = TQTime(23, 59, 59, 999);
792 else
793 endTime = end.time();
794 if (date > start.date())
795 startTime = TQTime();
796 else
797 startTime = start.time();
798
799 TQPair<TQTime, TQTime> res = firstInterval(date, startTime, endTime);
800 if (res.first < res.second) {
801 return TQPair<DateTime, DateTime>(DateTime(date,res.first),DateTime(date, res.second));
802 }
803 }
804 //kdError()<<k_funcinfo<<"Didn't find an interval ("<<start<<", "<<end<<")"<<endl;
805 return TQPair<DateTime, DateTime>(DateTime(), DateTime());
806}
807
808
809bool Calendar::hasInterval(const TQDate &date, const TQTime &startTime, const TQTime &endTime) const {
810 CalendarDay *day = findDay(date, true);
811 if (day) {
812 //kdDebug()<<k_funcinfo<<m_name<<" "<<date<<": "<<startTime<<" to "<<endTime<<endl;
813 return day->hasInterval(startTime, endTime);
814 }
815 if (m_weekdays) {
816 if (m_weekdays->state(date) == Map::Working) {
817 return m_weekdays->hasInterval(date, startTime, endTime);
818 } else if (m_weekdays->state(date) == Map::NonWorking) {
819 return false;
820 }
821 }
822 if (m_parent && !m_parent->isDeleted()) {
823 return m_parent->hasInterval(date, startTime, endTime);
824 }
825 return project()->defaultCalendar()->hasInterval(date, startTime, endTime);
826}
827
828bool Calendar::hasInterval(const DateTime &start, const DateTime &end) const {
829 //kdDebug()<<k_funcinfo<<m_name<<": "<<start<<" - "<<end<<endl;
830 if (!start.isValid() || !end.isValid() || end <= start) {
831 //kdError()<<k_funcinfo<<"Invalid input: "<<(start.isValid()?"":"(start invalid) ")<<(end.isValid()?"":"(end invalid) ")<<(start>end?"":"(start<=end)")<<endl;
832 //kdDebug()<<kdBacktrace(8)<<endl;
833 return false;
834 }
835 TQTime startTime;
836 TQTime endTime;
837 TQDate date = start.date();
838 for (; date <= end.date(); date = date.addDays(1)) {
839 if (date < end.date())
840 endTime = TQTime(23, 59, 59, 999);
841 else
842 endTime = end.time();
843 if (date > start.date())
844 startTime = TQTime();
845 else
846 startTime = start.time();
847
848 if (hasInterval(date, startTime, endTime))
849 return true;
850 }
851 return false;
852}
853
855 //kdDebug()<<k_funcinfo<<m_name<<": check from "<<time.toString()<<" limit="<<limit.toString()<<endl;
856 if (!time.isValid() || !limit.isValid() || time >= limit) {
857 kdError()<<k_funcinfo<<"Invalid input: "<<(time.isValid()?"":"(time invalid) ")<<(limit.isValid()?"":"(limit invalid) ")<<(time>limit?"":"(time>=limit)")<<endl;
858 return DateTime();
859 }
860 if (!hasInterval(time, limit)) {
861 return DateTime();
862 }
863 DateTime t = firstInterval(time, limit).first;
864 //kdDebug()<<k_funcinfo<<m_name<<": "<<t.toString()<<endl;
865 return t;
866}
867
869 //kdDebug()<<k_funcinfo<<m_name<<": check from "<<time.toString()<<" limit="<<limit.toString()<<endl;
870 if (!time.isValid() || !limit.isValid() || time <= limit) {
871 kdError()<<k_funcinfo<<"Invalid input: "<<(time.isValid()?"":"(time invalid) ")<<(limit.isValid()?"":"(limit invalid) ")<<(time>limit?"":"(time<=limit)")<<endl;
872 return DateTime();
873 }
874 DateTime lmt = time;
875 DateTime t = DateTime(time.date()); // start of first day
876 if (t == lmt)
877 t = TQDateTime(t.addDays(-1)); // in case time == start of day
878 if (t < limit)
879 t = limit; // always stop at limit (lower boundary)
880 DateTime res;
881 //kdDebug()<<k_funcinfo<<m_name<<": t="<<t<<", "<<lmt<<" limit="<<limit<<endl;
882 while (!res.isValid() && t >= limit) {
883 // check intervals for 1 day
884 DateTime r = firstInterval(t, lmt).second;
885 res = r;
886 // Find the last interval
887 while(r.isValid() && r < lmt) {
888 r = firstInterval(r, lmt).second;
889 if (r.isValid())
890 res = r;
891 //kdDebug()<<k_funcinfo<<m_name<<": r="<<r<<", "<<lmt<<" res="<<res<<endl;
892 }
893 if (!res.isValid()) {
894 if (t == limit) {
895 break;
896 }
897 lmt = t;
898 t = TQDateTime(t.addDays(-1));
899 if (t < limit) {
900 t = limit;
901 }
902 if (t == lmt)
903 break;
904 }
905 }
906 //kdDebug()<<k_funcinfo<<m_name<<": "<<res<<endl;
907 return res;
908}
909
910Calendar *Calendar::findCalendar(const TQString &id) const {
911 return (m_project ? m_project->findCalendar(id) : 0);
912}
913
914bool Calendar::removeId(const TQString &id) {
915 return (m_project ? m_project->removeCalendarId(id) : false);
916}
917
918void Calendar::insertId(const TQString &id){
919 if (m_project)
920 m_project->insertCalendarId(id, this);
921}
922
924StandardWorktime::StandardWorktime() {
925 init();
926}
927
928StandardWorktime::StandardWorktime(StandardWorktime *worktime) {
929 if (worktime) {
930 m_year = worktime->durationYear();
931 m_month = worktime->durationMonth();
932 m_week = worktime->durationWeek();
933 m_day = worktime->durationDay();
934 m_calendar = new Calendar(*(worktime->calendar()));
935 } else {
936 init();
937 }
938}
939
940StandardWorktime::~StandardWorktime() {
941 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
942}
943
944void StandardWorktime::init() {
945 // Some sane default values
946 m_year = Duration(0, 1760, 0);
947 m_month = Duration(0, 176, 0);
948 m_week = Duration(0, 40, 0);
949 m_day = Duration(0, 8, 0);
950 m_calendar = new Calendar;
951 m_calendar->setName(i18n("Base"));
952 TQPair<TQTime, TQTime> t = TQPair<TQTime, TQTime>(TQTime(8,0,0), TQTime(16,0,0));
953 for (int i=0; i < 5; ++i) {
954 m_calendar->weekday(i)->addInterval(t);
955 m_calendar->weekday(i)->setState(Map::Working);
956 }
957 m_calendar->weekday(5)->setState(Map::NonWorking);
958 m_calendar->weekday(6)->setState(Map::NonWorking);
959}
960
961bool StandardWorktime::load(TQDomElement &element) {
962 //kdDebug()<<k_funcinfo<<endl;
963 m_year = Duration::fromString(element.attribute("year"), Duration::Format_Hour);
964 m_month = Duration::fromString(element.attribute("month"), Duration::Format_Hour);
965 m_week = Duration::fromString(element.attribute("week"), Duration::Format_Hour);
966 m_day = Duration::fromString(element.attribute("day"), Duration::Format_Hour);
967
968 TQDomNodeList list = element.childNodes();
969 for (unsigned int i=0; i<list.count(); ++i) {
970 if (list.item(i).isElement()) {
971 TQDomElement e = list.item(i).toElement();
972 if (e.tagName() == "calendar") {
973 delete m_calendar;
974 m_calendar = new Calendar;
975 m_calendar->load(e);
976 }
977 }
978 }
979 return true;
980}
981
982void StandardWorktime::save(TQDomElement &element) const {
983 //kdDebug()<<k_funcinfo<<endl;
984 TQDomElement me = element.ownerDocument().createElement("standard-worktime");
985 element.appendChild(me);
986 me.setAttribute("year", m_year.toString(Duration::Format_Hour));
987 me.setAttribute("month", m_month.toString(Duration::Format_Hour));
988 me.setAttribute("week", m_week.toString(Duration::Format_Hour));
989 me.setAttribute("day", m_day.toString(Duration::Format_Hour));
990
991 m_calendar->save(me);
992}
993
994#ifndef NDEBUG
995void CalendarDay::printDebug(TQCString indent) {
996 TQString s[] = {"None", "Non-working", "Working"};
997 kdDebug()<<indent<<" "<<m_date.toString()<<" = "<<s[m_state]<<endl;
998 if (m_state == Map::Working) {
999 indent += " ";
1000 TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
1001 for (; it.current(); ++it) {
1002 kdDebug()<<indent<<" Interval: "<<it.current()->first<<" to "<<it.current()->second<<endl;
1003 }
1004 }
1005
1006}
1007void CalendarWeekdays::printDebug(TQCString indent) {
1008 kdDebug()<<indent<<"Weekdays ------"<<endl;
1009 TQPtrListIterator<CalendarDay> it = m_weekdays;
1010 for (char c='0'; it.current(); ++it) {
1011 it.current()->printDebug(indent + " Day " + c++ + ": ");
1012 }
1013
1014}
1015void Calendar::printDebug(TQCString indent) {
1016 kdDebug()<<indent<<"Calendar "<<m_id<<": '"<<m_name<<"' Deleted="<<m_deleted<<endl;
1017 kdDebug()<<indent<<" Parent: "<<(m_parent ? m_parent->name() : "No parent")<<endl;
1018 m_weekdays->printDebug(indent + " ");
1019 kdDebug()<<indent<<" Days --------"<<endl;
1020 TQPtrListIterator<CalendarDay> it = m_days;
1021 for (; it.current(); ++it) {
1022 it.current()->printDebug(indent + " ");
1023 }
1024}
1025
1026void StandardWorktime::printDebug(TQCString indent) {
1027 kdDebug()<<indent<<"StandardWorktime "<<endl;
1028 kdDebug()<<indent<<"Year: "<<m_year.toString()<<endl;
1029 kdDebug()<<indent<<"Month: "<<m_month.toString()<<endl;
1030 kdDebug()<<indent<<"Week: "<<m_week.toString()<<endl;
1031 kdDebug()<<indent<<"Day: "<<m_day.toString()<<endl;
1032}
1033
1034#endif
1035
1036} //KPlato namespace
Calendar defines the working and nonworking days and hours.
CalendarDay * findDay(const TQDate &date, bool skipUndefined=false) const
Find the definition for the day date.
TQPair< DateTime, DateTime > firstInterval(const DateTime &start, const DateTime &end) const
Returns the first 'work interval' for the interval starting at start and ending at end.
bool hasInterval(const DateTime &start, const DateTime &end) const
Returns true if at least a part of a 'work interval' exists for the interval starting at start and en...
DateTime firstAvailableAfter(const DateTime &time, const DateTime &limit)
Find the first available time after time before limit.
Duration effort(const TQDate &date, const TQTime &start, const TQTime &end) const
Returns the amount of 'worktime' that can be done on the date date between the times start and end.
DateTime firstAvailableBefore(const DateTime &time, const DateTime &limit)
Find the first available time backwards from time.
DateTime is a TQDateTime which knows about Duration.
Definition kptdatetime.h:33
The duration class can be used to store a timespan in a convenient format.
Definition kptduration.h:34
static const Duration zeroDuration
This is useful for occasions where we need a zero duration.