You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1037 lines
34 KiB
1037 lines
34 KiB
/* This file is part of the KDE project
|
|
Copyright (C) 2003 - 2006 Dag Andersen <danders@get2net.dk>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation;
|
|
version 2 of the License.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "kptcalendar.h"
|
|
#include "kptduration.h"
|
|
#include "kptdatetime.h"
|
|
#include "kptproject.h"
|
|
|
|
#include <tqdom.h>
|
|
#include <tqptrlist.h>
|
|
|
|
#include <klocale.h>
|
|
#include <kdebug.h>
|
|
|
|
namespace KPlato
|
|
{
|
|
|
|
///// CalendarDay ////
|
|
CalendarDay::CalendarDay()
|
|
: m_date(),
|
|
m_state(0),
|
|
m_workingIntervals() {
|
|
|
|
//kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
|
|
m_workingIntervals.setAutoDelete(true);
|
|
}
|
|
|
|
CalendarDay::CalendarDay(int state)
|
|
: m_date(),
|
|
m_state(state),
|
|
m_workingIntervals() {
|
|
|
|
//kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
|
|
m_workingIntervals.setAutoDelete(true);
|
|
}
|
|
|
|
CalendarDay::CalendarDay(TQDate date, int state)
|
|
: m_date(date),
|
|
m_state(state),
|
|
m_workingIntervals() {
|
|
|
|
//kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
|
|
m_workingIntervals.setAutoDelete(true);
|
|
}
|
|
|
|
CalendarDay::CalendarDay(CalendarDay *day)
|
|
: m_workingIntervals() {
|
|
|
|
//kdDebug()<<k_funcinfo<<"("<<this<<") from ("<<day<<")"<<endl;
|
|
m_workingIntervals.setAutoDelete(true);
|
|
copy(*day);
|
|
}
|
|
|
|
CalendarDay::~CalendarDay() {
|
|
//kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
|
|
}
|
|
|
|
const CalendarDay &CalendarDay::copy(const CalendarDay &day) {
|
|
//kdDebug()<<k_funcinfo<<"("<<&day<<") date="<<day.date().toString()<<endl;
|
|
m_date = day.date();
|
|
m_state = day.state();
|
|
m_workingIntervals.clear();
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = day.workingIntervals();
|
|
for(; it.current(); ++it) {
|
|
m_workingIntervals.append(new TQPair<TQTime, TQTime>(it.current()->first, it.current()->second));
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool CalendarDay::load(TQDomElement &element) {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
bool ok=false;
|
|
m_state = TQString(element.attribute("state", "-1")).toInt(&ok);
|
|
if (m_state < 0)
|
|
return false;
|
|
//kdDebug()<<k_funcinfo<<" state="<<m_state<<endl;
|
|
TQString s = element.attribute("date");
|
|
if (s != "") {
|
|
m_date = TQDate::fromString(s, Qt::ISODate);
|
|
if (!m_date.isValid())
|
|
m_date = TQDate::fromString(s);
|
|
}
|
|
clearIntervals();
|
|
TQDomNodeList list = element.childNodes();
|
|
for (unsigned int i=0; i<list.count(); ++i) {
|
|
if (list.item(i).isElement()) {
|
|
TQDomElement e = list.item(i).toElement();
|
|
if (e.tagName() == "interval") {
|
|
//kdDebug()<<k_funcinfo<<"Interval start="<<e.attribute("start")<<" end="<<e.attribute("end")<<endl;
|
|
TQString st = e.attribute("start");
|
|
TQString en = e.attribute("end");
|
|
if (st != "" && en != "") {
|
|
TQTime start = TQTime::fromString(st);
|
|
TQTime end = TQTime::fromString(en);
|
|
addInterval(new TQPair<TQTime, TQTime>(start,end));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CalendarDay::save(TQDomElement &element) const {
|
|
//kdDebug()<<k_funcinfo<<m_date.toString()<<endl;
|
|
if (m_state == Map::None)
|
|
return;
|
|
if (m_date.isValid()) {
|
|
element.setAttribute("date", m_date.toString(Qt::ISODate));
|
|
}
|
|
element.setAttribute("state", m_state);
|
|
if (m_workingIntervals.count() == 0)
|
|
return;
|
|
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
|
|
for (; it.current(); ++it) {
|
|
TQDomElement me = element.ownerDocument().createElement("interval");
|
|
element.appendChild(me);
|
|
me.setAttribute("end", it.current()->second.toString());
|
|
me.setAttribute("start", it.current()->first.toString());
|
|
}
|
|
}
|
|
|
|
void CalendarDay::addInterval(TQPair<TQTime, TQTime> *interval) {
|
|
m_workingIntervals.append(interval);
|
|
}
|
|
|
|
TQTime CalendarDay::startOfDay() const {
|
|
TQTime t;
|
|
if (!m_workingIntervals.isEmpty()) {
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
|
|
t = it.current()->first;
|
|
for (++it; it.current(); ++it) {
|
|
if (t > it.current()->first)
|
|
t = it.current()->first;
|
|
}
|
|
}
|
|
return t;
|
|
}
|
|
|
|
TQTime CalendarDay::endOfDay() const {
|
|
TQTime t;
|
|
if (!m_workingIntervals.isEmpty()) {
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
|
|
t = it.current()->second;
|
|
for (++it; it.current(); ++it) {
|
|
if (t > it.current()->second)
|
|
t = it.current()->second;
|
|
}
|
|
}
|
|
return t;
|
|
}
|
|
|
|
bool CalendarDay::operator==(const CalendarDay *day) const {
|
|
return operator==(*day);
|
|
}
|
|
bool CalendarDay::operator==(const CalendarDay &day) const {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
if (m_date.isValid() && day.date().isValid()) {
|
|
if (m_date != day.date()) {
|
|
//kdDebug()<<k_funcinfo<<m_date.toString()<<" != "<<day.date().toString()<<endl;
|
|
return false;
|
|
}
|
|
} else if (m_date.isValid() != day.date().isValid()) {
|
|
//kdDebug()<<k_funcinfo<<"one of the dates is not valid"<<endl;
|
|
return false;
|
|
}
|
|
if (m_state != day.state()) {
|
|
//kdDebug()<<k_funcinfo<<m_state<<" != "<<day.state()<<endl;
|
|
return false;
|
|
}
|
|
if (m_workingIntervals.count() != day.workingIntervals().count()) {
|
|
//kdDebug()<<k_funcinfo<<m_workingIntervals.count()<<" != "<<day.workingIntervals().count()<<endl;
|
|
return false;
|
|
}
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > dit = day.workingIntervals();
|
|
for (; it.current(); ++it) {
|
|
bool res = false;
|
|
TQPair<TQTime, TQTime> *a = it.current();
|
|
for (dit.toFirst(); dit.current(); ++dit) {
|
|
TQPair<TQTime, TQTime> *b = dit.current();
|
|
if (a->first == b->first && a->second == b->second) {
|
|
res = true;
|
|
break;
|
|
}
|
|
}
|
|
if (res == false) {
|
|
//kdDebug()<<k_funcinfo<<"interval mismatch "<<a->first.toString()<<"-"<<a->second.toString()<<endl;
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
bool CalendarDay::operator!=(const CalendarDay *day) const {
|
|
return operator!=(*day);
|
|
}
|
|
bool CalendarDay::operator!=(const CalendarDay &day) const {
|
|
return !operator==(day);
|
|
}
|
|
|
|
Duration CalendarDay::effort(const TQTime &start, const TQTime &end) {
|
|
//kdDebug()<<k_funcinfo<<start.toString()<<" - "<<end.toString()<<endl;
|
|
Duration eff;
|
|
if (m_state != Map::Working) {
|
|
//kdDebug()<<k_funcinfo<<"Non working day"<<endl;
|
|
return eff;
|
|
}
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
|
|
for (; it.current(); ++it) {
|
|
//kdDebug()<<k_funcinfo<<"Interval: "<<it.current()->first.toString()<<" - "<<it.current()->second.toString()<<endl;
|
|
if (end > it.current()->first && start < it.current()->second) {
|
|
DateTime dtStart(TQDate::currentDate(), start);
|
|
if (start < it.current()->first) {
|
|
dtStart.setTime(it.current()->first);
|
|
}
|
|
DateTime dtEnd(TQDate::currentDate(), end);
|
|
if (end > it.current()->second) {
|
|
dtEnd.setTime(it.current()->second);
|
|
}
|
|
eff += dtEnd - dtStart;
|
|
//kdDebug()<<k_funcinfo<<dtStart.time().toString()<<" - "<<dtEnd.time().toString()<<"="<<eff.toString(Duration::Format_Day)<<endl;
|
|
}
|
|
}
|
|
//kdDebug()<<k_funcinfo<<(m_date.isValid()?m_date.toString(Qt::ISODate):"Weekday")<<": "<<start.toString()<<" - "<<end.toString()<<": total="<<eff.toString(Duration::Format_Day)<<endl;
|
|
return eff;
|
|
}
|
|
|
|
TQPair<TQTime, TQTime> CalendarDay::interval(const TQTime &start, const TQTime &end) const {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
TQTime t1, t2;
|
|
if (m_state == Map::Working) {
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
|
|
for (; it.current(); ++it) {
|
|
if (start < it.current()->second && end > it.current()->first) {
|
|
t1 = start > it.current()->first ? start : it.current()->first;
|
|
t2 = end < it.current()->second ? end : it.current()->second;
|
|
//kdDebug()<<k_funcinfo<<t1.toString()<<" to "<<t2.toString()<<endl;
|
|
return TQPair<TQTime, TQTime>(t1, t2);
|
|
}
|
|
}
|
|
}
|
|
//kdError()<<k_funcinfo<<"No interval "<<m_date<<": "<<start<<","<<end<<endl;
|
|
return TQPair<TQTime, TQTime>(t1, t2);
|
|
}
|
|
|
|
bool CalendarDay::hasInterval() const {
|
|
return m_state == Map::Working && m_workingIntervals.count() > 0;
|
|
}
|
|
|
|
bool CalendarDay::hasInterval(const TQTime &start, const TQTime &end) const {
|
|
//kdDebug()<<k_funcinfo<<(m_date.isValid()?m_date.toString(Qt::ISODate):"Weekday")<<" "<<start.toString()<<" - "<<end.toString()<<endl;
|
|
if (m_state != Map::Working) {
|
|
return false;
|
|
}
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
|
|
for (; it.current(); ++it) {
|
|
if (start < it.current()->second && end > it.current()->first) {
|
|
//kdDebug()<<k_funcinfo<<"true:"<<(m_date.isValid()?m_date.toString(Qt::ISODate):"Weekday")<<" "<<it.current()->first.toString()<<" - "<<it.current()->second.toString()<<endl;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Duration CalendarDay::duration() const {
|
|
Duration dur;
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
|
|
for (; it.current(); ++it) {
|
|
DateTime start(TQDate::currentDate(), it.current()->first);
|
|
DateTime end(TQDate::currentDate(), it.current()->second);
|
|
dur += end - start;
|
|
}
|
|
return dur;
|
|
}
|
|
|
|
///// CalendarWeekdays ////
|
|
CalendarWeekdays::CalendarWeekdays()
|
|
: m_weekdays(),
|
|
m_workHours(40) {
|
|
|
|
//kdDebug()<<k_funcinfo<<"--->"<<endl;
|
|
for (int i=0; i < 7; ++i) {
|
|
m_weekdays.append(new CalendarDay());
|
|
}
|
|
m_weekdays.setAutoDelete(false);
|
|
//kdDebug()<<k_funcinfo<<"<---"<<endl;
|
|
}
|
|
|
|
CalendarWeekdays::CalendarWeekdays(CalendarWeekdays *weekdays)
|
|
: m_weekdays() {
|
|
//kdDebug()<<k_funcinfo<<"--->"<<endl;
|
|
copy(*weekdays);
|
|
//kdDebug()<<k_funcinfo<<"<---"<<endl;
|
|
}
|
|
|
|
CalendarWeekdays::~CalendarWeekdays() {
|
|
m_weekdays.setAutoDelete(true);
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
}
|
|
|
|
const CalendarWeekdays &CalendarWeekdays::copy(const CalendarWeekdays &weekdays) {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
m_weekdays.setAutoDelete(true);
|
|
m_weekdays.clear();
|
|
m_weekdays.setAutoDelete(false);
|
|
TQPtrListIterator<CalendarDay> it = weekdays.weekdays();
|
|
for (; it.current(); ++it) {
|
|
m_weekdays.append(new CalendarDay(it.current()));
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool CalendarWeekdays::load(TQDomElement &element) {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
bool ok;
|
|
int dayNo = TQString(element.attribute("day","-1")).toInt(&ok);
|
|
if (dayNo < 0 || dayNo > 6) {
|
|
kdError()<<k_funcinfo<<"Illegal weekday: "<<dayNo<<endl;
|
|
return true; // we continue anyway
|
|
}
|
|
CalendarDay *day = m_weekdays.at(dayNo);
|
|
if (!day)
|
|
day = new CalendarDay();
|
|
if (!day->load(element))
|
|
day->setState(Map::None);
|
|
return true;
|
|
}
|
|
|
|
void CalendarWeekdays::save(TQDomElement &element) const {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
TQPtrListIterator<CalendarDay> it = m_weekdays;
|
|
for (int i=0; it.current(); ++it) {
|
|
TQDomElement me = element.ownerDocument().createElement("weekday");
|
|
element.appendChild(me);
|
|
me.setAttribute("day", i++);
|
|
it.current()->save(me);
|
|
}
|
|
}
|
|
|
|
IntMap CalendarWeekdays::map() {
|
|
IntMap days;
|
|
for (unsigned int i=0; i < m_weekdays.count(); ++i) {
|
|
if (m_weekdays.at(i)->state() > 0)
|
|
days.insert(i+1, m_weekdays.at(i)->state()); //Note: day numbers 1..7
|
|
}
|
|
return days;
|
|
}
|
|
|
|
int CalendarWeekdays::state(const TQDate &date) const {
|
|
return state(date.dayOfWeek()-1);
|
|
}
|
|
|
|
int CalendarWeekdays::state(int weekday) const {
|
|
CalendarDay *day = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(weekday);
|
|
return day ? day->state() : Map::None;
|
|
}
|
|
|
|
void CalendarWeekdays::setState(int weekday, int state) {
|
|
CalendarDay *day = m_weekdays.at(weekday);
|
|
if (!day)
|
|
return;
|
|
day->setState(state);
|
|
}
|
|
|
|
const TQPtrList<TQPair<TQTime, TQTime> > &CalendarWeekdays::intervals(int weekday) const {
|
|
CalendarDay *day = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(weekday);
|
|
Q_ASSERT(day);
|
|
return day->workingIntervals();
|
|
}
|
|
|
|
void CalendarWeekdays::setIntervals(int weekday, TQPtrList<TQPair<TQTime, TQTime> >intervals) {
|
|
CalendarDay *day = m_weekdays.at(weekday);
|
|
if (day)
|
|
day->setIntervals(intervals);
|
|
}
|
|
|
|
void CalendarWeekdays::clearIntervals(int weekday) {
|
|
CalendarDay *day = m_weekdays.at(weekday);
|
|
if (day)
|
|
day->clearIntervals();
|
|
}
|
|
|
|
bool CalendarWeekdays::operator==(const CalendarWeekdays *wd) const {
|
|
if (m_weekdays.count() != wd->weekdays().count())
|
|
return false;
|
|
for (unsigned int i=0; i < m_weekdays.count(); ++i) {
|
|
// is there a better way to get around this const stuff?
|
|
CalendarDay *day1 = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(i);
|
|
CalendarDay *day2 = const_cast<TQPtrList<CalendarDay>&>(wd->weekdays()).at(i);
|
|
if (day1 != day2)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
bool CalendarWeekdays::operator!=(const CalendarWeekdays *wd) const {
|
|
if (m_weekdays.count() != wd->weekdays().count())
|
|
return true;
|
|
for (unsigned int i=0; i < m_weekdays.count(); ++i) {
|
|
// is there a better way to get around this const stuff?
|
|
CalendarDay *day1 = const_cast<CalendarWeekdays*>(this)->m_weekdays.at(i);
|
|
CalendarDay *day2 = const_cast<TQPtrList<CalendarDay>&>(wd->weekdays()).at(i);
|
|
if (day1 != day2)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Duration CalendarWeekdays::effort(const TQDate &date, const TQTime &start, const TQTime &end) {
|
|
//kdDebug()<<k_funcinfo<<"Day of week="<<date.dayOfWeek()-1<<endl;
|
|
CalendarDay *day = weekday(date.dayOfWeek()-1);
|
|
if (day && day->state() == Map::Working) {
|
|
return day->effort(start, end);
|
|
}
|
|
return Duration::zeroDuration;
|
|
}
|
|
|
|
TQPair<TQTime, TQTime> CalendarWeekdays::interval(const TQDate date, const TQTime &start, const TQTime &end) const {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
CalendarDay *day = weekday(date.dayOfWeek()-1);
|
|
if (day && day->state() == Map::Working) {
|
|
if (day->hasInterval(start, end)) {
|
|
return day->interval(start, end);
|
|
}
|
|
}
|
|
return TQPair<TQTime, TQTime>(TQTime(), TQTime());
|
|
}
|
|
|
|
bool CalendarWeekdays::hasInterval(const TQDate date, const TQTime &start, const TQTime &end) const {
|
|
//kdDebug()<<k_funcinfo<<date.toString()<<": "<<start.toString()<<" - "<<end.toString()<<endl;
|
|
CalendarDay *day = weekday(date.dayOfWeek()-1);
|
|
return day && day->hasInterval(start, end);
|
|
}
|
|
|
|
bool CalendarWeekdays::hasInterval() const {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
TQPtrListIterator<CalendarDay> it = m_weekdays;
|
|
for (; it.current(); ++it) {
|
|
if (it.current()->hasInterval())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
CalendarDay *CalendarWeekdays::weekday(int day) const {
|
|
TQPtrListIterator<CalendarDay> it = m_weekdays;
|
|
for (int i=0; it.current(); ++it, ++i) {
|
|
if (i == day)
|
|
return it.current();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Duration CalendarWeekdays::duration() const {
|
|
Duration dur;
|
|
TQPtrListIterator<CalendarDay> it = m_weekdays;
|
|
for (; it.current(); ++it) {
|
|
dur += it.current()->duration();
|
|
}
|
|
return dur;
|
|
}
|
|
|
|
Duration CalendarWeekdays::duration(int _weekday) const {
|
|
CalendarDay *day = weekday(_weekday);
|
|
if (day)
|
|
return day->duration();
|
|
return Duration();
|
|
}
|
|
|
|
TQTime CalendarWeekdays::startOfDay(int _weekday) const {
|
|
CalendarDay *day = weekday(_weekday);
|
|
if (day)
|
|
return day->startOfDay();
|
|
return TQTime();
|
|
}
|
|
|
|
TQTime CalendarWeekdays::endOfDay(int _weekday) const {
|
|
CalendarDay *day = weekday(_weekday);
|
|
if (day)
|
|
return day->endOfDay();
|
|
return TQTime();
|
|
}
|
|
|
|
|
|
///// Calendar ////
|
|
|
|
Calendar::Calendar()
|
|
: m_parent(0),
|
|
m_project(0),
|
|
m_deleted(false) {
|
|
|
|
init();
|
|
}
|
|
|
|
Calendar::Calendar(TQString name, Calendar *parent)
|
|
: m_name(name),
|
|
m_parent(parent),
|
|
m_project(0),
|
|
m_deleted(false),
|
|
m_days() {
|
|
|
|
init();
|
|
}
|
|
|
|
Calendar::~Calendar() {
|
|
//kdDebug()<<k_funcinfo<<"deleting "<<m_name<<endl;
|
|
removeId();
|
|
delete m_weekdays;
|
|
}
|
|
Calendar::Calendar(Calendar *calendar)
|
|
: m_project(0),
|
|
m_days() {
|
|
m_days.setAutoDelete(true);
|
|
copy(*calendar);
|
|
}
|
|
|
|
const Calendar &Calendar::copy(Calendar &calendar) {
|
|
m_name = calendar.name();
|
|
m_parent = calendar.parent();
|
|
m_deleted = calendar.isDeleted();
|
|
m_id = calendar.id();
|
|
|
|
TQPtrListIterator<CalendarDay> it = calendar.days();
|
|
for (; it.current(); ++it) {
|
|
m_days.append(new CalendarDay(it.current()));
|
|
}
|
|
m_weekdays = new CalendarWeekdays(calendar.weekdays());
|
|
return *this;
|
|
}
|
|
|
|
void Calendar::init() {
|
|
m_days.setAutoDelete(true);
|
|
m_weekdays = new CalendarWeekdays();
|
|
}
|
|
|
|
void Calendar::setProject(Project *project) {
|
|
m_project = project;
|
|
generateId();
|
|
}
|
|
|
|
void Calendar::setDeleted(bool yes) {
|
|
if (yes) {
|
|
removeId();
|
|
} else {
|
|
setId(m_id);
|
|
}
|
|
m_deleted = yes;
|
|
}
|
|
bool Calendar::setId(TQString id) {
|
|
//kdDebug()<<k_funcinfo<<id<<endl;
|
|
if (id.isEmpty()) {
|
|
kdError()<<k_funcinfo<<"id is empty"<<endl;
|
|
m_id = id;
|
|
return false;
|
|
}
|
|
Calendar *c = findCalendar();
|
|
if (c == this) {
|
|
kdDebug()<<k_funcinfo<<"My id found, remove it"<<endl;
|
|
removeId();
|
|
} else if (c) {
|
|
//can happen when making a copy
|
|
kdError()<<k_funcinfo<<"My id '"<<m_id<<"' already used for different node: "<<c->name()<<endl;
|
|
}
|
|
if (findCalendar(id)) {
|
|
kdError()<<k_funcinfo<<"id '"<<id<<"' is already used for different node: "<<findCalendar(id)->name()<<endl;
|
|
m_id = TQString(); // hmmm
|
|
return false;
|
|
}
|
|
m_id = id;
|
|
insertId(id);
|
|
//kdDebug()<<k_funcinfo<<m_name<<": inserted id="<<id<<endl;
|
|
return true;
|
|
}
|
|
|
|
void Calendar::generateId() {
|
|
if (!m_id.isEmpty()) {
|
|
removeId();
|
|
}
|
|
for (int i=0; i<32000 ; ++i) {
|
|
m_id = m_id.setNum(i);
|
|
if (!findCalendar()) {
|
|
insertId(m_id);
|
|
return;
|
|
}
|
|
}
|
|
m_id = TQString();
|
|
}
|
|
|
|
bool Calendar::load(TQDomElement &element) {
|
|
//kdDebug()<<k_funcinfo<<element.text()<<endl;
|
|
//bool ok;
|
|
setId(element.attribute("id"));
|
|
m_parentId = element.attribute("parent");
|
|
m_name = element.attribute("name","");
|
|
//TODO parent
|
|
|
|
TQDomNodeList list = element.childNodes();
|
|
for (unsigned int i=0; i<list.count(); ++i) {
|
|
if (list.item(i).isElement()) {
|
|
TQDomElement e = list.item(i).toElement();
|
|
if (e.tagName() == "weekday") {
|
|
if (!m_weekdays->load(e))
|
|
return false;
|
|
}
|
|
if (e.tagName() == "day") {
|
|
CalendarDay *day = new CalendarDay();
|
|
if (day->load(e)) {
|
|
if (!day->date().isValid()) {
|
|
delete day;
|
|
kdError()<<k_funcinfo<<m_name<<": Failed to load calendarDay - Invalid date"<<endl;
|
|
} else {
|
|
CalendarDay *d = findDay(day->date());
|
|
if (d) {
|
|
// already exists, keep the new
|
|
removeDay(d);
|
|
kdWarning()<<k_funcinfo<<m_name<<" Load calendarDay - Date already exists"<<endl;
|
|
}
|
|
addDay(day);
|
|
}
|
|
} else {
|
|
delete day;
|
|
kdError()<<k_funcinfo<<"Failed to load calendarDay"<<endl;
|
|
return true; //false; don't throw away the whole calendar
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Calendar::save(TQDomElement &element) const {
|
|
//kdDebug()<<k_funcinfo<<m_name<<endl;
|
|
if (m_deleted)
|
|
return;
|
|
|
|
TQDomElement me = element.ownerDocument().createElement("calendar");
|
|
element.appendChild(me);
|
|
if (m_parent && !m_parent->isDeleted())
|
|
me.setAttribute("parent", m_parent->id());
|
|
me.setAttribute("name", m_name);
|
|
me.setAttribute("id", m_id);
|
|
m_weekdays->save(me);
|
|
TQPtrListIterator<CalendarDay> it = m_days;
|
|
for (; it.current(); ++it) {
|
|
TQDomElement e = me.ownerDocument().createElement("day");
|
|
me.appendChild(e);
|
|
it.current()->save(e);
|
|
}
|
|
|
|
}
|
|
|
|
CalendarDay *Calendar::findDay(const TQDate &date, bool skipNone) const {
|
|
//kdDebug()<<k_funcinfo<<date.toString()<<endl;
|
|
TQPtrListIterator<CalendarDay> it = m_days;
|
|
for (; it.current(); ++it) {
|
|
if (it.current()->date() == date) {
|
|
if (skipNone && it.current()->state() == Map::None) {
|
|
continue; // hmmm, break?
|
|
}
|
|
return it.current();
|
|
}
|
|
}
|
|
//kdDebug()<<k_funcinfo<<date.toString()<<" not found"<<endl;
|
|
return 0;
|
|
}
|
|
|
|
bool Calendar::hasParent(Calendar *cal) {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
if (!m_parent)
|
|
return false;
|
|
if (m_parent == cal)
|
|
return true;
|
|
return m_parent->hasParent(cal);
|
|
}
|
|
|
|
Duration Calendar::effort(const TQDate &date, const TQTime &start, const TQTime &end) const {
|
|
//kdDebug()<<k_funcinfo<<m_name<<": "<<date.toString(Qt::ISODate)<<" "<<start.toString()<<" - "<<end.toString()<<endl;
|
|
if (start == end) {
|
|
return Duration::zeroDuration;
|
|
}
|
|
TQTime _start = start;
|
|
TQTime _end = end;
|
|
if (start > end) {
|
|
_start = end;
|
|
_end = start;
|
|
}
|
|
// first, check my own day
|
|
CalendarDay *day = findDay(date, true);
|
|
if (day) {
|
|
if (day->state() == Map::Working) {
|
|
return day->effort(_start, _end);
|
|
} else if (day->state() == Map::NonWorking) {
|
|
return Duration::zeroDuration;
|
|
} else {
|
|
kdError()<<k_funcinfo<<"Invalid state: "<<day->state()<<endl;
|
|
return Duration::zeroDuration;
|
|
}
|
|
}
|
|
// check my own weekdays
|
|
if (m_weekdays) {
|
|
if (m_weekdays->state(date) == Map::Working) {
|
|
return m_weekdays->effort(date, _start, _end);
|
|
}
|
|
if (m_weekdays->state(date) == Map::NonWorking) {
|
|
return Duration::zeroDuration;
|
|
}
|
|
}
|
|
if (m_parent && !m_parent->isDeleted()) {
|
|
return m_parent->effort(date, start, end);
|
|
}
|
|
// Check default calendar
|
|
return project()->defaultCalendar()->effort(date, start, end);
|
|
}
|
|
|
|
Duration Calendar::effort(const DateTime &start, const DateTime &end) const {
|
|
//kdDebug()<<k_funcinfo<<m_name<<": "<<start<<" to "<<end<<endl;
|
|
Duration eff;
|
|
if (!start.isValid() || !end.isValid() || end <= start) {
|
|
return eff;
|
|
}
|
|
TQDate date = start.date();
|
|
TQTime startTime = start.time();
|
|
TQTime endTime = end.time();
|
|
if (end.date() > date) {
|
|
endTime.setHMS(23, 59, 59, 999);
|
|
}
|
|
eff = effort(date, startTime, endTime); // first day
|
|
// Now get all the rest of the days
|
|
for (date = date.addDays(1); date <= end.date(); date = date.addDays(1)) {
|
|
if (date < end.date())
|
|
eff += effort(date, TQTime(), endTime); // whole days
|
|
else
|
|
eff += effort(date, TQTime(), end.time()); // last day
|
|
//kdDebug()<<k_funcinfo<<": eff now="<<eff.toString(Duration::Format_Day)<<endl;
|
|
}
|
|
//kdDebug()<<k_funcinfo<<start.date().toString()<<"- "<<end.date().toString()<<": total="<<eff.toString(Duration::Format_Day)<<endl;
|
|
return eff;
|
|
}
|
|
|
|
|
|
TQPair<TQTime, TQTime> Calendar::firstInterval(const TQDate &date, const TQTime &startTime, const TQTime &endTime) const {
|
|
CalendarDay *day = findDay(date, true);
|
|
if (day) {
|
|
return day->interval(startTime, endTime);
|
|
}
|
|
if (m_weekdays) {
|
|
if (m_weekdays->state(date) == Map::Working) {
|
|
return m_weekdays->interval(date, startTime, endTime);
|
|
}
|
|
if (m_weekdays->state(date) == Map::NonWorking) {
|
|
return TQPair<TQTime, TQTime>(TQTime(), TQTime());
|
|
}
|
|
}
|
|
if (m_parent && !m_parent->isDeleted()) {
|
|
return m_parent->firstInterval(date, startTime, endTime);
|
|
}
|
|
return project()->defaultCalendar()->firstInterval(date, startTime, endTime);
|
|
}
|
|
|
|
TQPair<DateTime, DateTime> Calendar::firstInterval(const DateTime &start, const DateTime &end) const {
|
|
//kdDebug()<<k_funcinfo<<start.toString()<<" - "<<end.toString()<<endl;
|
|
if (!start.isValid()) {
|
|
kdWarning()<<k_funcinfo<<"Invalid start time"<<endl;
|
|
return TQPair<DateTime, DateTime>(DateTime(), DateTime());
|
|
}
|
|
if (!end.isValid()) {
|
|
kdWarning()<<k_funcinfo<<"Invalid end time"<<endl;
|
|
return TQPair<DateTime, DateTime>(DateTime(), DateTime());
|
|
}
|
|
TQTime startTime;
|
|
TQTime endTime;
|
|
TQDate date = start.date();
|
|
int i=0;
|
|
for (; date <= end.date(); date = date.addDays(1)) {
|
|
if (date < end.date())
|
|
endTime = TQTime(23, 59, 59, 999);
|
|
else
|
|
endTime = end.time();
|
|
if (date > start.date())
|
|
startTime = TQTime();
|
|
else
|
|
startTime = start.time();
|
|
|
|
TQPair<TQTime, TQTime> res = firstInterval(date, startTime, endTime);
|
|
if (res.first < res.second) {
|
|
return TQPair<DateTime, DateTime>(DateTime(date,res.first),DateTime(date, res.second));
|
|
}
|
|
}
|
|
//kdError()<<k_funcinfo<<"Didn't find an interval ("<<start<<", "<<end<<")"<<endl;
|
|
return TQPair<DateTime, DateTime>(DateTime(), DateTime());
|
|
}
|
|
|
|
|
|
bool Calendar::hasInterval(const TQDate &date, const TQTime &startTime, const TQTime &endTime) const {
|
|
CalendarDay *day = findDay(date, true);
|
|
if (day) {
|
|
//kdDebug()<<k_funcinfo<<m_name<<" "<<date<<": "<<startTime<<" to "<<endTime<<endl;
|
|
return day->hasInterval(startTime, endTime);
|
|
}
|
|
if (m_weekdays) {
|
|
if (m_weekdays->state(date) == Map::Working) {
|
|
return m_weekdays->hasInterval(date, startTime, endTime);
|
|
} else if (m_weekdays->state(date) == Map::NonWorking) {
|
|
return false;
|
|
}
|
|
}
|
|
if (m_parent && !m_parent->isDeleted()) {
|
|
return m_parent->hasInterval(date, startTime, endTime);
|
|
}
|
|
return project()->defaultCalendar()->hasInterval(date, startTime, endTime);
|
|
}
|
|
|
|
bool Calendar::hasInterval(const DateTime &start, const DateTime &end) const {
|
|
//kdDebug()<<k_funcinfo<<m_name<<": "<<start<<" - "<<end<<endl;
|
|
if (!start.isValid() || !end.isValid() || end <= start) {
|
|
//kdError()<<k_funcinfo<<"Invalid input: "<<(start.isValid()?"":"(start invalid) ")<<(end.isValid()?"":"(end invalid) ")<<(start>end?"":"(start<=end)")<<endl;
|
|
//kdDebug()<<kdBacktrace(8)<<endl;
|
|
return false;
|
|
}
|
|
TQTime startTime;
|
|
TQTime endTime;
|
|
TQDate date = start.date();
|
|
for (; date <= end.date(); date = date.addDays(1)) {
|
|
if (date < end.date())
|
|
endTime = TQTime(23, 59, 59, 999);
|
|
else
|
|
endTime = end.time();
|
|
if (date > start.date())
|
|
startTime = TQTime();
|
|
else
|
|
startTime = start.time();
|
|
|
|
if (hasInterval(date, startTime, endTime))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
DateTime Calendar::firstAvailableAfter(const DateTime &time, const DateTime &limit) {
|
|
//kdDebug()<<k_funcinfo<<m_name<<": check from "<<time.toString()<<" limit="<<limit.toString()<<endl;
|
|
if (!time.isValid() || !limit.isValid() || time >= limit) {
|
|
kdError()<<k_funcinfo<<"Invalid input: "<<(time.isValid()?"":"(time invalid) ")<<(limit.isValid()?"":"(limit invalid) ")<<(time>limit?"":"(time>=limit)")<<endl;
|
|
return DateTime();
|
|
}
|
|
if (!hasInterval(time, limit)) {
|
|
return DateTime();
|
|
}
|
|
DateTime t = firstInterval(time, limit).first;
|
|
//kdDebug()<<k_funcinfo<<m_name<<": "<<t.toString()<<endl;
|
|
return t;
|
|
}
|
|
|
|
DateTime Calendar::firstAvailableBefore(const DateTime &time, const DateTime &limit) {
|
|
//kdDebug()<<k_funcinfo<<m_name<<": check from "<<time.toString()<<" limit="<<limit.toString()<<endl;
|
|
if (!time.isValid() || !limit.isValid() || time <= limit) {
|
|
kdError()<<k_funcinfo<<"Invalid input: "<<(time.isValid()?"":"(time invalid) ")<<(limit.isValid()?"":"(limit invalid) ")<<(time>limit?"":"(time<=limit)")<<endl;
|
|
return DateTime();
|
|
}
|
|
DateTime lmt = time;
|
|
DateTime t = DateTime(time.date()); // start of first day
|
|
if (t == lmt)
|
|
t = TQDateTime(t.addDays(-1)); // in case time == start of day
|
|
if (t < limit)
|
|
t = limit; // always stop at limit (lower boundary)
|
|
DateTime res;
|
|
//kdDebug()<<k_funcinfo<<m_name<<": t="<<t<<", "<<lmt<<" limit="<<limit<<endl;
|
|
while (!res.isValid() && t >= limit) {
|
|
// check intervals for 1 day
|
|
DateTime r = firstInterval(t, lmt).second;
|
|
res = r;
|
|
// Find the last interval
|
|
while(r.isValid() && r < lmt) {
|
|
r = firstInterval(r, lmt).second;
|
|
if (r.isValid())
|
|
res = r;
|
|
//kdDebug()<<k_funcinfo<<m_name<<": r="<<r<<", "<<lmt<<" res="<<res<<endl;
|
|
}
|
|
if (!res.isValid()) {
|
|
if (t == limit) {
|
|
break;
|
|
}
|
|
lmt = t;
|
|
t = TQDateTime(t.addDays(-1));
|
|
if (t < limit) {
|
|
t = limit;
|
|
}
|
|
if (t == lmt)
|
|
break;
|
|
}
|
|
}
|
|
//kdDebug()<<k_funcinfo<<m_name<<": "<<res<<endl;
|
|
return res;
|
|
}
|
|
|
|
Calendar *Calendar::findCalendar(const TQString &id) const {
|
|
return (m_project ? m_project->findCalendar(id) : 0);
|
|
}
|
|
|
|
bool Calendar::removeId(const TQString &id) {
|
|
return (m_project ? m_project->removeCalendarId(id) : false);
|
|
}
|
|
|
|
void Calendar::insertId(const TQString &id){
|
|
if (m_project)
|
|
m_project->insertCalendarId(id, this);
|
|
}
|
|
|
|
/////////////
|
|
StandardWorktime::StandardWorktime() {
|
|
init();
|
|
}
|
|
|
|
StandardWorktime::StandardWorktime(StandardWorktime *worktime) {
|
|
if (worktime) {
|
|
m_year = worktime->durationYear();
|
|
m_month = worktime->durationMonth();
|
|
m_week = worktime->durationWeek();
|
|
m_day = worktime->durationDay();
|
|
m_calendar = new Calendar(*(worktime->calendar()));
|
|
} else {
|
|
init();
|
|
}
|
|
}
|
|
|
|
StandardWorktime::~StandardWorktime() {
|
|
//kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
|
|
}
|
|
|
|
void StandardWorktime::init() {
|
|
// Some sane default values
|
|
m_year = Duration(0, 1760, 0);
|
|
m_month = Duration(0, 176, 0);
|
|
m_week = Duration(0, 40, 0);
|
|
m_day = Duration(0, 8, 0);
|
|
m_calendar = new Calendar;
|
|
m_calendar->setName(i18n("Base"));
|
|
TQPair<TQTime, TQTime> t = TQPair<TQTime, TQTime>(TQTime(8,0,0), TQTime(16,0,0));
|
|
for (int i=0; i < 5; ++i) {
|
|
m_calendar->weekday(i)->addInterval(t);
|
|
m_calendar->weekday(i)->setState(Map::Working);
|
|
}
|
|
m_calendar->weekday(5)->setState(Map::NonWorking);
|
|
m_calendar->weekday(6)->setState(Map::NonWorking);
|
|
}
|
|
|
|
bool StandardWorktime::load(TQDomElement &element) {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
m_year = Duration::fromString(element.attribute("year"), Duration::Format_Hour);
|
|
m_month = Duration::fromString(element.attribute("month"), Duration::Format_Hour);
|
|
m_week = Duration::fromString(element.attribute("week"), Duration::Format_Hour);
|
|
m_day = Duration::fromString(element.attribute("day"), Duration::Format_Hour);
|
|
|
|
TQDomNodeList list = element.childNodes();
|
|
for (unsigned int i=0; i<list.count(); ++i) {
|
|
if (list.item(i).isElement()) {
|
|
TQDomElement e = list.item(i).toElement();
|
|
if (e.tagName() == "calendar") {
|
|
delete m_calendar;
|
|
m_calendar = new Calendar;
|
|
m_calendar->load(e);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void StandardWorktime::save(TQDomElement &element) const {
|
|
//kdDebug()<<k_funcinfo<<endl;
|
|
TQDomElement me = element.ownerDocument().createElement("standard-worktime");
|
|
element.appendChild(me);
|
|
me.setAttribute("year", m_year.toString(Duration::Format_Hour));
|
|
me.setAttribute("month", m_month.toString(Duration::Format_Hour));
|
|
me.setAttribute("week", m_week.toString(Duration::Format_Hour));
|
|
me.setAttribute("day", m_day.toString(Duration::Format_Hour));
|
|
|
|
m_calendar->save(me);
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
void CalendarDay::printDebug(TQCString indent) {
|
|
TQString s[] = {"None", "Non-working", "Working"};
|
|
kdDebug()<<indent<<" "<<m_date.toString()<<" = "<<s[m_state]<<endl;
|
|
if (m_state == Map::Working) {
|
|
indent += " ";
|
|
TQPtrListIterator<TQPair<TQTime, TQTime> > it = m_workingIntervals;
|
|
for (; it.current(); ++it) {
|
|
kdDebug()<<indent<<" Interval: "<<it.current()->first<<" to "<<it.current()->second<<endl;
|
|
}
|
|
}
|
|
|
|
}
|
|
void CalendarWeekdays::printDebug(TQCString indent) {
|
|
kdDebug()<<indent<<"Weekdays ------"<<endl;
|
|
TQPtrListIterator<CalendarDay> it = m_weekdays;
|
|
for (char c='0'; it.current(); ++it) {
|
|
it.current()->printDebug(indent + " Day " + c++ + ": ");
|
|
}
|
|
|
|
}
|
|
void Calendar::printDebug(TQCString indent) {
|
|
kdDebug()<<indent<<"Calendar "<<m_id<<": '"<<m_name<<"' Deleted="<<m_deleted<<endl;
|
|
kdDebug()<<indent<<" Parent: "<<(m_parent ? m_parent->name() : "No parent")<<endl;
|
|
m_weekdays->printDebug(indent + " ");
|
|
kdDebug()<<indent<<" Days --------"<<endl;
|
|
TQPtrListIterator<CalendarDay> it = m_days;
|
|
for (; it.current(); ++it) {
|
|
it.current()->printDebug(indent + " ");
|
|
}
|
|
}
|
|
|
|
void StandardWorktime::printDebug(TQCString indent) {
|
|
kdDebug()<<indent<<"StandardWorktime "<<endl;
|
|
kdDebug()<<indent<<"Year: "<<m_year.toString()<<endl;
|
|
kdDebug()<<indent<<"Month: "<<m_month.toString()<<endl;
|
|
kdDebug()<<indent<<"Week: "<<m_week.toString()<<endl;
|
|
kdDebug()<<indent<<"Day: "<<m_day.toString()<<endl;
|
|
}
|
|
|
|
#endif
|
|
|
|
} //KPlato namespace
|