diff --git a/src/libs/kernel/kptcalendar.cpp b/src/libs/kernel/kptcalendar.cpp index aafb0ec2..8ed7bc4e 100644 --- a/src/libs/kernel/kptcalendar.cpp +++ b/src/libs/kernel/kptcalendar.cpp @@ -1,1763 +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) { dbg << *(day->timeIntervals().at(i)); } dbg << "]"; return dbg; } QDebug operator<<(QDebug dbg, KPlato::StandardWorktime *wt) { dbg << "Standard"; return dbg; } diff --git a/src/libs/models/kptresourceappointmentsmodel.cpp b/src/libs/models/kptresourceappointmentsmodel.cpp index 5517afde..b1fcadb8 100644 --- a/src/libs/models/kptresourceappointmentsmodel.cpp +++ b/src/libs/models/kptresourceappointmentsmodel.cpp @@ -1,2032 +1,2032 @@ /* This file is part of the KDE project Copyright (C) 2007, 2011, 2012 Dag Andersen danders@get2net> 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 "kptresourceappointmentsmodel.h" #include "kptglobal.h" #include "kptcommonstrings.h" #include "kptappointment.h" #include "kptcommand.h" #include "kpteffortcostmap.h" #include "kptitemmodelbase.h" #include "kptcalendar.h" #include "kptduration.h" #include "kptnode.h" #include "kptproject.h" #include "kpttask.h" #include "kptresource.h" #include "kptdatetime.h" #include "kptdebug.h" #include #include #include #include #include #include namespace KPlato { ResourceAppointmentsItemModel::ResourceAppointmentsItemModel( QObject *parent ) : ItemModelBase( parent ), m_group( 0 ), m_resource( 0 ), m_showInternal( true ), m_showExternal( true ) { } ResourceAppointmentsItemModel::~ResourceAppointmentsItemModel() { } void ResourceAppointmentsItemModel::slotResourceToBeInserted( const ResourceGroup *group, int row ) { debugPlan<name()<(group); QModelIndex i = index( group ); beginInsertRows( i, row, row ); } void ResourceAppointmentsItemModel::slotResourceInserted( const Resource *r ) { debugPlan<name(); Q_ASSERT( r->parentGroup() == m_group ); endInsertRows(); m_group = 0; refresh(); connect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsItemModel::slotAppointmentToBeInserted ); connect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsItemModel::slotAppointmentInserted ); connect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentToBeRemoved ); connect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentRemoved ); connect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsItemModel::slotAppointmentChanged ); } void ResourceAppointmentsItemModel::slotResourceToBeRemoved( const Resource *r ) { debugPlan<name(); int row = r->parentGroup()->indexOf( r ); beginRemoveRows( index( r->parentGroup() ), row, row ); disconnect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsItemModel::slotAppointmentToBeInserted ); disconnect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsItemModel::slotAppointmentInserted ); disconnect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentToBeRemoved ); disconnect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentRemoved ); disconnect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsItemModel::slotAppointmentChanged ); } void ResourceAppointmentsItemModel::slotResourceRemoved( const Resource *resource ) { Q_UNUSED(resource); //debugPlan<name(); endRemoveRows(); refresh(); } void ResourceAppointmentsItemModel::slotResourceGroupToBeInserted( const ResourceGroup *group, int row ) { //debugPlan<name()<(group); beginInsertRows( QModelIndex(), row, row ); } void ResourceAppointmentsItemModel::slotResourceGroupInserted( const ResourceGroup *group ) { //debugPlan<name()<name()<(group); int row = index( group ).row(); beginRemoveRows( QModelIndex(), row, row ); } void ResourceAppointmentsItemModel::slotResourceGroupRemoved( const ResourceGroup *group ) { //debugPlan<name()<= 0 ); refreshData(); emit dataChanged( createExternalAppointmentIndex( row, 0, a ), createExternalAppointmentIndex( row, columnCount() - 1, a ) ); } void ResourceAppointmentsItemModel::slotProjectCalculated( ScheduleManager *sm ) { if ( sm == m_manager ) { setScheduleManager( sm ); } } int ResourceAppointmentsItemModel::rowNumber( Resource *res, Appointment *a ) const { int r = 0; if ( m_showInternal ) { r = res->appointments( id() ).indexOf( a ); if ( r > -1 ) { return r; } r = res->numAppointments(); } if ( m_showExternal ) { int rr = res->externalAppointmentList().indexOf( a ); if ( rr > -1 ) { return r + rr; } } return -1; } void ResourceAppointmentsItemModel::setShowInternalAppointments( bool show ) { if ( m_showInternal == show ) { return; } beginResetModel(); m_showInternal = show; refreshData(); endResetModel(); } void ResourceAppointmentsItemModel::setShowExternalAppointments( bool show ) { if ( m_showExternal == show ) { return; } beginResetModel(); m_showExternal = show; refreshData(); endResetModel(); } void ResourceAppointmentsItemModel::setProject( Project *project ) { beginResetModel(); debugPlan; if ( m_project ) { disconnect(m_project, &Project::aboutToBeDeleted, this, &ResourceAppointmentsItemModel::projectDeleted); disconnect( m_project, &Project::resourceChanged, this, &ResourceAppointmentsItemModel::slotResourceChanged ); disconnect( m_project, &Project::resourceGroupChanged, this, &ResourceAppointmentsItemModel::slotResourceGroupChanged ); disconnect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceAppointmentsItemModel::slotResourceGroupToBeInserted ); disconnect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceAppointmentsItemModel::slotResourceGroupToBeRemoved ); disconnect( m_project, &Project::resourceToBeAdded, this, &ResourceAppointmentsItemModel::slotResourceToBeInserted ); disconnect( m_project, &Project::resourceToBeRemoved, this, &ResourceAppointmentsItemModel::slotResourceToBeRemoved ); disconnect( m_project, &Project::resourceGroupAdded, this, &ResourceAppointmentsItemModel::slotResourceGroupInserted ); disconnect( m_project, &Project::resourceGroupRemoved, this, &ResourceAppointmentsItemModel::slotResourceGroupRemoved ); disconnect( m_project, &Project::resourceAdded, this, &ResourceAppointmentsItemModel::slotResourceInserted ); disconnect( m_project, &Project::resourceRemoved, this, &ResourceAppointmentsItemModel::slotResourceRemoved ); disconnect( m_project, &Project::defaultCalendarChanged, this, &ResourceAppointmentsItemModel::slotCalendarChanged ); disconnect( m_project, &Project::projectCalculated, this, &ResourceAppointmentsItemModel::slotProjectCalculated ); disconnect( m_project, &Project::scheduleManagerChanged, this, &ResourceAppointmentsItemModel::slotProjectCalculated ); foreach ( Resource *r, m_project->resourceList() ) { disconnect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsItemModel::slotAppointmentToBeInserted ); disconnect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsItemModel::slotAppointmentInserted ); disconnect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentToBeRemoved ); disconnect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentRemoved ); disconnect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsItemModel::slotAppointmentChanged ); } } m_project = project; if ( m_project ) { connect(m_project, &Project::aboutToBeDeleted, this, &ResourceAppointmentsItemModel::projectDeleted); connect( m_project, &Project::resourceChanged, this, &ResourceAppointmentsItemModel::slotResourceChanged ); connect( m_project, &Project::resourceGroupChanged, this, &ResourceAppointmentsItemModel::slotResourceGroupChanged ); connect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceAppointmentsItemModel::slotResourceGroupToBeInserted ); connect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceAppointmentsItemModel::slotResourceGroupToBeRemoved ); connect( m_project, &Project::resourceToBeAdded, this, &ResourceAppointmentsItemModel::slotResourceToBeInserted ); connect( m_project, &Project::resourceToBeRemoved, this, &ResourceAppointmentsItemModel::slotResourceToBeRemoved ); connect( m_project, &Project::resourceGroupAdded, this, &ResourceAppointmentsItemModel::slotResourceGroupInserted ); connect( m_project, &Project::resourceGroupRemoved, this, &ResourceAppointmentsItemModel::slotResourceGroupRemoved ); connect( m_project, &Project::resourceAdded, this, &ResourceAppointmentsItemModel::slotResourceInserted ); connect( m_project, &Project::resourceRemoved, this, &ResourceAppointmentsItemModel::slotResourceRemoved ); connect( m_project, &Project::defaultCalendarChanged, this, &ResourceAppointmentsItemModel::slotCalendarChanged ); connect( m_project, &Project::projectCalculated, this, &ResourceAppointmentsItemModel::slotProjectCalculated ); connect( m_project, &Project::scheduleManagerChanged, this, &ResourceAppointmentsItemModel::slotProjectCalculated ); foreach ( Resource *r, m_project->resourceList() ) { connect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsItemModel::slotAppointmentToBeInserted ); connect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsItemModel::slotAppointmentInserted ); connect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentToBeRemoved ); connect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsItemModel::slotAppointmentRemoved ); connect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsItemModel::slotAppointmentChanged ); } } refreshData(); endResetModel(); emit refreshed(); } QDate ResourceAppointmentsItemModel::startDate() const { if ( m_project && m_manager ) { return m_project->startTime( id() ).date(); } return QDate::currentDate(); } QDate ResourceAppointmentsItemModel::endDate() const { if ( m_project && m_manager ) { return m_project->endTime( id() ).date(); } return QDate::currentDate(); } void ResourceAppointmentsItemModel::setScheduleManager( ScheduleManager *sm ) { if (sm == m_manager) { return; } beginResetModel(); debugPlan<scheduleId(); } Qt::ItemFlags ResourceAppointmentsItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = ItemModelBase::flags( index ); return flags &= ~Qt::ItemIsEditable; } QModelIndex ResourceAppointmentsItemModel::parent( const QModelIndex &idx ) const { if ( !idx.isValid() || m_project == 0 || m_manager == 0 ) { warnPlan<<"No data "<indexOf( r->parentGroup() ); p = createGroupIndex( row, 0, r->parentGroup() ); //debugPlan<<"Parent:"<parentGroup()->name(); Q_ASSERT( p.isValid() ); } } if ( ! p.isValid() && m_showInternal ) { Appointment *a = appointment( idx ); if ( a && a->resource() && a->resource()->resource() ) { Resource *r = a->resource()->resource(); int row = r->parentGroup()->indexOf( r ); p = createResourceIndex( row, 0, r ); //debugPlan<<"Parent:"<name(); Q_ASSERT( p.isValid() ); } } if ( ! p.isValid() && m_showExternal ) { Appointment *a = externalAppointment( idx ); Resource *r = parent( a ); if ( r ) { int row = r->parentGroup()->indexOf( r ); p = createResourceIndex( row, 0, r ); } } if ( ! p.isValid() ) { //debugPlan<<"Parent:"<resourceList() ) { if ( r->appointments( id() ).contains( const_cast( a ) ) ) { return r; } if ( r->externalAppointmentList().contains( const_cast( a ) ) ) { return r; } } return 0; } QModelIndex ResourceAppointmentsItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_project == 0 || m_manager == 0 ) { return QModelIndex(); } if ( ! parent.isValid() ) { if ( row < m_project->numResourceGroups() ) { //debugPlan<<"Group: "<resourceGroupAt( row )<resourceGroupAt( row ) ); } return QModelIndex(); } ResourceGroup *g = resourcegroup( parent ); if ( g ) { if ( row < g->numResources() ) { //debugPlan<<"Resource: "<resourceAt( row )<resourceAt( row ) ); } return QModelIndex(); } Resource *r = resource( parent ); if ( r && ( m_showInternal || m_showExternal ) ) { int num = m_showInternal ? r->numAppointments( id() ) : 0; if ( row < num ) { //debugPlan<<"Appointment: "<appointmentAt( row, m_manager->scheduleId() ); return createAppointmentIndex( row, column, r->appointmentAt( row, id() ) ); } int extRow = row - num; //debugPlan<<"Appointment: "<externalAppointmentList().value( extRow ); Q_ASSERT( extRow >= 0 && extRow < r->externalAppointmentList().count() ); return createExternalAppointmentIndex( row, column, r->externalAppointmentList().value( extRow ) ); } return QModelIndex(); } QModelIndex ResourceAppointmentsItemModel::index( const Resource *resource ) const { if ( m_project == 0 || resource == 0 ) { return QModelIndex(); } Resource *r = const_cast(resource); int row = -1; ResourceGroup *par = r->parentGroup(); if ( par ) { row = par->indexOf( r ); return createResourceIndex( row, 0, r ); } return QModelIndex(); } QModelIndex ResourceAppointmentsItemModel::index( const ResourceGroup *group ) const { if ( m_project == 0 || group == 0 ) { return QModelIndex(); } ResourceGroup *g = const_cast(group); int row = m_project->indexOf( g ); return createGroupIndex( row, 0, g ); } void ResourceAppointmentsItemModel::refresh() { refreshData(); emit refreshed(); } void ResourceAppointmentsItemModel::refreshData() { long id = m_manager == 0 ? -1 : m_manager->scheduleId(); //debugPlan<<"Schedule id: "< ec; QHash extEff; foreach ( Resource *r, m_project->resourceList() ) { foreach (Appointment* a, r->appointments( id )) { QDate s = a->startTime().date(); QDate e = a->endTime().date(); ec[ a ] = a->plannedPrDay( s, e ); if ( ! start.isValid() || s < start ) { start = s; } if ( ! end.isValid() || e > end ) { end = e; } //debugPlan<node()->node()->name()<<": "<externalAppointmentList() ) { extEff[ a ] = a->plannedPrDay( startDate(), endDate() ); //debugPlan<name()<auxcilliaryInfo()<<": "<name()<auxcilliaryInfo()<<": "<name()<<": "<numResourceGroups()<numResourceGroups(); } ResourceGroup *g = resourcegroup( parent ); if ( g ) { //debugPlan<name()<<": "<numResources()<numResources(); } Resource *r = resource( parent ); if ( r ) { int rows = m_showInternal ? r->numAppointments( id() ) : 0; rows += m_showExternal ? r->numExternalAppointments() : 0; return rows; } return 0; } QVariant ResourceAppointmentsItemModel::name( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->name(); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAppointmentsItemModel::name( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->name(); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAppointmentsItemModel::name( const Node *node, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return node->name(); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAppointmentsItemModel::name( const Appointment *app, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return app->auxcilliaryInfo(); case Qt::ToolTipRole: return i18n( "External project: %1", app->auxcilliaryInfo() ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::ForegroundRole: if ( m_externalEffortMap.contains( app ) ) { return QColor( Qt::blue ); } break; } return QVariant(); } QVariant ResourceAppointmentsItemModel::total( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: { Duration d; if ( m_showInternal ) { QList lst = res->appointments( m_manager->scheduleId() ); foreach ( Appointment *a, lst ) { if ( m_effortMap.contains( a ) ) { d += m_effortMap[ a ].totalEffort(); } } } if ( m_showExternal ) { QList lst = res->externalAppointmentList(); foreach ( Appointment *a, lst ) { if ( m_externalEffortMap.contains( a ) ) { d += m_externalEffortMap[ a ].totalEffort(); } } } return QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); } case Qt::EditRole: case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::TextAlignmentRole: return (int)(Qt::AlignRight|Qt::AlignVCenter); } return QVariant(); } QVariant ResourceAppointmentsItemModel::total( const Resource *res, const QDate &date, int role ) const { switch ( role ) { case Qt::DisplayRole: { Duration d; if ( m_showInternal ) { QList lst = res->appointments( id() ); foreach ( Appointment *a, lst ) { if ( m_effortMap.contains( a ) ) { d += m_effortMap[ a ].effortOnDate( date ); } } } if ( m_showExternal ) { QList lst = res->externalAppointmentList(); foreach ( Appointment *a, lst ) { if ( m_externalEffortMap.contains( a ) ) { d += m_externalEffortMap[ a ].effortOnDate( date ); } } } QString ds = QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); Duration avail = res->effort( 0, DateTime( date, QTime(0,0,0) ), Duration( 1.0, Duration::Unit_d ) ); QString avails = QLocale().toString( avail.toDouble( Duration::Unit_h ), 'f', 1 ); return QString( "%1(%2)").arg( ds).arg( avails ); } case Qt::EditRole: case Qt::ToolTipRole: return i18n( "The total booking on %1, along with the maximum hours for the resource", QLocale().toString( date, QLocale::ShortFormat ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::TextAlignmentRole: return (int)(Qt::AlignRight|Qt::AlignVCenter); case Qt::BackgroundRole: { - if ( res->calendar() && res->calendar()->state( date ) != CalendarDay::Working ) { + if (date.isValid() && res->calendar() && res->calendar()->state( date ) != CalendarDay::Working ) { QColor c( 0xf0f0f0 ); return QVariant::fromValue( c ); //return QVariant( Qt::cyan ); } break; } } return QVariant(); } QVariant ResourceAppointmentsItemModel::total( const Appointment *a, int role ) const { switch ( role ) { case Qt::DisplayRole: { Duration d; if ( m_effortMap.contains( a ) ) { d = m_effortMap[ a ].totalEffort(); } else if ( m_externalEffortMap.contains( a ) ) { d = m_externalEffortMap[ a ].totalEffort(); } return QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); } case Qt::ToolTipRole: { if ( m_effortMap.contains( a ) ) { return i18n( "Total booking by this task" ); } else if ( m_externalEffortMap.contains( a ) ) { return i18n( "Total booking by the external project" ); } return QVariant(); } case Qt::EditRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::TextAlignmentRole: return (int)(Qt::AlignRight|Qt::AlignVCenter); case Qt::ForegroundRole: if ( m_externalEffortMap.contains( a ) ) { return QColor( Qt::blue ); } break; } return QVariant(); } QVariant ResourceAppointmentsItemModel::assignment( const Appointment *a, const QDate &date, int role ) const { switch ( role ) { case Qt::DisplayRole: { Duration d; if ( m_effortMap.contains( a ) ) { if ( date < m_effortMap[ a ].startDate() || date > m_effortMap[ a ].endDate() ) { return QVariant(); } d = m_effortMap[ a ].effortOnDate( date ); return QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); } else if ( m_externalEffortMap.contains( a ) ) { if ( date < m_externalEffortMap[ a ].startDate() || date > m_externalEffortMap[ a ].endDate() ) { return QVariant(); } d = m_externalEffortMap[ a ].effortOnDate( date ); return QLocale().toString( d.toDouble( Duration::Unit_h ), 'f', 1 ); } return QVariant(); } case Qt::EditRole: case Qt::ToolTipRole: { if ( m_effortMap.contains( a ) ) { return i18n( "Booking by this task on %1", QLocale().toString( date, QLocale::ShortFormat ) ); } else if ( m_externalEffortMap.contains( a ) ) { return i18n( "Booking by external project on %1",QLocale().toString( date, QLocale::ShortFormat ) ); } return QVariant(); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::TextAlignmentRole: return (int)(Qt::AlignRight|Qt::AlignVCenter); case Qt::ForegroundRole: if ( m_externalEffortMap.contains( a ) ) { return QColor( Qt::blue ); } break; case Qt::BackgroundRole: { Resource *r = parent( a ); if ( r && r->calendar() && r->calendar()->state( date ) != CalendarDay::Working ) { QColor c( 0xf0f0f0 ); return QVariant::fromValue( c ); //return QVariant( Qt::cyan ); } break; } } return QVariant(); } QVariant ResourceAppointmentsItemModel::notUsed( const ResourceGroup *, int role ) const { switch ( role ) { case Qt::DisplayRole: return QString(" "); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::EditRole: case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceAppointmentsItemModel::data( const QModelIndex &index, int role ) const { if ( m_project == 0 || m_manager == 0 ) { return QVariant(); } QVariant result; if ( index.column() >= columnCount() ) { debugPlan<<"invalid display value column "<node()->node(), role ); break; case 1: result = total( a, role ); break; default: { QDate d = startDate().addDays( index.column()-2 ); result = assignment( a, d, role ); break; } } if ( result.isValid() ) { if ( role == Qt::DisplayRole && result.type() == QVariant::String && result.toString().isEmpty()) { // HACK to show focus in empty cells result = ' '; } return result; } return QVariant(); } a = externalAppointment( index ); if ( a ) { //debugPlan<<"external"<auxcilliaryInfo()<( resource( index ) ); if ( o ) { return o; } o = dynamic_cast( resourcegroup( index ) ); } return o; } Node *ResourceAppointmentsItemModel::node( const QModelIndex &index ) const { Appointment *a = appointment( index ); if ( a == 0 ) { return 0; } return a->node()->node(); } Appointment *ResourceAppointmentsItemModel::appointment( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 ) { return 0; } foreach ( Resource *r, m_project->resourceList() ) { foreach ( Appointment *a, r->appointments( id() ) ) { if ( a == index.internalPointer() ) { return a; } } } return 0; } Appointment *ResourceAppointmentsItemModel::externalAppointment( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 ) { return 0; } foreach ( Resource *r, m_project->resourceList() ) { foreach ( Appointment *a, r->externalAppointmentList() ) { if ( a == index.internalPointer() ) { return a; } } } return 0; } QModelIndex ResourceAppointmentsItemModel::createAppointmentIndex( int row, int col, void *ptr ) const { return createIndex( row, col, ptr ); } QModelIndex ResourceAppointmentsItemModel::createExternalAppointmentIndex( int row, int col, void *ptr ) const { if ( m_project == 0 || m_manager == 0 ) { return QModelIndex(); } QModelIndex i = createIndex( row, col, ptr ); //debugPlan<resourceList() ) { if ( r == index.internalPointer() ) { return r; } } return 0; } QModelIndex ResourceAppointmentsItemModel::createResourceIndex( int row, int col, void *ptr ) const { return createIndex( row, col, ptr ); } ResourceGroup *ResourceAppointmentsItemModel::resourcegroup( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } foreach ( ResourceGroup *r, m_project->resourceGroups() ) { if ( r == index.internalPointer() ) { return r; } } return 0; } QModelIndex ResourceAppointmentsItemModel::createGroupIndex( int row, int col, void *ptr ) const { return createIndex( row, col, ptr ); } void ResourceAppointmentsItemModel::slotCalendarChanged( Calendar* ) { foreach ( Resource *r, m_project->resourceList() ) { if ( r->calendar( true ) == 0 ) { slotResourceChanged( r ); } } } void ResourceAppointmentsItemModel::slotResourceChanged( Resource *res ) { ResourceGroup *g = res->parentGroup(); if ( g ) { int row = g->indexOf( res ); emit dataChanged( createResourceIndex( row, 0, res ), createResourceIndex( row, columnCount() - 1, res ) ); return; } } void ResourceAppointmentsItemModel::slotResourceGroupChanged( ResourceGroup *res ) { Project *p = res->project(); if ( p ) { int row = p->resourceGroups().indexOf( res ); emit dataChanged( createGroupIndex( row, 0, res ), createGroupIndex( row, columnCount() - 1, res ) ); } } //------------------------------------------------------- class Q_DECL_HIDDEN ResourceAppointmentsRowModel::Private { public: Private( Private *par=0, void *p=0, KPlato::ObjectType t=OT_None ) : parent( par ), ptr( p ), type( t ), internalCached( false ), externalCached( false ), intervalRow( -1 ) {} ~Private() { qDeleteAll( intervals ); } QVariant data( int column, long id = -1, int role = Qt::DisplayRole ) const; Private *parent; void *ptr; KPlato::ObjectType type; bool internalCached; bool externalCached; Private *intervalAt( int row ) const; // used by interval AppointmentInterval interval; protected: QVariant groupData( int column, int role ) const; QVariant resourceData( int column, long id, int role ) const; QVariant appointmentData( int column, int role ) const; QVariant externalData( int column, int role ) const; QVariant intervalData( int column, int role ) const; private: // used by resource Appointment internal; Appointment external; // used by appointment int intervalRow; mutable QMap intervals; }; QVariant ResourceAppointmentsRowModel::Private::data( int column, long id, int role ) const { if ( role == Role::ObjectType ) { return (int)type; } switch ( type ) { case OT_ResourceGroup: return groupData( column, role ); case OT_Resource: return resourceData( column, id, role ); case OT_Appointment: return appointmentData( column, role ); case OT_External: return externalData( column, role ); case OT_Interval: return intervalData( column, role ); default: break; } return QVariant(); } QVariant ResourceAppointmentsRowModel::Private::groupData( int column, int role ) const { ResourceGroup *g = static_cast( ptr ); if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return g->name(); case ResourceAppointmentsRowModel::Type: return g->typeToString( true ); case ResourceAppointmentsRowModel::StartTime: return " "; case ResourceAppointmentsRowModel::EndTime: return " "; case ResourceAppointmentsRowModel::Load: return " "; } } else if ( role == Role::Maximum ) { return g->units(); //TODO: Maximum Load } return QVariant(); } QVariant ResourceAppointmentsRowModel::Private::resourceData( int column, long id, int role ) const { KPlato::Resource *r = static_cast( ptr ); if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return r->name(); case ResourceAppointmentsRowModel::Type: return r->typeToString( true ); case ResourceAppointmentsRowModel::StartTime: return " "; case ResourceAppointmentsRowModel::EndTime: return " "; case ResourceAppointmentsRowModel::Load: return " "; } } else if ( role == Role::Maximum ) { return r->units(); //TODO: Maximum Load } else if ( role == Role::InternalAppointments ) { if ( ! internalCached ) { Resource *r = static_cast( ptr ); const_cast( this )->internal.clear(); foreach ( Appointment *a, r->appointments( id ) ) { const_cast( this )->internal += *a; } const_cast( this )->internalCached = true; } return QVariant::fromValue( (void*)(&internal) ); } else if ( role == Role::ExternalAppointments ) { if ( ! externalCached ) { Resource *r = static_cast( ptr ); const_cast( this )->external.clear(); foreach ( Appointment *a, r->externalAppointmentList() ) { Appointment e; e.setIntervals( a->intervals( r->startTime( id ), r->endTime( id ) ) ); const_cast( this )->external += e; } const_cast( this )->externalCached = true; } return QVariant::fromValue( (void*)(&external) ); } return QVariant(); } QVariant ResourceAppointmentsRowModel::Private::appointmentData( int column, int role ) const { KPlato::Appointment *a = static_cast( ptr ); if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return a->node()->node()->name(); case ResourceAppointmentsRowModel::Type: return a->node()->node()->typeToString( true ); case ResourceAppointmentsRowModel::StartTime: return QLocale().toString( a->startTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::EndTime: return QLocale().toString( a->endTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::Load: return " "; } } else if ( role == Qt::ToolTipRole ) { Node *n = a->node()->node(); return xi18nc( "@info:tooltip", "%1: %2%3: %4", n->wbsCode(), n->name(), QLocale().toString( a->startTime(), QLocale::ShortFormat ), KFormat().formatDuration( ( a->endTime() - a->startTime() ).milliseconds() ) ); } else if ( role == Role::Maximum ) { return a->resource()->resource()->units(); //TODO: Maximum Load } return QVariant(); } QVariant ResourceAppointmentsRowModel::Private::externalData( int column, int role ) const { KPlato::Appointment *a = static_cast( ptr ); if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return a->auxcilliaryInfo(); case ResourceAppointmentsRowModel::Type: return i18n( "Project" ); case ResourceAppointmentsRowModel::StartTime: return QLocale().toString( a->startTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::EndTime: return QLocale().toString( a->endTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::Load: return " "; } } else if ( role == Qt::ForegroundRole ) { return QColor( Qt::blue ); } else if ( role == Role::Maximum ) { KPlato::Resource *r = static_cast( parent->ptr ); return r->units(); //TODO: Maximum Load } return QVariant(); } ResourceAppointmentsRowModel::Private *ResourceAppointmentsRowModel::Private::intervalAt( int row ) const { Q_ASSERT( type == OT_Appointment || type == OT_External ); Private *p = intervals.value( row ); if ( p ) { return p; } Appointment *a = static_cast( ptr ); p = new Private( const_cast( this ), 0, OT_Interval ); p->intervalRow = row; p->interval = a->intervalAt( row ); intervals.insert( row, p ); return p; } QVariant ResourceAppointmentsRowModel::Private::intervalData( int column, int role ) const { if ( role == Qt::DisplayRole ) { switch ( column ) { case ResourceAppointmentsRowModel::Name: return QVariant(); case ResourceAppointmentsRowModel::Type: return i18n( "Interval" ); case ResourceAppointmentsRowModel::StartTime: return QLocale().toString( interval.startTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::EndTime: return QLocale().toString( interval.endTime(), QLocale::ShortFormat ); case ResourceAppointmentsRowModel::Load: return interval.load(); } } else if ( role == Qt::ToolTipRole ) { Appointment *a = static_cast( parent->ptr ); if (a && a->node() && a->node()->node()) { Node *n = a->node()->node(); return xi18nc( "@info:tooltip", "%1: %2%3: %4Assigned: %5Available: %6", n->wbsCode(), n->name(), QLocale().toString( a->startTime(), QLocale::ShortFormat ), KFormat().formatDuration( ( a->endTime() - a->startTime() ).milliseconds() ), interval.load(), a->resource()->resource()->units() ); } } else if ( role == Role::Maximum ) { return parent->appointmentData( column, role ); } return QVariant(); } int ResourceAppointmentsRowModel::sortRole( int column ) const { switch ( column ) { case ResourceAppointmentsRowModel::StartTime: case ResourceAppointmentsRowModel::EndTime: return Qt::EditRole; default: break; } return Qt::DisplayRole; } #ifndef QT_NO_DEBUG_STREAM QDebug operator<<( QDebug dbg, KPlato::ObjectType t) { switch(t){ case KPlato::OT_None: dbg << "None"; break; case KPlato::OT_ResourceGroup: dbg << "Group"; break; case KPlato::OT_Resource: dbg << "Resource"; break; case KPlato::OT_Appointment: dbg << "Appointment"; break; case KPlato::OT_External: dbg << "External"; break; case KPlato::OT_Interval: dbg << "Interval"; break; default: dbg << "Unknown"; } return dbg; } QDebug operator<<( QDebug dbg, const ResourceAppointmentsRowModel::Private& s ) { dbg <<&s; return dbg; } QDebug operator<<( QDebug dbg, const ResourceAppointmentsRowModel::Private* s ) { if ( s == 0 ) { dbg<<"ResourceAppointmentsRowModel::Private[ ("<<(void*)s<<") ]"; } else { dbg << "ResourceAppointmentsRowModel::Private[ ("<<(void*)s<<") Type="<type<<" parent="; switch( s->type ) { case KPlato::OT_ResourceGroup: dbg<(s->ptr)->project()<(s->ptr)->project()->name(); dbg<<" ptr="<(s->ptr)<(s->ptr)->name(); break; case KPlato::OT_Resource: dbg<(s->parent->ptr)<(s->parent->ptr)->name(); dbg<<" ptr="<(s->ptr)<(s->ptr)->name(); break; case KPlato::OT_Appointment: case KPlato::OT_External: dbg<(s->parent->ptr)<(s->parent->ptr)->name(); dbg<<" ptr="<(s->ptr); break; case KPlato::OT_Interval: dbg<(s->parent->ptr)<<" ptr="<(s->ptr); break; default: dbg<parent<<" ptr="<ptr; break; } dbg<<" ]"; } return dbg; } #endif ResourceAppointmentsRowModel::ResourceAppointmentsRowModel( QObject *parent ) : ItemModelBase( parent ), m_schedule( 0 ) { } ResourceAppointmentsRowModel::~ResourceAppointmentsRowModel() { qDeleteAll( m_datamap ); } void ResourceAppointmentsRowModel::setProject( Project *project ) { beginResetModel(); //debugPlan<resourceList() ) { disconnect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsRowModel::slotAppointmentToBeInserted ); disconnect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsRowModel::slotAppointmentInserted ); disconnect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentToBeRemoved ); disconnect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentRemoved ); disconnect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsRowModel::slotAppointmentChanged ); } } m_project = project; if ( m_project ) { connect(m_project, &Project::aboutToBeDeleted, this, &ResourceAppointmentsRowModel::projectDeleted); connect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceAppointmentsRowModel::slotResourceGroupToBeInserted ); connect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceAppointmentsRowModel::slotResourceGroupToBeRemoved ); connect( m_project, &Project::resourceToBeAdded, this, &ResourceAppointmentsRowModel::slotResourceToBeInserted ); connect( m_project, &Project::resourceToBeRemoved, this, &ResourceAppointmentsRowModel::slotResourceToBeRemoved ); connect( m_project, &Project::resourceGroupAdded, this, &ResourceAppointmentsRowModel::slotResourceGroupInserted ); connect( m_project, &Project::resourceGroupRemoved, this, &ResourceAppointmentsRowModel::slotResourceGroupRemoved ); connect( m_project, &Project::resourceAdded, this, &ResourceAppointmentsRowModel::slotResourceInserted ); connect( m_project, &Project::resourceRemoved, this, &ResourceAppointmentsRowModel::slotResourceRemoved ); connect( m_project, &Project::projectCalculated, this, &ResourceAppointmentsRowModel::slotProjectCalculated ); foreach ( Resource *r, m_project->resourceList() ) { connect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsRowModel::slotAppointmentToBeInserted ); connect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsRowModel::slotAppointmentInserted ); connect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentToBeRemoved ); connect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentRemoved ); connect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsRowModel::slotAppointmentChanged ); } } endResetModel(); } void ResourceAppointmentsRowModel::setScheduleManager( ScheduleManager *sm ) { debugPlan<<"ResourceAppointmentsRowModel::setScheduleManager:"<expected() != m_schedule ) { beginResetModel(); m_manager = sm; m_schedule = sm ? sm->expected() : 0; qDeleteAll( m_datamap ); m_datamap.clear(); endResetModel(); } } long ResourceAppointmentsRowModel::id() const { return m_manager ? m_manager->scheduleId() : -1; } const QMetaEnum ResourceAppointmentsRowModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } int ResourceAppointmentsRowModel::columnCount( const QModelIndex & /*parent */) const { return columnMap().keyCount(); } int ResourceAppointmentsRowModel::rowCount( const QModelIndex & parent ) const { if ( m_project == 0 ) { return 0; } if ( ! parent.isValid() ) { return m_project->numResourceGroups(); } if ( ResourceGroup *g = resourcegroup( parent ) ) { return g->numResources(); } if ( m_manager == 0 ) { return 0; } if ( Resource *r = resource( parent ) ) { return r->numAppointments( id() ) + r->numExternalAppointments(); // number of tasks there are appointments with + external projects } if ( Appointment *a = appointment( parent ) ) { return a->count(); // number of appointment intervals } return 0; } QVariant ResourceAppointmentsRowModel::data( const QModelIndex &index, int role ) const { //debugPlan<(index.internalPointer() )->data( index.column(), id(), role ); } QVariant ResourceAppointmentsRowModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Vertical ) { return QVariant(); } if ( role == Qt::DisplayRole ) { switch ( section ) { case Name: return i18n( "Name" ); case Type: return i18n( "Type" ); case StartTime: return i18n( "Start Time" ); case EndTime: return i18n( "End Time" ); case Load: return xi18nc( "@title:column noun", "Load" ); } } if ( role == Qt::TextAlignmentRole ) { switch ( section ) { case Name: case Type: case StartTime: case EndTime: return (int)(Qt::AlignLeft|Qt::AlignVCenter); case Load: return (int)(Qt::AlignRight|Qt::AlignVCenter); } } return ItemModelBase::headerData( section, orientation, role ); } QModelIndex ResourceAppointmentsRowModel::parent( const QModelIndex &idx ) const { if ( !idx.isValid() || m_project == 0 ) { warnPlan<<"No data "<indexOf( pg ); p = const_cast( this )->createGroupIndex( row, 0, m_project ); //debugPlan<<"Parent:"<parentGroup()->name(); Q_ASSERT( p.isValid() ); return p; } if ( Resource *pr = parentResource( idx ) ) { // Appointment, parent is Resource int row = pr->parentGroup()->indexOf( pr ); p = const_cast( this )->createResourceIndex( row, 0, pr->parentGroup() ); //debugPlan<<"Parent:"<parentGroup()->name(); Q_ASSERT( p.isValid() ); return p; } if ( Appointment *a = parentAppointment( idx ) ) { // AppointmentInterval, parent is Appointment Private *pi = static_cast( idx.internalPointer() ); if ( pi->parent->type == OT_Appointment ) { Q_ASSERT( a->resource()->id() == id() ); if ( a->resource() && a->resource()->resource() ) { Resource *r = a->resource()->resource(); int row = r->indexOf( a, id() ); Q_ASSERT( row >= 0 ); p = const_cast( this )->createAppointmentIndex( row, 0, r ); //debugPlan<<"Parent:"<name(); Q_ASSERT( p.isValid() ); } } else if ( pi->parent->type == OT_External ) { Resource *r = static_cast( pi->parent->parent->ptr ); int row = r->externalAppointmentList().indexOf( a ); Q_ASSERT( row >= 0 ); row += r->numAppointments( id() ); p = const_cast( this )->createAppointmentIndex( row, 0, r ); } return p; } return QModelIndex(); } QModelIndex ResourceAppointmentsRowModel::index( ResourceGroup *g ) const { if ( m_project == 0 || g == 0 ) { return QModelIndex(); } return const_cast( this )->createGroupIndex( m_project->indexOf( g ), 0, m_project ); } QModelIndex ResourceAppointmentsRowModel::index( Resource *r ) const { if ( m_project == 0 || r == 0 ) { return QModelIndex(); } return const_cast( this )->createResourceIndex( r->parentGroup()->indexOf( r ), 0, r->parentGroup() ); } QModelIndex ResourceAppointmentsRowModel::index( Appointment *a ) const { if ( m_project == 0 || m_manager == 0 || a == 0 || a->resource()->resource() ) { return QModelIndex(); } Resource *r = a->resource()->resource(); return const_cast( this )->createAppointmentIndex( r->indexOf( a, id() ), 0, r ); } QModelIndex ResourceAppointmentsRowModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_project == 0 || row < 0 || column < 0 ) { return QModelIndex(); } if ( ! parent.isValid() ) { if ( row < m_project->numResourceGroups() ) { //debugPlan<<"Group: "<resourceGroupAt( row ); return const_cast( this )->createGroupIndex( row, column, m_project ); } return QModelIndex(); } if ( ResourceGroup *g = resourcegroup( parent ) ) { if ( row < g->numResources() ) { //debugPlan<<"Resource: "<resourceAt( row )<( parent.internalPointer() ); return const_cast( this )->createResourceIndex( row, column, g ); } return QModelIndex(); } if ( m_manager == 0 ) { return QModelIndex(); } if ( Resource *r = resource( parent ) ) { int num = r->numAppointments( id() ) + r->numExternalAppointments(); if ( row < num ) { //debugPlan<<"Appointment: "<appointmentAt( row, m_manager->scheduleId() )<( parent.internalPointer() ); return const_cast( this )->createAppointmentIndex( row, column, r ); } return QModelIndex(); } if ( Appointment *a = appointment( parent ) ) { int num = a->count(); if ( row < num ) { //debugPlan<<"Appointment interval at: "<( parent.internalPointer() ); return const_cast( this )->createIntervalIndex( row, column, a ); } return QModelIndex(); } return QModelIndex(); } QModelIndex ResourceAppointmentsRowModel::createGroupIndex( int row, int column, Project *project ) { ResourceGroup *group = project->resourceGroupAt( row ); Private *p = m_datamap.value( (void*)group ); if ( p == 0 ) { p = new Private( 0, group, OT_ResourceGroup ); m_datamap.insert( group, p ); } QModelIndex idx = createIndex( row, column, p ); Q_ASSERT( idx.isValid() ); return idx; } QModelIndex ResourceAppointmentsRowModel::createResourceIndex( int row, int column, ResourceGroup *g ) { Resource *res = g->resourceAt( row ); Private *p = m_datamap.value( (void*)res ); if ( p == 0 ) { Private *pg = m_datamap.value( g ); Q_ASSERT( pg ); p = new Private( pg, res, OT_Resource ); m_datamap.insert( res, p ); } QModelIndex idx = createIndex( row, column, p ); Q_ASSERT( idx.isValid() ); return idx; } QModelIndex ResourceAppointmentsRowModel::createAppointmentIndex( int row, int column, Resource *r ) { Private *p = 0; KPlato::ObjectType type; Appointment *a = 0; if ( row < r->numAppointments( id() ) ) { a = r->appointmentAt( row, id() ); type = OT_Appointment; } else { a = r->externalAppointmentList().value( row - r->numAppointments( id() ) ); type = OT_External; } Q_ASSERT( a ); p = m_datamap.value( (void*)a ); if ( p == 0 ) { Private *pr = m_datamap.value( r ); Q_ASSERT( pr ); p = new Private( pr, a, type ); m_datamap.insert( a, p ); } QModelIndex idx = createIndex( row, column, p ); Q_ASSERT( idx.isValid() ); return idx; } QModelIndex ResourceAppointmentsRowModel::createIntervalIndex( int row, int column, Appointment *a ) { AppointmentInterval i = a->intervalAt( row ); Private *pr = m_datamap.value( a ); Q_ASSERT( pr ); Private *p = pr->intervalAt( row ); Q_ASSERT( p ); QModelIndex idx = createIndex( row, column, p ); Q_ASSERT( idx.isValid() ); return idx; } void ResourceAppointmentsRowModel::slotResourceToBeInserted( const ResourceGroup *group, int row ) { debugPlan<name()<( group ) ); beginInsertRows( i, row, row ); } void ResourceAppointmentsRowModel::slotResourceInserted( const Resource *r ) { debugPlan<name(); endInsertRows(); connect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsRowModel::slotAppointmentToBeInserted ); connect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsRowModel::slotAppointmentInserted ); connect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentToBeRemoved ); connect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentRemoved ); connect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsRowModel::slotAppointmentChanged ); } void ResourceAppointmentsRowModel::slotResourceToBeRemoved( const Resource *r ) { debugPlan<name(); int row = r->parentGroup()->indexOf( r ); beginRemoveRows( index( r->parentGroup() ), row, row ); disconnect( r, &Resource::externalAppointmentToBeAdded, this, &ResourceAppointmentsRowModel::slotAppointmentToBeInserted ); disconnect( r, &Resource::externalAppointmentAdded, this, &ResourceAppointmentsRowModel::slotAppointmentInserted ); disconnect( r, &Resource::externalAppointmentToBeRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentToBeRemoved ); disconnect( r, &Resource::externalAppointmentRemoved, this, &ResourceAppointmentsRowModel::slotAppointmentRemoved ); disconnect( r, &Resource::externalAppointmentChanged, this, &ResourceAppointmentsRowModel::slotAppointmentChanged ); Private *p = 0; foreach ( Appointment *a, r->appointments( id() ) ) { // remove appointment p = m_datamap.value( a ); if ( p ) { m_datamap.remove( a ); delete p; } } foreach ( Appointment *a, r->externalAppointmentList() ) { // remove appointment p = m_datamap.value( a ); if ( p ) { m_datamap.remove( a ); delete p; } } // remove resource p = m_datamap.value( (void*)r ); if ( p ) { m_datamap.remove( const_cast( r ) ); delete p; } } void ResourceAppointmentsRowModel::slotResourceRemoved( const Resource *resource ) { Q_UNUSED(resource); //debugPlan<name(); endRemoveRows(); } void ResourceAppointmentsRowModel::slotResourceGroupToBeInserted( const ResourceGroup *group, int row ) { Q_UNUSED(group); beginInsertRows( QModelIndex(), row, row ); } void ResourceAppointmentsRowModel::slotResourceGroupInserted( const ResourceGroup*/*group*/ ) { endInsertRows(); } void ResourceAppointmentsRowModel::slotResourceGroupToBeRemoved( const ResourceGroup *group ) { //debugPlan<name()<indexOf( const_cast( group ) ); beginRemoveRows( QModelIndex(), row, row ); Private *p = m_datamap.value( const_cast( group ) ); if ( p ) { m_datamap.remove( const_cast( group ) ); delete p; } } void ResourceAppointmentsRowModel::slotResourceGroupRemoved( const ResourceGroup *group ) { Q_UNUSED(group); //debugPlan<name(); endRemoveRows(); } void ResourceAppointmentsRowModel::slotAppointmentToBeInserted( Resource *r, int row ) { Q_UNUSED(r); Q_UNUSED(row); // external appointments only, (Internal handled in slotProjectCalculated) } void ResourceAppointmentsRowModel::slotAppointmentInserted( Resource *r, Appointment *a ) { Q_UNUSED(a); beginResetModel(); // external appointments only, (Internal handled in slotProjectCalculated) Private *p = m_datamap.value( r ); if ( p ) { p->externalCached = false; } endResetModel(); } void ResourceAppointmentsRowModel::slotAppointmentToBeRemoved( Resource *r, int row ) { Q_UNUSED(row); // external appointments only, (Internal handled in slotProjectCalculated) Private *p = m_datamap.value( r ); if ( p ) { p->externalCached = false; } } void ResourceAppointmentsRowModel::slotAppointmentRemoved() { // external appointments only, (Internal handled in slotProjectCalculated) beginResetModel(); endResetModel(); } void ResourceAppointmentsRowModel::slotAppointmentChanged( Resource *r, Appointment *a ) { Q_UNUSED(r); Q_UNUSED(a); // external appointments only, (Internal handled in slotProjectCalculated) // will not happen atm } void ResourceAppointmentsRowModel::slotProjectCalculated( ScheduleManager *sm ) { if ( sm == m_manager ) { setScheduleManager( sm ); } } ResourceGroup *ResourceAppointmentsRowModel::parentGroup( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } Private *ch = static_cast( index.internalPointer() ); if ( ch && ch->type == OT_Resource ) { return static_cast( ch->parent->ptr ); } return 0; } ResourceGroup *ResourceAppointmentsRowModel::resourcegroup( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } Private *p = static_cast( index.internalPointer() ); if ( p && p->type == OT_ResourceGroup ) { return static_cast( p->ptr ); } return 0; } Resource *ResourceAppointmentsRowModel::parentResource( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } Private *ch = static_cast( index.internalPointer() ); if ( ch && ( ch->type == OT_Appointment || ch->type == OT_External ) ) { return static_cast( ch->parent->ptr ); } return 0; } Resource *ResourceAppointmentsRowModel::resource( const QModelIndex &index ) const { if ( m_project == 0 ) { return 0; } Private *p = static_cast( index.internalPointer() ); if ( p && p->type == OT_Resource ) { return static_cast( p->ptr ); } return 0; } Appointment *ResourceAppointmentsRowModel::parentAppointment( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 ) { return 0; } Private *ch = static_cast( index.internalPointer() ); if ( ch && ch->type == OT_Interval ) { return static_cast( ch->parent->ptr ); } return 0; } Appointment *ResourceAppointmentsRowModel::appointment( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 || ! index.isValid() ) { return 0; } Private *p = static_cast( index.internalPointer() ); if ( p && ( p->type == OT_Appointment || p->type == OT_External ) ) { return static_cast( p->ptr ); } return 0; } AppointmentInterval *ResourceAppointmentsRowModel::interval( const QModelIndex &index ) const { if ( m_project == 0 || m_manager == 0 ) { return 0; } Private *p = static_cast( index.internalPointer() ); if ( p && p->type == OT_Interval ) { return &( p->interval ); } return 0; } Node *ResourceAppointmentsRowModel::node( const QModelIndex &idx ) const { Appointment *a = appointment( idx ); return ( a && a->node() ? a->node()->node() : 0 ); } //--------------------------------------------- ResourceAppointmentsGanttModel::ResourceAppointmentsGanttModel( QObject *parent ) : ResourceAppointmentsRowModel( parent ) { } ResourceAppointmentsGanttModel::~ResourceAppointmentsGanttModel() { } QVariant ResourceAppointmentsGanttModel::data( const ResourceGroup *g, int column, int role ) const { Q_UNUSED(column); switch( role ) { case KGantt::ItemTypeRole: return KGantt::TypeSummary; case KGantt::StartTimeRole: return g->startTime( id() ); case KGantt::EndTimeRole: return g->endTime( id() ); } return QVariant(); } QVariant ResourceAppointmentsGanttModel::data( const Resource *r, int column, int role ) const { Q_UNUSED(column); switch( role ) { case KGantt::ItemTypeRole: return KGantt::TypeSummary; case KGantt::StartTimeRole: return r->startTime( id() ); case KGantt::EndTimeRole: return r->endTime( id() ); } return QVariant(); } QVariant ResourceAppointmentsGanttModel::data( const Appointment *a, int column, int role ) const { Q_UNUSED(column); switch( role ) { case KGantt::ItemTypeRole: return KGantt::TypeMulti; case KGantt::StartTimeRole: return a->startTime(); case KGantt::EndTimeRole: return a->endTime(); } return QVariant(); } QVariant ResourceAppointmentsGanttModel::data( const AppointmentInterval *a, int column, int role ) const { Q_UNUSED(column); switch( role ) { case KGantt::ItemTypeRole: return KGantt::TypeTask; case KGantt::StartTimeRole: return a->startTime(); case KGantt::EndTimeRole: return a->endTime(); } return QVariant(); } QVariant ResourceAppointmentsGanttModel::data( const QModelIndex &index, int role ) const { //debugPlan<