kplato

kptcalendar.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 - 2006 Dag Andersen <danders@get2net.dk>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation;
00007    version 2 of the License.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kptcalendar.h"
00021 #include "kptduration.h"
00022 #include "kptdatetime.h"
00023 #include "kptproject.h"
00024 
00025 #include <qdom.h>
00026 #include <qptrlist.h>
00027 
00028 #include <klocale.h>
00029 #include <kdebug.h>
00030 
00031 namespace KPlato
00032 {
00033 
00035 CalendarDay::CalendarDay()
00036     : m_date(),
00037       m_state(0),
00038       m_workingIntervals() {
00039 
00040     //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00041     m_workingIntervals.setAutoDelete(true);
00042 }
00043 
00044 CalendarDay::CalendarDay(int state)
00045     : m_date(),
00046       m_state(state),
00047       m_workingIntervals() {
00048 
00049     //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00050     m_workingIntervals.setAutoDelete(true);
00051 }
00052 
00053 CalendarDay::CalendarDay(QDate date, int state)
00054     : m_date(date),
00055       m_state(state),
00056       m_workingIntervals() {
00057 
00058     //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00059     m_workingIntervals.setAutoDelete(true);
00060 }
00061 
00062 CalendarDay::CalendarDay(CalendarDay *day)
00063     : m_workingIntervals() {
00064 
00065     //kdDebug()<<k_funcinfo<<"("<<this<<") from ("<<day<<")"<<endl;
00066     m_workingIntervals.setAutoDelete(true);
00067     copy(*day);
00068 }
00069 
00070 CalendarDay::~CalendarDay() {
00071     //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00072 }
00073 
00074 const CalendarDay &CalendarDay::copy(const CalendarDay &day) {
00075     //kdDebug()<<k_funcinfo<<"("<<&day<<") date="<<day.date().toString()<<endl;
00076     m_date = day.date();
00077     m_state = day.state();
00078     m_workingIntervals.clear();
00079     QPtrListIterator<QPair<QTime, QTime> > it = day.workingIntervals();
00080     for(; it.current(); ++it) {
00081         m_workingIntervals.append(new QPair<QTime, QTime>(it.current()->first, it.current()->second));
00082     }
00083     return *this;
00084 }
00085 
00086 bool CalendarDay::load(QDomElement &element) {
00087     //kdDebug()<<k_funcinfo<<endl;
00088     bool ok=false;
00089     m_state = QString(element.attribute("state", "-1")).toInt(&ok);
00090     if (m_state < 0)
00091         return false;
00092     //kdDebug()<<k_funcinfo<<" state="<<m_state<<endl;
00093     QString s = element.attribute("date");
00094     if (s != "") {
00095         m_date = QDate::fromString(s, Qt::ISODate);
00096         if (!m_date.isValid())
00097             m_date = QDate::fromString(s);
00098     }
00099     clearIntervals();
00100     QDomNodeList list = element.childNodes();
00101     for (unsigned int i=0; i<list.count(); ++i) {
00102         if (list.item(i).isElement()) {
00103             QDomElement e = list.item(i).toElement();
00104             if (e.tagName() == "interval") {
00105                 //kdDebug()<<k_funcinfo<<"Interval start="<<e.attribute("start")<<" end="<<e.attribute("end")<<endl;
00106                 QString st = e.attribute("start");
00107                 QString en = e.attribute("end");
00108                 if (st != "" && en != "") {
00109                     QTime start = QTime::fromString(st);
00110                     QTime end = QTime::fromString(en);
00111                     addInterval(new QPair<QTime, QTime>(start,end));
00112                 }
00113             }
00114         }
00115     }
00116     return true;
00117 }
00118 
00119 void CalendarDay::save(QDomElement &element) const {
00120     //kdDebug()<<k_funcinfo<<m_date.toString()<<endl;
00121     if (m_state == Map::None)
00122         return;
00123     if (m_date.isValid()) {
00124         element.setAttribute("date", m_date.toString(Qt::ISODate));
00125     }
00126     element.setAttribute("state", m_state);
00127     if (m_workingIntervals.count() == 0)
00128         return;
00129     
00130     QPtrListIterator<QPair<QTime, QTime> > it = m_workingIntervals;
00131     for (; it.current(); ++it) {
00132         QDomElement me = element.ownerDocument().createElement("interval");
00133         element.appendChild(me);
00134         me.setAttribute("end", it.current()->second.toString());
00135         me.setAttribute("start", it.current()->first.toString());
00136     }
00137 } 
00138 
00139 void CalendarDay::addInterval(QPair<QTime, QTime> *interval) {
00140     m_workingIntervals.append(interval);
00141 }
00142 
00143 QTime CalendarDay::startOfDay() const {
00144     QTime t;
00145     if (!m_workingIntervals.isEmpty()) {
00146         QPtrListIterator<QPair<QTime, QTime> > it = m_workingIntervals;
00147         t = it.current()->first;
00148         for (++it; it.current(); ++it) {
00149             if (t > it.current()->first)
00150                 t = it.current()->first;
00151         }
00152     }
00153     return t;
00154 }
00155 
00156 QTime CalendarDay::endOfDay() const {
00157     QTime t;
00158     if (!m_workingIntervals.isEmpty()) {
00159         QPtrListIterator<QPair<QTime, QTime> > it = m_workingIntervals;
00160         t = it.current()->second;
00161         for (++it; it.current(); ++it) {
00162             if (t > it.current()->second)
00163                 t = it.current()->second;
00164         }
00165     }
00166     return t;
00167 }
00168     
00169 bool CalendarDay::operator==(const CalendarDay *day) const {
00170     return operator==(*day);
00171 }
00172 bool CalendarDay::operator==(const CalendarDay &day) const {
00173     //kdDebug()<<k_funcinfo<<endl;
00174     if (m_date.isValid() && day.date().isValid()) {
00175         if (m_date != day.date()) {
00176             //kdDebug()<<k_funcinfo<<m_date.toString()<<" != "<<day.date().toString()<<endl;
00177             return false;
00178         }
00179     } else if (m_date.isValid() != day.date().isValid()) {
00180         //kdDebug()<<k_funcinfo<<"one of the dates is not valid"<<endl;
00181         return false;
00182     }
00183     if (m_state != day.state()) {
00184         //kdDebug()<<k_funcinfo<<m_state<<" != "<<day.state()<<endl;
00185         return false;
00186     }
00187     if (m_workingIntervals.count() != day.workingIntervals().count()) {
00188         //kdDebug()<<k_funcinfo<<m_workingIntervals.count()<<" != "<<day.workingIntervals().count()<<endl;
00189         return false;
00190     }
00191     QPtrListIterator<QPair<QTime, QTime> > it = m_workingIntervals;
00192     QPtrListIterator<QPair<QTime, QTime> > dit = day.workingIntervals();
00193     for (; it.current(); ++it) {
00194         bool res = false;
00195         QPair<QTime, QTime> *a = it.current();
00196         for (dit.toFirst(); dit.current(); ++dit) {
00197             QPair<QTime, QTime> *b = dit.current();
00198             if (a->first == b->first && a->second == b->second) {
00199                 res = true;
00200                 break;
00201             }
00202         }
00203         if (res == false) {
00204             //kdDebug()<<k_funcinfo<<"interval mismatch "<<a->first.toString()<<"-"<<a->second.toString()<<endl;
00205             return false;
00206         }
00207     }
00208     return true;
00209 }
00210 bool CalendarDay::operator!=(const CalendarDay *day) const {
00211     return operator!=(*day);
00212 }
00213 bool CalendarDay::operator!=(const CalendarDay &day) const {
00214     return !operator==(day);
00215 }
00216 
00217 Duration CalendarDay::effort(const QTime &start, const QTime &end) {
00218     //kdDebug()<<k_funcinfo<<start.toString()<<" - "<<end.toString()<<endl;
00219     Duration eff;
00220     if (m_state != Map::Working) {
00221         //kdDebug()<<k_funcinfo<<"Non working day"<<endl;
00222         return eff;
00223     }
00224     QPtrListIterator<QPair<QTime, QTime> > it = m_workingIntervals;
00225     for (; it.current(); ++it) {
00226         //kdDebug()<<k_funcinfo<<"Interval: "<<it.current()->first.toString()<<" - "<<it.current()->second.toString()<<endl;
00227         if (end > it.current()->first && start < it.current()->second) {
00228             DateTime dtStart(QDate::currentDate(), start);
00229             if (start < it.current()->first) {
00230                 dtStart.setTime(it.current()->first);
00231             }
00232             DateTime dtEnd(QDate::currentDate(), end);
00233             if (end > it.current()->second) {
00234                 dtEnd.setTime(it.current()->second);
00235             }
00236             eff += dtEnd - dtStart;
00237             //kdDebug()<<k_funcinfo<<dtStart.time().toString()<<" - "<<dtEnd.time().toString()<<"="<<eff.toString(Duration::Format_Day)<<endl;
00238         }
00239     }
00240     //kdDebug()<<k_funcinfo<<(m_date.isValid()?m_date.toString(Qt::ISODate):"Weekday")<<": "<<start.toString()<<" - "<<end.toString()<<": total="<<eff.toString(Duration::Format_Day)<<endl;
00241     return eff;
00242 }
00243 
00244 QPair<QTime, QTime> CalendarDay::interval(const QTime &start, const QTime &end) const {
00245     //kdDebug()<<k_funcinfo<<endl;
00246     QTime t1, t2;
00247     if (m_state == Map::Working) {
00248         QPtrListIterator<QPair<QTime, QTime> > it = m_workingIntervals;
00249         for (; it.current(); ++it) {
00250             if (start < it.current()->second && end > it.current()->first) {
00251                 t1 = start > it.current()->first ? start : it.current()->first;
00252                 t2 = end < it.current()->second ? end : it.current()->second;
00253                 //kdDebug()<<k_funcinfo<<t1.toString()<<" to "<<t2.toString()<<endl;
00254                 return QPair<QTime, QTime>(t1, t2);
00255             }
00256         }
00257     }
00258     //kdError()<<k_funcinfo<<"No interval "<<m_date<<": "<<start<<","<<end<<endl;
00259     return QPair<QTime, QTime>(t1, t2);
00260 }
00261 
00262 bool CalendarDay::hasInterval() const {
00263     return m_state == Map::Working && m_workingIntervals.count() > 0;
00264 }
00265 
00266 bool CalendarDay::hasInterval(const QTime &start, const QTime &end) const {
00267     //kdDebug()<<k_funcinfo<<(m_date.isValid()?m_date.toString(Qt::ISODate):"Weekday")<<" "<<start.toString()<<" - "<<end.toString()<<endl;
00268     if (m_state != Map::Working) {
00269         return false;
00270     }
00271     QPtrListIterator<QPair<QTime, QTime> > it = m_workingIntervals;
00272     for (; it.current(); ++it) {
00273         if (start < it.current()->second && end > it.current()->first) {
00274             //kdDebug()<<k_funcinfo<<"true:"<<(m_date.isValid()?m_date.toString(Qt::ISODate):"Weekday")<<" "<<it.current()->first.toString()<<" - "<<it.current()->second.toString()<<endl;
00275             return true;
00276         }
00277     }
00278     return false;
00279 }
00280 
00281 Duration CalendarDay::duration() const {
00282     Duration dur;
00283     QPtrListIterator<QPair<QTime, QTime> > it = m_workingIntervals;
00284     for (; it.current(); ++it) {
00285         DateTime start(QDate::currentDate(), it.current()->first);
00286         DateTime end(QDate::currentDate(), it.current()->second);
00287         dur += end - start;
00288     }
00289     return dur;
00290 }
00291 
00293 CalendarWeekdays::CalendarWeekdays()
00294     : m_weekdays(),
00295       m_workHours(40) {
00296 
00297     //kdDebug()<<k_funcinfo<<"--->"<<endl;
00298     for (int i=0; i < 7; ++i) {
00299         m_weekdays.append(new CalendarDay());
00300     }
00301     m_weekdays.setAutoDelete(false);
00302     //kdDebug()<<k_funcinfo<<"<---"<<endl;
00303 }
00304 
00305 CalendarWeekdays::CalendarWeekdays(CalendarWeekdays *weekdays)
00306     : m_weekdays() {
00307     //kdDebug()<<k_funcinfo<<"--->"<<endl;
00308     copy(*weekdays);
00309     //kdDebug()<<k_funcinfo<<"<---"<<endl;
00310 }
00311 
00312 CalendarWeekdays::~CalendarWeekdays() {
00313     m_weekdays.setAutoDelete(true);
00314     //kdDebug()<<k_funcinfo<<endl;
00315 }
00316 
00317 const CalendarWeekdays &CalendarWeekdays::copy(const CalendarWeekdays &weekdays) {
00318     //kdDebug()<<k_funcinfo<<endl;
00319     m_weekdays.setAutoDelete(true);
00320     m_weekdays.clear();
00321     m_weekdays.setAutoDelete(false);
00322     QPtrListIterator<CalendarDay> it = weekdays.weekdays();
00323     for (; it.current(); ++it) {
00324         m_weekdays.append(new CalendarDay(it.current()));
00325     }
00326     return *this;
00327 }
00328 
00329 bool CalendarWeekdays::load(QDomElement &element) {
00330     //kdDebug()<<k_funcinfo<<endl;
00331     bool ok;
00332     int dayNo = QString(element.attribute("day","-1")).toInt(&ok);
00333     if (dayNo < 0 || dayNo > 6) {
00334         kdError()<<k_funcinfo<<"Illegal weekday: "<<dayNo<<endl;
00335         return true; // we continue anyway
00336     }
00337     CalendarDay *day = m_weekdays.at(dayNo);
00338     if (!day)
00339         day = new CalendarDay();
00340     if (!day->load(element))
00341         day->setState(Map::None);
00342     return true;
00343 }
00344 
00345 void CalendarWeekdays::save(QDomElement &element) const {
00346     //kdDebug()<<k_funcinfo<<endl;
00347     QPtrListIterator<CalendarDay> it = m_weekdays;
00348     for (int i=0; it.current(); ++it) {
00349         QDomElement me = element.ownerDocument().createElement("weekday");
00350         element.appendChild(me);
00351         me.setAttribute("day", i++);
00352         it.current()->save(me);
00353     }
00354 }    
00355 
00356 IntMap CalendarWeekdays::map() {
00357     IntMap days;
00358     for (unsigned int i=0; i < m_weekdays.count(); ++i) {
00359         if (m_weekdays.at(i)->state() > 0)
00360             days.insert(i+1, m_weekdays.at(i)->state()); //Note: day numbers 1..7
00361     }
00362     return days;
00363 }
00364 
00365 int CalendarWeekdays::state(const QDate &date) const {
00366     return state(date.dayOfWeek()-1);
00367 }
00368 
00369 int CalendarWeekdays::state(int weekday) const {
00370     CalendarDay *day = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(weekday);
00371     return day ? day->state() : Map::None;
00372 }
00373 
00374 void CalendarWeekdays::setState(int weekday, int state) {
00375     CalendarDay *day = m_weekdays.at(weekday);
00376     if (!day)
00377         return;
00378     day->setState(state);
00379 }
00380 
00381 const QPtrList<QPair<QTime, QTime> > &CalendarWeekdays::intervals(int weekday) const { 
00382     CalendarDay *day = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(weekday);
00383     Q_ASSERT(day);
00384     return day->workingIntervals();
00385 }
00386 
00387 void CalendarWeekdays::setIntervals(int weekday, QPtrList<QPair<QTime, QTime> >intervals) {
00388     CalendarDay *day = m_weekdays.at(weekday);
00389     if (day)
00390         day->setIntervals(intervals); 
00391 }
00392 
00393 void CalendarWeekdays::clearIntervals(int weekday) {
00394     CalendarDay *day = m_weekdays.at(weekday);
00395     if (day)
00396         day->clearIntervals(); 
00397 }
00398 
00399 bool CalendarWeekdays::operator==(const CalendarWeekdays *wd) const {
00400     if (m_weekdays.count() != wd->weekdays().count())
00401         return false;
00402     for (unsigned int i=0; i < m_weekdays.count(); ++i) {
00403         // is there a better way to get around this const stuff?
00404         CalendarDay *day1 = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(i);
00405         CalendarDay *day2 = const_cast<QPtrList<CalendarDay>&>(wd->weekdays()).at(i);
00406         if (day1 != day2)
00407             return false;
00408     }
00409     return true;
00410 }
00411 bool CalendarWeekdays::operator!=(const CalendarWeekdays *wd) const {
00412     if (m_weekdays.count() != wd->weekdays().count())
00413         return true;
00414     for (unsigned int i=0; i < m_weekdays.count(); ++i) {
00415         // is there a better way to get around this const stuff?
00416         CalendarDay *day1 = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(i);
00417         CalendarDay *day2 = const_cast<QPtrList<CalendarDay>&>(wd->weekdays()).at(i);
00418         if (day1 != day2)
00419             return true;
00420     }
00421     return false;
00422 }
00423 
00424 Duration CalendarWeekdays::effort(const QDate &date, const QTime &start, const QTime &end) {
00425     //kdDebug()<<k_funcinfo<<"Day of week="<<date.dayOfWeek()-1<<endl;
00426     CalendarDay *day = weekday(date.dayOfWeek()-1);
00427     if (day && day->state() == Map::Working) {
00428         return day->effort(start, end);
00429     }
00430     return Duration::zeroDuration;
00431 }
00432 
00433 QPair<QTime, QTime> CalendarWeekdays::interval(const QDate date, const QTime &start, const QTime &end) const {
00434     //kdDebug()<<k_funcinfo<<endl;
00435     CalendarDay *day = weekday(date.dayOfWeek()-1);
00436     if (day && day->state() == Map::Working) {
00437         if (day->hasInterval(start, end)) {
00438             return day->interval(start, end);
00439         }
00440     }
00441     return QPair<QTime, QTime>(QTime(), QTime());
00442 }
00443 
00444 bool CalendarWeekdays::hasInterval(const QDate date, const QTime &start, const QTime &end) const {
00445     //kdDebug()<<k_funcinfo<<date.toString()<<": "<<start.toString()<<" - "<<end.toString()<<endl;
00446     CalendarDay *day = weekday(date.dayOfWeek()-1);
00447     return day && day->hasInterval(start, end);
00448 }
00449 
00450 bool CalendarWeekdays::hasInterval() const {
00451     //kdDebug()<<k_funcinfo<<endl;
00452     QPtrListIterator<CalendarDay> it = m_weekdays;
00453     for (; it.current(); ++it) {
00454         if (it.current()->hasInterval())
00455             return true;
00456     }
00457     return false;
00458 }
00459 
00460 CalendarDay *CalendarWeekdays::weekday(int day) const {
00461     QPtrListIterator<CalendarDay> it = m_weekdays;
00462     for (int i=0; it.current(); ++it, ++i) {
00463         if (i == day)
00464             return it.current();
00465     }
00466     return 0;
00467 }
00468 
00469 Duration CalendarWeekdays::duration() const {
00470     Duration dur;
00471     QPtrListIterator<CalendarDay> it = m_weekdays;
00472     for (; it.current(); ++it) {
00473         dur += it.current()->duration();
00474     }
00475     return dur;
00476 }
00477 
00478 Duration CalendarWeekdays::duration(int _weekday) const {
00479     CalendarDay *day = weekday(_weekday);
00480     if (day)
00481         return day->duration();
00482     return Duration();
00483 }
00484 
00485 QTime CalendarWeekdays::startOfDay(int _weekday) const {
00486     CalendarDay *day = weekday(_weekday);
00487     if (day)
00488         return day->startOfDay();
00489     return QTime();
00490 }
00491 
00492 QTime CalendarWeekdays::endOfDay(int _weekday) const {
00493     CalendarDay *day = weekday(_weekday);
00494     if (day)
00495         return day->endOfDay();
00496     return QTime();
00497 }
00498     
00499 
00501 
00502 Calendar::Calendar()
00503     : m_parent(0),
00504       m_project(0),
00505       m_deleted(false) {
00506 
00507     init();
00508 }
00509 
00510 Calendar::Calendar(QString name, Calendar *parent)
00511     : m_name(name),
00512       m_parent(parent),
00513       m_project(0),
00514       m_deleted(false),
00515       m_days() {
00516     
00517     init();
00518 }
00519 
00520 Calendar::~Calendar() {
00521     //kdDebug()<<k_funcinfo<<"deleting "<<m_name<<endl;
00522     removeId();
00523     delete m_weekdays; 
00524 }
00525 Calendar::Calendar(Calendar *calendar)
00526     : m_project(0),
00527       m_days() {
00528     m_days.setAutoDelete(true);
00529     copy(*calendar);
00530 }
00531 
00532 const Calendar &Calendar::copy(Calendar &calendar) {
00533     m_name = calendar.name();
00534     m_parent = calendar.parent();
00535     m_deleted = calendar.isDeleted();
00536     m_id = calendar.id();
00537     
00538     QPtrListIterator<CalendarDay> it = calendar.days();
00539     for (; it.current(); ++it) {
00540         m_days.append(new CalendarDay(it.current()));
00541     }
00542     m_weekdays = new CalendarWeekdays(calendar.weekdays());
00543     return *this;
00544 }
00545 
00546 void Calendar::init() {
00547     m_days.setAutoDelete(true);
00548     m_weekdays = new CalendarWeekdays();
00549 }
00550 
00551 void Calendar::setProject(Project *project) { 
00552     m_project = project;
00553     generateId();
00554 }
00555 
00556 void Calendar::setDeleted(bool yes) {
00557     if (yes) {
00558         removeId();
00559     } else {
00560         setId(m_id);
00561     }
00562     m_deleted = yes;
00563 }
00564 bool Calendar::setId(QString id) {
00565     //kdDebug()<<k_funcinfo<<id<<endl;
00566     if (id.isEmpty()) {
00567         kdError()<<k_funcinfo<<"id is empty"<<endl;
00568         m_id = id;
00569         return false;
00570     }
00571     Calendar *c = findCalendar();
00572     if (c == this) {
00573         kdDebug()<<k_funcinfo<<"My id found, remove it"<<endl;
00574         removeId();
00575     } else if (c) {
00576         //can happen when making a copy
00577         kdError()<<k_funcinfo<<"My id '"<<m_id<<"' already used for different node: "<<c->name()<<endl;
00578     }
00579     if (findCalendar(id)) {
00580         kdError()<<k_funcinfo<<"id '"<<id<<"' is already used for different node: "<<findCalendar(id)->name()<<endl;
00581         m_id = QString(); // hmmm
00582         return false;
00583     }
00584     m_id = id;
00585     insertId(id);
00586     //kdDebug()<<k_funcinfo<<m_name<<": inserted id="<<id<<endl;
00587     return true;
00588 }
00589 
00590 void Calendar::generateId() {
00591     if (!m_id.isEmpty()) {
00592         removeId();
00593     }
00594     for (int i=0; i<32000 ; ++i) {
00595         m_id = m_id.setNum(i);
00596         if (!findCalendar()) {
00597             insertId(m_id);
00598             return;
00599         }
00600     }
00601     m_id = QString();
00602 }
00603 
00604 bool Calendar::load(QDomElement &element) {
00605     //kdDebug()<<k_funcinfo<<element.text()<<endl;
00606     //bool ok;
00607     setId(element.attribute("id"));
00608     m_parentId = element.attribute("parent");
00609     m_name = element.attribute("name","");
00610     //TODO parent
00611     
00612     QDomNodeList list = element.childNodes();
00613     for (unsigned int i=0; i<list.count(); ++i) {
00614         if (list.item(i).isElement()) {
00615             QDomElement e = list.item(i).toElement();
00616             if (e.tagName() == "weekday") {
00617                 if (!m_weekdays->load(e))
00618                     return false;
00619             }
00620             if (e.tagName() == "day") {
00621                 CalendarDay *day = new CalendarDay();
00622                 if (day->load(e)) {
00623                     if (!day->date().isValid()) {
00624                         delete day;
00625                         kdError()<<k_funcinfo<<m_name<<": Failed to load calendarDay - Invalid date"<<endl;
00626                     } else {
00627                         CalendarDay *d = findDay(day->date());
00628                         if (d) {
00629                             // already exists, keep the new
00630                             removeDay(d);
00631                             kdWarning()<<k_funcinfo<<m_name<<" Load calendarDay - Date already exists"<<endl;
00632                         }
00633                         addDay(day);
00634                     }
00635                 } else {
00636                     delete day;
00637                     kdError()<<k_funcinfo<<"Failed to load calendarDay"<<endl;
00638                     return true; //false; don't throw away the whole calendar
00639                 }
00640             }
00641         }
00642     }
00643     return true;
00644 }
00645 
00646 void Calendar::save(QDomElement &element) const {
00647     //kdDebug()<<k_funcinfo<<m_name<<endl;
00648     if (m_deleted)
00649         return;
00650     
00651     QDomElement me = element.ownerDocument().createElement("calendar");
00652     element.appendChild(me);
00653     if (m_parent && !m_parent->isDeleted()) 
00654         me.setAttribute("parent", m_parent->id());
00655     me.setAttribute("name", m_name);
00656     me.setAttribute("id", m_id);
00657     m_weekdays->save(me);
00658     QPtrListIterator<CalendarDay> it = m_days;
00659     for (; it.current(); ++it) {
00660         QDomElement e = me.ownerDocument().createElement("day");
00661         me.appendChild(e);
00662         it.current()->save(e);
00663     }
00664     
00665 }
00666 
00667 CalendarDay *Calendar::findDay(const QDate &date, bool skipNone) const {
00668     //kdDebug()<<k_funcinfo<<date.toString()<<endl;
00669     QPtrListIterator<CalendarDay> it = m_days;
00670     for (; it.current(); ++it) {
00671         if (it.current()->date() == date) {
00672             if (skipNone  && it.current()->state() == Map::None) {
00673                 continue; // hmmm, break?
00674             }
00675             return it.current();
00676         }
00677     }
00678     //kdDebug()<<k_funcinfo<<date.toString()<<" not found"<<endl;
00679     return 0;
00680 }
00681 
00682 bool Calendar::hasParent(Calendar *cal) {
00683     //kdDebug()<<k_funcinfo<<endl;
00684     if (!m_parent)
00685         return false;
00686     if (m_parent == cal)
00687         return true;
00688     return m_parent->hasParent(cal);
00689 }
00690 
00691 Duration Calendar::effort(const QDate &date, const QTime &start, const QTime &end) const {
00692     //kdDebug()<<k_funcinfo<<m_name<<": "<<date.toString(Qt::ISODate)<<" "<<start.toString()<<" - "<<end.toString()<<endl;
00693     if (start == end) {
00694         return Duration::zeroDuration;
00695     }
00696     QTime _start = start;
00697     QTime _end = end;
00698     if (start > end) {
00699         _start = end;
00700         _end = start;
00701     }
00702     // first, check my own day
00703     CalendarDay *day = findDay(date, true);
00704     if (day) {
00705         if (day->state() == Map::Working) {
00706             return day->effort(_start, _end);
00707         } else if (day->state() == Map::NonWorking) {
00708             return Duration::zeroDuration;
00709         } else {
00710             kdError()<<k_funcinfo<<"Invalid state: "<<day->state()<<endl;
00711             return Duration::zeroDuration;
00712         }
00713     }
00714     // check my own weekdays
00715     if (m_weekdays) {
00716         if (m_weekdays->state(date) == Map::Working) {
00717             return m_weekdays->effort(date, _start, _end);
00718         }
00719         if (m_weekdays->state(date) == Map::NonWorking) {
00720             return Duration::zeroDuration;
00721         }
00722     }
00723     if (m_parent && !m_parent->isDeleted()) {
00724         return m_parent->effort(date, start, end);
00725     }
00726     // Check default calendar
00727     return project()->defaultCalendar()->effort(date, start, end);
00728 }
00729 
00730 Duration Calendar::effort(const DateTime &start, const DateTime &end) const {
00731     //kdDebug()<<k_funcinfo<<m_name<<": "<<start<<" to "<<end<<endl;
00732     Duration eff;
00733     if (!start.isValid() || !end.isValid() || end <= start) {
00734         return eff;
00735     }
00736     QDate date = start.date();
00737     QTime startTime = start.time();
00738     QTime endTime = end.time();
00739     if (end.date() > date) {
00740         endTime.setHMS(23, 59, 59, 999);
00741     }
00742     eff = effort(date, startTime, endTime); // first day
00743     // Now get all the rest of the days
00744     for (date = date.addDays(1); date <= end.date(); date = date.addDays(1)) {
00745         if (date < end.date())
00746              eff += effort(date, QTime(), endTime); // whole days
00747         else 
00748              eff += effort(date, QTime(), end.time()); // last day
00749         //kdDebug()<<k_funcinfo<<": eff now="<<eff.toString(Duration::Format_Day)<<endl;
00750     }
00751     //kdDebug()<<k_funcinfo<<start.date().toString()<<"- "<<end.date().toString()<<": total="<<eff.toString(Duration::Format_Day)<<endl;
00752     return eff;
00753 }
00754 
00755 
00756 QPair<QTime, QTime> Calendar::firstInterval(const QDate &date, const QTime &startTime, const QTime &endTime) const {
00757     CalendarDay *day = findDay(date, true);
00758     if (day) {
00759         return day->interval(startTime, endTime);
00760     }
00761     if (m_weekdays) {
00762         if (m_weekdays->state(date) == Map::Working) {
00763             return m_weekdays->interval(date, startTime, endTime);
00764         }
00765         if (m_weekdays->state(date) == Map::NonWorking) {
00766             return QPair<QTime, QTime>(QTime(), QTime());
00767         }
00768     }
00769     if (m_parent && !m_parent->isDeleted()) {
00770         return m_parent->firstInterval(date, startTime, endTime);
00771     }
00772     return project()->defaultCalendar()->firstInterval(date, startTime, endTime);
00773 }
00774 
00775 QPair<DateTime, DateTime> Calendar::firstInterval(const DateTime &start, const DateTime &end) const {
00776     //kdDebug()<<k_funcinfo<<start.toString()<<" - "<<end.toString()<<endl;
00777     if (!start.isValid()) {
00778         kdWarning()<<k_funcinfo<<"Invalid start time"<<endl;
00779         return QPair<DateTime, DateTime>(DateTime(), DateTime());
00780     }
00781     if (!end.isValid()) {
00782         kdWarning()<<k_funcinfo<<"Invalid end time"<<endl;
00783         return QPair<DateTime, DateTime>(DateTime(), DateTime());
00784     }
00785     QTime startTime;
00786     QTime endTime;
00787     QDate date = start.date();
00788     int i=0;
00789     for (; date <= end.date(); date = date.addDays(1)) {
00790         if (date < end.date())
00791             endTime = QTime(23, 59, 59, 999);
00792         else
00793             endTime = end.time();
00794         if (date > start.date())
00795             startTime = QTime();
00796         else 
00797             startTime = start.time();
00798             
00799         QPair<QTime, QTime> res = firstInterval(date, startTime, endTime);
00800         if (res.first < res.second) {
00801             return QPair<DateTime, DateTime>(DateTime(date,res.first),DateTime(date, res.second));
00802         }
00803     }
00804     //kdError()<<k_funcinfo<<"Didn't find an interval ("<<start<<", "<<end<<")"<<endl;
00805     return QPair<DateTime, DateTime>(DateTime(), DateTime());
00806 }
00807 
00808 
00809 bool Calendar::hasInterval(const QDate &date, const QTime &startTime, const QTime &endTime) const {
00810     CalendarDay *day = findDay(date, true);
00811     if (day) {
00812         //kdDebug()<<k_funcinfo<<m_name<<" "<<date<<": "<<startTime<<" to "<<endTime<<endl;
00813         return day->hasInterval(startTime, endTime);
00814     } 
00815     if (m_weekdays) {
00816         if (m_weekdays->state(date) == Map::Working) {
00817             return m_weekdays->hasInterval(date, startTime, endTime);
00818         } else if (m_weekdays->state(date) == Map::NonWorking) {
00819             return false;
00820         }
00821     }
00822     if (m_parent && !m_parent->isDeleted()) {
00823         return m_parent->hasInterval(date, startTime, endTime);
00824     }
00825     return project()->defaultCalendar()->hasInterval(date, startTime, endTime);
00826 }
00827 
00828 bool Calendar::hasInterval(const DateTime &start, const DateTime &end) const {
00829     //kdDebug()<<k_funcinfo<<m_name<<": "<<start<<" - "<<end<<endl;
00830     if (!start.isValid() || !end.isValid() || end <= start) {
00831         //kdError()<<k_funcinfo<<"Invalid input: "<<(start.isValid()?"":"(start invalid) ")<<(end.isValid()?"":"(end invalid) ")<<(start>end?"":"(start<=end)")<<endl;
00832         //kdDebug()<<kdBacktrace(8)<<endl;
00833         return false;
00834     }
00835     QTime startTime;
00836     QTime endTime;
00837     QDate date = start.date();
00838     for (; date <= end.date(); date = date.addDays(1)) {
00839         if (date < end.date())
00840             endTime = QTime(23, 59, 59, 999);
00841         else
00842             endTime = end.time();
00843         if (date > start.date())
00844             startTime = QTime();
00845         else 
00846             startTime = start.time();
00847 
00848         if (hasInterval(date, startTime, endTime))
00849             return true;
00850     }
00851     return false;
00852 }
00853 
00854 DateTime Calendar::firstAvailableAfter(const DateTime &time, const DateTime &limit) {
00855     //kdDebug()<<k_funcinfo<<m_name<<": check from "<<time.toString()<<" limit="<<limit.toString()<<endl;
00856     if (!time.isValid() || !limit.isValid() || time >= limit) {
00857         kdError()<<k_funcinfo<<"Invalid input: "<<(time.isValid()?"":"(time invalid) ")<<(limit.isValid()?"":"(limit invalid) ")<<(time>limit?"":"(time>=limit)")<<endl;
00858         return DateTime();
00859     }
00860     if (!hasInterval(time, limit)) {
00861         return DateTime();
00862     }
00863     DateTime t = firstInterval(time, limit).first;
00864     //kdDebug()<<k_funcinfo<<m_name<<": "<<t.toString()<<endl;
00865     return t;
00866 }
00867 
00868 DateTime Calendar::firstAvailableBefore(const DateTime &time, const DateTime &limit) {
00869     //kdDebug()<<k_funcinfo<<m_name<<": check from "<<time.toString()<<" limit="<<limit.toString()<<endl;
00870     if (!time.isValid() || !limit.isValid() || time <= limit) {
00871         kdError()<<k_funcinfo<<"Invalid input: "<<(time.isValid()?"":"(time invalid) ")<<(limit.isValid()?"":"(limit invalid) ")<<(time>limit?"":"(time<=limit)")<<endl;
00872         return DateTime();
00873     }
00874     DateTime lmt = time;
00875     DateTime t = DateTime(time.date()); // start of first day
00876     if (t == lmt)
00877         t = t.addDays(-1); // in case time == start of day
00878     if (t < limit)
00879         t = limit;  // always stop at limit (lower boundary)
00880     DateTime res;
00881     //kdDebug()<<k_funcinfo<<m_name<<": t="<<t<<", "<<lmt<<" limit="<<limit<<endl;
00882     while (!res.isValid() && t >= limit) {
00883         // check intervals for 1 day
00884         DateTime r = firstInterval(t, lmt).second;
00885         res = r;
00886         // Find the last interval
00887         while(r.isValid() && r < lmt) {
00888             r = firstInterval(r, lmt).second;
00889             if (r.isValid())
00890                 res = r;
00891             //kdDebug()<<k_funcinfo<<m_name<<": r="<<r<<", "<<lmt<<" res="<<res<<endl;
00892         }
00893         if (!res.isValid()) {
00894             if (t == limit) {
00895                 break;
00896             }
00897             lmt = t;
00898             t = t.addDays(-1);
00899             if (t < limit) {
00900                 t = limit;
00901             }
00902             if (t == lmt)
00903                 break;
00904         }
00905     }
00906     //kdDebug()<<k_funcinfo<<m_name<<": "<<res<<endl;
00907     return res;
00908 }
00909 
00910 Calendar *Calendar::findCalendar(const QString &id) const { 
00911     return (m_project ? m_project->findCalendar(id) : 0); 
00912 }
00913 
00914 bool Calendar::removeId(const QString &id) { 
00915     return (m_project ? m_project->removeCalendarId(id) : false); 
00916 }
00917 
00918 void Calendar::insertId(const QString &id){ 
00919     if (m_project)
00920         m_project->insertCalendarId(id, this); 
00921 }
00922 
00924 StandardWorktime::StandardWorktime() {
00925     init();
00926 }
00927 
00928 StandardWorktime::StandardWorktime(StandardWorktime *worktime) {
00929     if (worktime) {
00930         m_year = worktime->durationYear();
00931         m_month = worktime->durationMonth();
00932         m_week = worktime->durationWeek();
00933         m_day = worktime->durationDay();
00934         m_calendar = new Calendar(*(worktime->calendar()));
00935     } else {
00936         init();
00937     }
00938 }
00939 
00940 StandardWorktime::~StandardWorktime() {
00941     //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00942 }
00943 
00944 void StandardWorktime::init() {
00945     // Some sane default values
00946     m_year = Duration(0, 1760, 0);
00947     m_month = Duration(0, 176, 0);
00948     m_week = Duration(0, 40, 0);
00949     m_day = Duration(0, 8, 0);
00950     m_calendar = new Calendar;
00951     m_calendar->setName(i18n("Base"));
00952     QPair<QTime, QTime> t = QPair<QTime, QTime>(QTime(8,0,0), QTime(16,0,0));
00953     for (int i=0; i < 5; ++i) {
00954         m_calendar->weekday(i)->addInterval(t);
00955         m_calendar->weekday(i)->setState(Map::Working);
00956     }
00957     m_calendar->weekday(5)->setState(Map::NonWorking);
00958     m_calendar->weekday(6)->setState(Map::NonWorking);
00959 }
00960 
00961 bool StandardWorktime::load(QDomElement &element) {
00962     //kdDebug()<<k_funcinfo<<endl;
00963     m_year = Duration::fromString(element.attribute("year"), Duration::Format_Hour); 
00964     m_month = Duration::fromString(element.attribute("month"), Duration::Format_Hour); 
00965     m_week = Duration::fromString(element.attribute("week"), Duration::Format_Hour); 
00966     m_day = Duration::fromString(element.attribute("day"), Duration::Format_Hour); 
00967     
00968     QDomNodeList list = element.childNodes();
00969     for (unsigned int i=0; i<list.count(); ++i) {
00970         if (list.item(i).isElement()) {
00971             QDomElement e = list.item(i).toElement();
00972             if (e.tagName() == "calendar") {
00973                 delete m_calendar;
00974                 m_calendar = new Calendar;
00975                 m_calendar->load(e);
00976             }
00977         }
00978     }
00979     return true;
00980 }
00981 
00982 void StandardWorktime::save(QDomElement &element) const {
00983     //kdDebug()<<k_funcinfo<<endl;
00984     QDomElement me = element.ownerDocument().createElement("standard-worktime");
00985     element.appendChild(me);
00986     me.setAttribute("year", m_year.toString(Duration::Format_Hour));
00987     me.setAttribute("month", m_month.toString(Duration::Format_Hour));
00988     me.setAttribute("week", m_week.toString(Duration::Format_Hour));
00989     me.setAttribute("day", m_day.toString(Duration::Format_Hour));
00990     
00991     m_calendar->save(me);
00992 }
00993 
00994 #ifndef NDEBUG
00995 void CalendarDay::printDebug(QCString indent) {
00996     QString s[] = {"None", "Non-working", "Working"};
00997     kdDebug()<<indent<<" "<<m_date.toString()<<" = "<<s[m_state]<<endl;
00998     if (m_state == Map::Working) {
00999         indent += "  ";
01000         QPtrListIterator<QPair<QTime, QTime> > it = m_workingIntervals;
01001         for (; it.current(); ++it) {
01002             kdDebug()<<indent<<" Interval: "<<it.current()->first<<" to "<<it.current()->second<<endl;
01003         }
01004     }
01005     
01006 }
01007 void CalendarWeekdays::printDebug(QCString indent) {
01008     kdDebug()<<indent<<"Weekdays ------"<<endl;
01009     QPtrListIterator<CalendarDay> it = m_weekdays;
01010     for (char c='0'; it.current(); ++it) {
01011         it.current()->printDebug(indent + "  Day " + c++ + ": ");
01012     }
01013 
01014 }
01015 void Calendar::printDebug(QCString indent) {
01016     kdDebug()<<indent<<"Calendar "<<m_id<<": '"<<m_name<<"' Deleted="<<m_deleted<<endl;
01017     kdDebug()<<indent<<"  Parent: "<<(m_parent ? m_parent->name() : "No parent")<<endl;
01018     m_weekdays->printDebug(indent + "  ");
01019     kdDebug()<<indent<<"  Days --------"<<endl;
01020     QPtrListIterator<CalendarDay> it = m_days;
01021     for (; it.current(); ++it) {
01022         it.current()->printDebug(indent + "  ");
01023     }
01024 }
01025 
01026 void StandardWorktime::printDebug(QCString indent) {
01027     kdDebug()<<indent<<"StandardWorktime "<<endl;
01028     kdDebug()<<indent<<"Year: "<<m_year.toString()<<endl;
01029     kdDebug()<<indent<<"Month: "<<m_month.toString()<<endl;
01030     kdDebug()<<indent<<"Week: "<<m_week.toString()<<endl;
01031     kdDebug()<<indent<<"Day: "<<m_day.toString()<<endl;
01032 }
01033 
01034 #endif
01035 
01036 }  //KPlato namespace
KDE Home | KDE Accessibility Home | Description of Access Keys