diff --git a/src/libs/kernel/kptcalendar.cpp b/src/libs/kernel/kptcalendar.cpp index 8ed7bc4e..275b78b4 100644 --- a/src/libs/kernel/kptcalendar.cpp +++ b/src/libs/kernel/kptcalendar.cpp @@ -1,1766 +1,1766 @@ /* This file is part of the KDE project Copyright (C) 2003 - 2007, 2012 Dag Andersen Copyright (C) 2016 Dag Andersen Copyright (C) 2017 Dag Andersen 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; either version 2 of the License, or (at your option) any later version. 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. */ // clazy:excludeall=qstring-arg #include "kptcalendar.h" #include "kptappointment.h" #include "kptmap.h" #include "kptduration.h" #include "kptdatetime.h" #include "kptproject.h" #include "kptschedule.h" #include "kptxmlloaderobject.h" #include "kptcommand.h" #include "kptdebug.h" #include #include #ifdef HAVE_KHOLIDAYS #include #include #endif #include #include namespace KPlato { #ifdef HAVE_KHOLIDAYS // start qt-copy (with some changes) // Copyright (C) 2013 John Layt struct TzTimeZone { QString country; QByteArray comment; }; // Define as a type as Q_GLOBAL_STATIC doesn't like it typedef QHash TzTimeZoneHash; // Parse zone.tab table, assume lists all installed zones, if not will need to read directories static TzTimeZoneHash loadTzTimeZones() { QString path = QStringLiteral("/usr/share/zoneinfo/zone.tab"); if (!QFile::exists(path)) path = QStringLiteral("/usr/lib/zoneinfo/zone.tab"); QFile tzif(path); if (!tzif.open(QIODevice::ReadOnly)) return TzTimeZoneHash(); TzTimeZoneHash zonesHash; // TODO QTextStream inefficient, replace later QTextStream ts(&tzif); while (!ts.atEnd()) { const QString line = ts.readLine(); // Comment lines are prefixed with a # if (!line.isEmpty() && line.at(0) != '#') { // Data rows are tab-separated columns Region, Coordinates, ID, Optional Comments QStringList parts = line.split(QLatin1Char('\t')); TzTimeZone zone; zone.country = parts.at(0); if (parts.size() > 3) zone.comment = parts.at(3).toUtf8(); zonesHash.insert(parts.at(2).toUtf8(), zone); } } return zonesHash; } // Hash of available system tz files as loaded by loadTzTimeZones() Q_GLOBAL_STATIC_WITH_ARGS(const TzTimeZoneHash, tzZones, (loadTzTimeZones())); // end qt-copy #endif QString CalendarDay::stateToString( int st, bool trans ) { return ( st == None ) ? (trans ? i18n( "Undefined" ) : QStringLiteral( "Undefined" )) : ( st == NonWorking ) ? (trans ? i18n( "Non-working" ) : QStringLiteral( "Non-working" )) : ( st == Working ) ? (trans ? i18n( "Working" ) : QStringLiteral( "Working" )) : QString(); } QStringList CalendarDay::stateList( bool trans ) { QStringList lst; return trans ? lst << i18n( "Undefined" ) << i18n( "Non-working" ) << i18n( "Working" ) : lst << QStringLiteral("Undefined") << QStringLiteral("Non-working") << QStringLiteral("Working"); } ///// CalendarDay //// CalendarDay::CalendarDay() : m_date(), m_state(Undefined), m_calendar( 0 ) { //debugPlan<<"("<second)); me.setAttribute(QStringLiteral("start"), i->first.toString()); } } void CalendarDay::addInterval(TimeInterval *interval) { if (!interval) { return; } // TODO: check for overlapping intervals and handle them for what makes sense QList ::Iterator it; const QList ::Iterator end = m_timeIntervals.end(); QList ::Iterator position = end; for (it = m_timeIntervals.begin(); it != end; ++it) { // first found that is later? if ((*it)->startTime() > interval->startTime()) { // insert before position = it; break; } } m_timeIntervals.insert(position, interval); } bool CalendarDay::operator==(const CalendarDay *day) const { return operator==(*day); } bool CalendarDay::operator==(const CalendarDay &day) const { //debugPlan; if (m_date.isValid() && day.date().isValid()) { if (m_date != day.date()) { //debugPlan<first.toString()<<"-"<second.toString(); 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(QTime start, int length, const QTimeZone &timeZone, Schedule *sch) { // debugPlan<endsMidnight() && start >= i->endTime() ) { //debugPlan<<"Skip:"<="<first.addMSecs(i->second); continue; } QTime t1 = start.addMSecs( length ); if ( t1 != QTime( 0, 0, 0 ) && t1 < i->first ) { //debugPlan<<"Skip:"<first; continue; } t1 = qMax( start, i->first ); if ( i->endsMidnight() ) { l = t1.msecsTo( QTime( 23, 59, 59, 999 ) ) + 1; } else { l = t1.msecsTo( i->endTime() ); } l = qMin( l, length - start.msecsTo( t1 ) ); if ( l <= 0 ) { continue; } //debugPlan<<"Interval:"<"<available( dti ); //FIXME needs an effort method //debugPlan<<"Checked sch:"<first<<" -"<second; d += Duration( (qint64)i->second ); } return d; } TimeInterval CalendarDay::interval(QTime start, int length, const QTimeZone &timeZone, Schedule *sch) const { //debugPlan; return interval( m_date, start, length, timeZone, sch ); } TimeInterval CalendarDay::interval(QDate date, QTime start, int length, const QTimeZone &timeZone, Schedule *sch) const { //debugPlan<<"Inp:"< 0 ); Q_ASSERT( QTime(0,0,0).msecsTo( start ) + length <= 1000*60*60*24 ); QTime t1; int l = 0; if ( ! hasInterval() ) { return TimeInterval(); } foreach (TimeInterval *i, m_timeIntervals) { //debugPlan<<"Interval:"<first<second<first.addMSecs(i->second); if ( ! i->endsMidnight() && start >= i->endTime() ) { //debugPlan<<"Skip:"<="<first.addMSecs(i->second); continue; } QTime t1 = start.addMSecs( length ); if ( t1 != QTime( 0, 0, 0 ) && t1 < i->first ) { //debugPlan<<"Skip:"<first; continue; } t1 = qMax( start, i->first ); if ( i->endsMidnight() ) { l = t1.msecsTo( QTime( 23, 59, 59, 999 ) ) + 1; } else { l = t1.msecsTo( i->endTime() ); } l = qMin( l, length - start.msecsTo( t1 ) ); if ( l <= 0 ) { continue; } TimeInterval ti( t1, l ); //debugPlan<<"Day give:"<"<"<second ); } return dur; } void CalendarDay::removeInterval( TimeInterval *ti ) { m_timeIntervals.removeOne(ti); } int CalendarDay::numIntervals() const { return m_state == Working ? m_timeIntervals.count() : 0; } bool CalendarDay::hasInterval(const TimeInterval* interval) const { return m_timeIntervals.contains(const_cast(interval)); } DateTime CalendarDay::start() const { if ( m_state != Working || m_timeIntervals.isEmpty() ) { return DateTime(); } QDate date = m_date; if ( ! m_date.isValid() ) { date = QDate::currentDate(); } if ( m_calendar && m_calendar->timeZone().isValid() ) { return DateTime( date, m_timeIntervals.first()->startTime(), m_calendar->timeZone() ); } return DateTime( date, m_timeIntervals.first()->startTime() ); } DateTime CalendarDay::end() const { if ( m_state != Working || m_timeIntervals.isEmpty() ) { return DateTime(); } QDate date; if ( m_date.isValid() ) { date = m_timeIntervals.last()->endsMidnight() ? m_date.addDays( 1 ) : m_date; } else { date = QDate::currentDate(); } if ( m_calendar && m_calendar->timeZone().isValid() ) { return DateTime( date, m_timeIntervals.last()->endTime(), m_calendar->timeZone() ); } return DateTime( date, m_timeIntervals.last()->endTime() ); } ///// CalendarWeekdays //// CalendarWeekdays::CalendarWeekdays() : m_weekdays() { //debugPlan<<"--->"; for (int i=1; i <= 7; ++i) { m_weekdays.insert( i, new CalendarDay() ); } //debugPlan<<"<---"; } CalendarWeekdays::CalendarWeekdays( const CalendarWeekdays *weekdays ) : m_weekdays() { //debugPlan<<"--->"; copy(*weekdays); //debugPlan<<"<---"; } CalendarWeekdays::~CalendarWeekdays() { qDeleteAll( m_weekdays ); //debugPlan; } const CalendarWeekdays &CalendarWeekdays::copy(const CalendarWeekdays &weekdays) { //debugPlan; qDeleteAll( m_weekdays ); m_weekdays.clear(); QMapIterator i( weekdays.weekdayMap() ); while ( i.hasNext() ) { i.next(); m_weekdays.insert( i.key(), new CalendarDay( i.value() ) ); } return *this; } bool CalendarWeekdays::load( KoXmlElement &element, XMLLoaderObject &status ) { //debugPlan; bool ok; int dayNo = QString(element.attribute(QStringLiteral("day"),QStringLiteral("-1"))).toInt(&ok); if (dayNo < 0 || dayNo > 6) { errorPlan<<"Illegal weekday: "<load( element, status ) ) day->setState(CalendarDay::None); return true; } void CalendarWeekdays::save(QDomElement &element) const { //debugPlan; QMapIterator i( m_weekdays ); while ( i.hasNext() ) { i.next(); QDomElement me = element.ownerDocument().createElement(QStringLiteral("weekday")); element.appendChild(me); me.setAttribute( QStringLiteral("day"), QString::number(i.key() - 1) ); // 0 (monday) .. 6 (sunday) i.value()->save(me); } } const QMap &CalendarWeekdays::weekdayMap() const { return m_weekdays; } IntMap CalendarWeekdays::stateMap() const { IntMap days; QMapIterator i( m_weekdays ); while ( i.hasNext() ) { i.next(); if ( i.value()->state() != CalendarDay::None ) days.insert( i.key(), i.value()->state() ); } return days; } int CalendarWeekdays::state(QDate date) const { return state( date.dayOfWeek() ); } int CalendarWeekdays::state( int weekday ) const { CalendarDay *day = m_weekdays.value( weekday ); return day ? day->state() : CalendarDay::None; } void CalendarWeekdays::setState(int weekday, int state) { CalendarDay *day = m_weekdays.value( weekday ); if ( day == 0 ) return; day->setState(state); } QList CalendarWeekdays::intervals(int weekday) const { CalendarDay *day = m_weekdays.value( weekday ); Q_ASSERT(day); return day->timeIntervals(); } void CalendarWeekdays::setIntervals(int weekday, const QList &intervals) { CalendarDay *day = m_weekdays.value( weekday ); if (day) { day->setIntervals( intervals ); } } void CalendarWeekdays::clearIntervals(int weekday) { CalendarDay *day = m_weekdays.value( weekday ); if (day) { day->clearIntervals(); } } bool CalendarWeekdays::operator==(const CalendarWeekdays *wd) const { if (m_weekdays.count() != wd->weekdays().count()) { return false; } QMapIterator i( wd->weekdayMap() ); while ( i.hasNext() ) { i.next(); CalendarDay *day1 = i.value(); CalendarDay *day2 = m_weekdays.value( i.key() ); if (day1 != day2) return false; } return true; } bool CalendarWeekdays::operator!=(const CalendarWeekdays *wd) const { return operator==( wd ) == false; } Duration CalendarWeekdays::effort(QDate date, QTime start, int length, const QTimeZone &timeZone, Schedule *sch) { // debugPlan<<"Day of week="<state() == CalendarDay::Working) { return day->effort(date, start, length, timeZone, sch); } return Duration::zeroDuration; } TimeInterval CalendarWeekdays::interval(QDate date, QTime start, int length, const QTimeZone &timeZone, Schedule *sch) const { //debugPlan; CalendarDay *day = weekday( date.dayOfWeek() ); if (day && day->state() == CalendarDay::Working) { return day->interval(date, start, length, timeZone, sch); } return TimeInterval(); } bool CalendarWeekdays::hasInterval(QDate date, QTime start, int length, const QTimeZone &timeZone, Schedule *sch) const { //debugPlan<hasInterval(date, start, length, timeZone, sch); } bool CalendarWeekdays::hasInterval() const { //debugPlan; foreach ( CalendarDay *d, m_weekdays ) { if (d->hasInterval()) return true; } return false; } CalendarDay *CalendarWeekdays::weekday( int day ) const { Q_ASSERT( day >= 1 && day <= 7 ); Q_ASSERT( m_weekdays.contains( day ) ); return m_weekdays.value( day ); } //static int CalendarWeekdays::dayOfWeek(const QString& name) { QStringList lst; lst << QStringLiteral("Monday") << QStringLiteral("Tuesday") << QStringLiteral("Wednesday") << QStringLiteral("Thursday") << QStringLiteral("Friday") << QStringLiteral("Saturday") << QStringLiteral("Sunday"); int idx = -1; if ( lst.contains( name ) ) { idx = lst.indexOf( name ) + 1; } return idx; } Duration CalendarWeekdays::duration() const { Duration dur; foreach ( CalendarDay *d, m_weekdays ) { dur += d->duration(); } return dur; } Duration CalendarWeekdays::duration(int _weekday) const { CalendarDay *day = weekday(_weekday); if (day) return day->duration(); return Duration(); } int CalendarWeekdays::indexOf( const CalendarDay *day ) const { return m_weekdays.key(const_cast(day)); } ///// Calendar //// Calendar::Calendar() : QObject( 0 ), // don't use parent m_parent(0), m_project(0), m_default( false ), m_shared(false) { init(); } Calendar::Calendar(const QString& name, Calendar *parent) : QObject( 0 ), // don't use parent m_name(name), m_parent(parent), m_project(0), m_days(), m_default( false ), m_shared(false) { init(); } Calendar::~Calendar() { //debugPlan<<"deleting"<regionCode()); #endif foreach (CalendarDay *d, calendar.days()) { m_days.append(new CalendarDay(d)); } delete m_weekdays; m_weekdays = new CalendarWeekdays(calendar.weekdays()); return *this; } void Calendar::init() { #ifdef HAVE_KHOLIDAYS m_region = new KHolidays::HolidayRegion(); #endif m_weekdays = new CalendarWeekdays(); m_timeZone = QTimeZone::systemTimeZone(); m_cacheversion = 0; m_blockversion = false; } int Calendar::cacheVersion() const { return m_parent ? m_parent->cacheVersion() : m_cacheversion; } void Calendar::incCacheVersion() { if ( m_blockversion ) { return; } if ( m_parent ) { m_parent->incCacheVersion(); } else { ++m_cacheversion; debugPlan<setCacheVersion( version ); } else { m_cacheversion = version; debugPlan<changed( this ); } } void Calendar::setParentCal( Calendar *parent, int pos ) { if ( m_parent ) { m_parent->takeCalendar( this ); } m_parent = parent; if ( m_parent ) { m_parent->addCalendar( this, pos ); } } bool Calendar::isChildOf( const Calendar *cal ) const { Calendar *p = parentCal(); for (; p != 0; p = p->parentCal() ) { if ( cal == p ) { return true; } } return false; } void Calendar::setProject(Project *project) { m_project = project; } void Calendar::setTimeZone( const QTimeZone &tz ) { if (m_timeZone == tz) { return; } //debugPlan<name(); m_timeZone = tz; #ifdef HAVE_KHOLIDAYS if (m_regionCode == QLatin1String("Default")) { setHolidayRegion(QStringLiteral("Default")); } #endif if ( m_project ) { m_project->changed( this ); } incCacheVersion(); } QTimeZone Calendar::projectTimeZone() const { return m_project ? m_project->timeZone() : QTimeZone::systemTimeZone(); } void Calendar::setDefault( bool on ) { m_default = on; if ( m_project ) { m_project->changed( this ); } incCacheVersion(); } // Note: only project should do this void Calendar::setId(const QString& id) { //debugPlan<setTimeZone( m_timeZone ); } void Calendar::takeCalendar( Calendar *calendar ) { int i = indexOf( calendar ); if ( i != -1 ) { m_calendars.removeAt( i ); } } int Calendar::indexOf( const Calendar *calendar ) const { return m_calendars.indexOf( const_cast(calendar) ); } bool Calendar::loadCacheVersion( KoXmlElement &element, XMLLoaderObject &status ) { Q_UNUSED(status); m_cacheversion = element.attribute( QStringLiteral("version"), 0 ).toInt(); debugPlan<load( e, status ) ) return false; } if (e.tagName() == QLatin1String("day")) { CalendarDay *day = new CalendarDay(); if ( day->load( e, status ) ) { if (!day->date().isValid()) { delete day; errorPlan<date()); if (d) { // already exists, keep the new delete takeDay(d); warnPlan<id()); } me.setAttribute(QStringLiteral("name"), m_name); me.setAttribute(QStringLiteral("id"), m_id); if ( m_default ) { me.setAttribute(QStringLiteral("default"), QString::number(m_default)); } me.setAttribute(QStringLiteral("timezone"), m_timeZone.isValid() ? QString::fromLatin1(m_timeZone.id()) : QString()); m_weekdays->save(me); foreach (CalendarDay *d, m_days) { QDomElement e = me.ownerDocument().createElement(QStringLiteral("day")); me.appendChild(e); d->save(e); } me.setAttribute(QStringLiteral("shared"), m_shared); #ifdef HAVE_KHOLIDAYS me.setAttribute(QStringLiteral("holiday-region"), m_regionCode); #endif saveCacheVersion( me ); } int Calendar::state(QDate date) const { if (!date.isValid()) { return CalendarDay::Undefined; } CalendarDay *day = findDay( date ); if ( day && day->state() != CalendarDay::Undefined ) { return day->state(); } #ifdef HAVE_KHOLIDAYS if (isHoliday(date)) { return CalendarDay::NonWorking; } #endif day = weekday( date.dayOfWeek() ); if ( day && day->state() != CalendarDay::Undefined ) { return day->state(); } return m_parent ? m_parent->state( date ) : CalendarDay::Undefined; } CalendarDay *Calendar::findDay(QDate date, bool skipUndefined) const { //debugPlan<date() == date) { if (skipUndefined && d->state() == CalendarDay::Undefined) { continue; // hmmm, break? } return d; } } //debugPlan<setState( state ); emit changed( day ); incCacheVersion(); } void Calendar::addWorkInterval( CalendarDay *day, TimeInterval *ti ) { emit workIntervalToBeAdded( day, ti, day->numIntervals() ); day->addInterval( ti ); emit workIntervalAdded( day, ti ); incCacheVersion(); } void Calendar::takeWorkInterval( CalendarDay *day, TimeInterval *ti ) { if ( !day->hasInterval(ti) ) { return; } emit workIntervalToBeRemoved( day, ti ); day->removeInterval( ti ); emit workIntervalRemoved( day, ti ); incCacheVersion(); return; } void Calendar::setWorkInterval( TimeInterval *ti, const TimeInterval &value ) { *ti = value; emit changed( ti ); incCacheVersion(); } void Calendar::setDate( CalendarDay *day, QDate date ) { day->setDate( date ); emit changed( day ); incCacheVersion(); } CalendarDay *Calendar::day( QDate date ) const { foreach ( CalendarDay *d, m_days ) { if ( d->date() == date ) { return d; } } return 0; } IntMap Calendar::weekdayStateMap() const { return m_weekdays->stateMap(); } void Calendar::setWeekday( int dayno, const CalendarDay &day ) { if ( dayno < 1 || dayno > 7 ) { return; } CalendarDay *wd = weekday( dayno ); while ( ! wd->timeIntervals().isEmpty() ) { TimeInterval *ti = wd->timeIntervals().constLast(); emit workIntervalToBeRemoved( wd, ti ); wd->removeInterval( ti ); emit workIntervalRemoved( wd, ti ); } wd->setState( day.state() ); emit changed( wd ); foreach ( TimeInterval *ti, day.timeIntervals() ) { TimeInterval *t = new TimeInterval( *ti ); emit workIntervalToBeAdded( wd, t, wd->numIntervals() ); // hmmmm wd->addInterval( t ); emit workIntervalAdded( wd, t ); } incCacheVersion(); } bool Calendar::hasParent(Calendar *cal) { //debugPlan; if (!m_parent) return false; if (m_parent == cal) return true; return m_parent->hasParent(cal); } AppointmentIntervalList Calendar::workIntervals( const QDateTime &start, const QDateTime &end, double load ) const { //debugPlan< start.date()) { startTime = QTime(0, 0, 0); } if (date < end.date()) { length = startTime.msecsTo( QTime(23, 59, 59, 999) ) + 1; } else { length = startTime.msecsTo( end.time() ); } if ( length <= 0 ) { break; } res = firstInterval( date, startTime, length ); while ( res.isValid() ) { //debugPlan<<"interval:"<= end ) { warnPlan<<"Invalid interval"; return lst; } Q_ASSERT(m_timeZone.isValid()); QDateTime zonedStart = start.toTimeZone( m_timeZone ); QDateTime zonedEnd = end.toTimeZone( m_timeZone ); Q_ASSERT( zonedStart.isValid() && zonedEnd.isValid() ); return workIntervals( zonedStart, zonedEnd, load ); } Duration Calendar::effort(QDate date, QTime start, int length, Schedule *sch) const { // debugPlan<"<state() == CalendarDay::Working) { return day->effort(start, length, m_timeZone, sch); } else if (day->state() == CalendarDay::NonWorking) { return Duration::zeroDuration; } else { errorPlan<<"Invalid state: "<state(); return Duration::zeroDuration; } } #ifdef HAVE_KHOLIDAYS if (isHoliday(date)) { return Duration::zeroDuration; } #endif // check my own weekdays if (m_weekdays) { if (m_weekdays->state(date) == CalendarDay::Working) { return m_weekdays->effort(date, start, length, m_timeZone, sch); } if (m_weekdays->state(date) == CalendarDay::NonWorking) { return Duration::zeroDuration; } } if (m_parent) { return m_parent->effort(date, start, length, sch); } return Duration::zeroDuration; } Duration Calendar::effort(const QDateTime &start, const QDateTime &end, Schedule *sch) const { // debugPlan< t0 ) { eff += effort(date, t0, t0.msecsTo( endTime ), sch); // last day } //debugPlan<<": eff now="<resource() ) debugPlan<resource()->name()<name()<<"Available:"<resource()->availableFrom()<resource()->availableUntil(); errorPlan<<"Illegal datetime: "<interval(startTime, length, m_timeZone, sch); } #ifdef HAVE_KHOLIDAYS if (isHoliday(date)) { return TimeInterval(); } #endif if (m_weekdays) { if (m_weekdays->state(date) == CalendarDay::Working) { //debugPlan<<"Check weekday"; TimeInterval i = m_weekdays->interval(date, startTime, length, m_timeZone, sch); //debugPlan<<"Checked weekday, got"<state(date) == CalendarDay::NonWorking) { return TimeInterval(); } } if (m_parent) { //debugPlan<<"Check parent"; return m_parent->firstInterval(date, startTime, length, sch); } return TimeInterval(); } DateTimeInterval Calendar::firstInterval( const QDateTime &start, const QDateTime &end, Schedule *sch) const { TimeInterval res; QTime startTime = start.time(); int length = 0; if ( start.date() == end.date() ) { // Handle single day length = startTime.msecsTo( end.time() ); if ( length <= 0 ) { warnPlan<<"Invalid length"< start.date()) { startTime = QTime(0, 0, 0); } if (date < end.date()) { length = startTime.msecsTo( QTime(23, 59, 59, 999) ) + 1; } else { length = startTime.msecsTo( end.time() ); } if ( length <= 0 ) { break; } //debugPlan<<"Check:"<= end ) { warnPlan<<"Invalid interval"<limit?"":"(time>limit)"); return DateTime(); } if ( time == limit ) { return DateTime(); } Q_ASSERT( m_timeZone.isValid() ); QDateTime zonedTime = time.toTimeZone( m_timeZone ); QDateTime zonedLimit = limit.toTimeZone( m_timeZone ); Q_ASSERT( zonedTime.isValid() && zonedLimit.isValid() ); return firstInterval( zonedTime, zonedLimit, sch ).first; } DateTime Calendar::firstAvailableBefore(const QDateTime &time, const QDateTime &limit, Schedule *sch) { debugPlan<findCalendar(id) : 0); } bool Calendar::removeId(const QString &id) { return (m_project ? m_project->removeCalendarId(id) : false); } void Calendar::insertId(const QString &id){ if (m_project) m_project->insertCalendarId(id, this); } void Calendar::addDay( CalendarDay *day ) { emit dayToBeAdded( day, 0 ); m_days.insert(0, day); emit dayAdded( day ); incCacheVersion(); } CalendarDay *Calendar::takeDay(CalendarDay *day) { int i = m_days.indexOf(day); if (i == -1) { return 0; } emit dayToBeRemoved( day ); m_days.removeAt(i); emit dayRemoved( day ); incCacheVersion(); return day; } QList > Calendar::consecutiveVacationDays() const { QList > lst; std::pair interval( 0, 0 ); foreach ( CalendarDay* day, m_days ) { if ( day->state() == CalendarDay::NonWorking ) { if ( interval.first == 0 ) { interval.first = day; } interval.second = day; } else { if ( interval.first != 0 ) { lst << std::pair( interval ); } interval.first = interval.second = 0; } } return lst; } QList Calendar::workingDays() const { QList lst; foreach ( CalendarDay* day, m_days ) { if ( day->state() == CalendarDay::Working ) { lst << day; } } return lst; } bool Calendar::isShared() const { return m_shared; } void Calendar::setShared(bool on) { m_shared = on; } #ifdef HAVE_KHOLIDAYS bool Calendar::isHoliday(QDate date) const { if (m_region->isValid()) { KHolidays::Holiday::List lst = m_region->holidays(date); if (!lst.isEmpty() && lst.first().dayType() != KHolidays::Holiday::Workday) { return true; } } return false; } KHolidays::HolidayRegion *Calendar::holidayRegion() const { return m_region; } void Calendar::setHolidayRegion(const QString &code) { delete m_region; m_regionCode = code; if (code == QLatin1String("Default")) { QString country; if (m_timeZone.isValid()) { // TODO be more accurate when country has multiple timezones/regions country = tzZones->value(m_timeZone.id()).country; } m_region = new KHolidays::HolidayRegion(KHolidays::HolidayRegion::defaultRegionCode(country)); } else { m_region = new KHolidays::HolidayRegion(code); } debugPlan<"<isValid(); emit changed(static_cast(0)); if (m_project) { m_project->changed(this); } } QString Calendar::holidayRegionCode() const { return m_regionCode; } QStringList Calendar::holidayRegionCodes() const { QStringList lst = KHolidays::HolidayRegion::regionCodes(); lst.removeDuplicates(); return lst; } #endif ///////////// StandardWorktime::StandardWorktime( Project *project ) : m_project( project ) { init(); } StandardWorktime::StandardWorktime(StandardWorktime *worktime) { if (worktime) { m_year = worktime->durationYear(); m_month = worktime->durationMonth(); m_week = worktime->durationWeek(); m_day = worktime->durationDay(); } else { init(); } } StandardWorktime::~StandardWorktime() { //debugPlan<<"("<changed( this ); } } QList StandardWorktime::scales() const { return QList() << m_year.milliseconds() << m_month.milliseconds() << m_week.milliseconds() << m_day.milliseconds() << 60*60*1000 << 60*1000 << 1000 << 1; } bool StandardWorktime::load( KoXmlElement &element, XMLLoaderObject &status ) { //debugPlan; m_year = Duration::fromString(element.attribute(QStringLiteral("year")), Duration::Format_Hour); m_month = Duration::fromString(element.attribute(QStringLiteral("month")), Duration::Format_Hour); m_week = Duration::fromString(element.attribute(QStringLiteral("week")), Duration::Format_Hour); m_day = Duration::fromString(element.attribute(QStringLiteral("day")), Duration::Format_Hour); KoXmlNode n = element.firstChild(); for ( ; ! n.isNull(); n = n.nextSibling() ) { if ( ! n.isElement() ) { continue; } KoXmlElement e = n.toElement(); if (e.tagName() == QLatin1String("calendar")) { // pre 0.6 version stored base calendar in standard worktime if ( status.version() >= QLatin1String("0.6") ) { warnPlan<<"Old format, calendar in standard worktime"; warnPlan<<"Tries to load anyway"; } // try to load anyway Calendar *calendar = new Calendar; if ( calendar->load( e, status ) ) { status.project().addCalendar( calendar ); calendar->setDefault( true ); status.project().setDefaultCalendar( calendar ); // hmmm status.setBaseCalendar( calendar ); } else { delete calendar; errorPlan<<"Failed to load calendar"; } } } return true; } void StandardWorktime::save(QDomElement &element) const { //debugPlan; QDomElement me = element.ownerDocument().createElement(QStringLiteral("standard-worktime")); element.appendChild(me); me.setAttribute(QStringLiteral("year"), m_year.toString(Duration::Format_Hour)); me.setAttribute(QStringLiteral("month"), m_month.toString(Duration::Format_Hour)); me.setAttribute(QStringLiteral("week"), m_week.toString(Duration::Format_Hour)); me.setAttribute(QStringLiteral("day"), m_day.toString(Duration::Format_Hour)); } } //KPlato namespace QString stateToString(int state) { const QStringList lst = QStringList() << "U" << "N" << "W"; return lst.value(state); } QDebug operator<<(QDebug dbg, KPlato::Calendar *c) { if (!c) { return dbg << "Calendar[0x0]"; } dbg << "Calendar[" << c->name(); for (int i = 1; i <= 7; ++i) { if (c->weekday(i)) { dbg << endl << '\t' << i << ':' << c->weekday(i); } } foreach(const KPlato::CalendarDay *day, c->days()) { dbg << endl << '\t'<< day; } dbg << endl << ']'; return dbg; } QDebug operator<<(QDebug dbg, KPlato::CalendarWeekdays *w) { if (!w) { return dbg << "Weekdays[0x0]"; } dbg << "Weekdays:" << w->weekdayMap(); return dbg; } QDebug operator<<(QDebug dbg, KPlato::CalendarDay *day) { if (!day) { return dbg << "Day[0x0]"; } dbg << "Day[" << stateToString(day->state()); if (day->date().isValid()) { dbg << day->date(); } - for(int i; i < day->numIntervals(); ++i) { + for(int i = 0; i < day->numIntervals(); ++i) { dbg << *(day->timeIntervals().at(i)); } dbg << "]"; return dbg; } QDebug operator<<(QDebug dbg, KPlato::StandardWorktime *wt) { dbg << "Standard"; return dbg; }