diff --git a/src/libs/models/kptresourcemodel.cpp b/src/libs/models/kptresourcemodel.cpp index a9b2a27e..a99819ae 100644 --- a/src/libs/models/kptresourcemodel.cpp +++ b/src/libs/models/kptresourcemodel.cpp @@ -1,1835 +1,1835 @@ /* This file is part of the KDE project Copyright (C) 2007 Dag Andersen Copyright (C) 2011, 2012 Dag Andersen Copyright (C) 2016 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 "kptresourcemodel.h" #include "kptlocale.h" #include "kptcommonstrings.h" #include "kptcommand.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 #include #ifdef PLAN_KCONTACTS_FOUND #include #include #endif namespace KPlato { //-------------------------------------- ResourceModel::ResourceModel( QObject *parent ) : QObject( parent ), m_project( 0 ) { } ResourceModel::~ResourceModel() { } const QMetaEnum ResourceModel::columnMap() const { return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") ); } void ResourceModel::setProject( Project *project ) { m_project = project; } int ResourceModel::propertyCount() const { return columnMap().keyCount(); } QVariant ResourceModel::name( const Resource *res, int role ) const { //debugPlan<name()<<","<name(); case Qt::ToolTipRole: if (res->isShared()) { return xi18nc("@info:tooltip", "%1 is a Shared resource and can thus be shared with other projects", res->name()); } if ( res->autoAllocate() ) { return xi18nc( "@info:tooltip", "%1:This resource will be automatically allocated to new tasks", res->name() ); } return res->name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); case Qt::DecorationRole: if ( res->isBaselined() ) { return koIcon("view-time-schedule-baselined"); } break; case Qt::CheckStateRole: return res->autoAllocate() ? Qt::Checked : Qt::Unchecked; default: break; } return QVariant(); } QVariant ResourceModel::name( const ResourceGroup *res, int role ) const { //debugPlan<name()<<","<name(); case Qt::ToolTipRole: if (!res->isShared()) { return res->name(); } return xi18nc("@info:tooltip", "%1 is a Shared resource group and can thus be shared with other projects", res->name()); break; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::scope( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return res->isShared() ? i18n("Shared") : i18n("Local"); case Qt::ToolTipRole: if (!res->isShared()) { return xi18nc("@info:tooltip", "%1 is a Local resource and can only be used in this project", res->name()); } return xi18nc("@info:tooltip", "%1 is a Shared resource and can thus be shared with other projects", res->name()); case Qt::EditRole: return res->isShared() ? "Shared" : "Local"; case Role::EnumList: return QStringList() << i18n("Local") << i18n("Shared"); case Role::EnumListValue: return res->isShared() ? 1 : 0; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::scope( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return res->isShared() ? i18n("Shared") : i18n("Local"); case Qt::ToolTipRole: if (!res->isShared()) { return xi18nc("@info:tooltip", "%1 is a Local resource group and can only be used in this project", res->name()); } return xi18nc("@info:tooltip", "%1 is a Shared resource group and can thus be shared with other projects", res->name()); case Qt::EditRole: return res->isShared() ? "Shared" : "Local"; case Role::EnumList: return QStringList() << i18n("Local") << i18n("Shared"); case Role::EnumListValue: return res->isShared() ? 1 : 0; case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::type( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return res->typeToString( true ); case Qt::EditRole: return res->typeToString( false ); case Role::EnumList: return res->typeToStringList( true ); case Role::EnumListValue: return (int)res->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::type( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return res->typeToString( true ); case Qt::EditRole: return res->typeToString( false ); case Role::EnumList: return res->typeToStringList( true ); case Role::EnumListValue: return (int)res->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::initials( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->initials(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::email( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: case Qt::ToolTipRole: return res->email(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::calendar( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: { if ( res->type() == Resource::Type_Team ) { return " "; } QString s = i18n( "None" ); Calendar *cal = res->calendar( true ); // don't check for default calendar if ( cal ) { s = cal->name(); } else if ( res->type() == Resource::Type_Work ) { // Do we get a default calendar cal = res->calendar(); if ( cal ) { s = i18nc( "Default (calendar name)", "Default (%1)", cal->name() ); } } return s; } case Qt::ToolTipRole: { if ( res->type() == Resource::Type_Team ) { return xi18nc( "@info:tooltip", "A team resource does not have a calendar" ); } QString s = xi18nc( "@info:tooltip", "No calendar" ); Calendar *cal = res->calendar( true ); // don't check for default calendar if ( cal ) { s = cal->name(); } else if ( res->type() == Resource::Type_Work ) { // Do we get a default calendar cal = res->calendar(); if ( cal ) { s = xi18nc( "@info:tooltip 1=calendar name", "Using default calendar: %1", cal->name() ); } } return s; } case Role::EnumList: { Calendar *cal = m_project->defaultCalendar(); QString s = i18n( "None" ); if ( cal && res->type() == Resource::Type_Work ) { s = i18nc( "Default (calendar name)", "Default (%1)", cal->name() ); } return QStringList() << s << m_project->calendarNames(); } case Qt::EditRole: case Role::EnumListValue: { Calendar *cal = res->calendar( true ); // don't check for default calendar return cal == 0 ? 0 : m_project->calendarNames().indexOf( cal->name() ) + 1; } case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::units( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return res->units(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::availableFrom( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( res->availableFrom(), QLocale::ShortFormat ); case Qt::EditRole: return res->availableFrom(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: { if ( res->availableFrom().isValid() ) { return xi18nc( "infor:tooltip", "Available from: %1", QLocale().toString( res->availableFrom(), QLocale::LongFormat ) ); } return xi18nc( "infor:tooltip", "Available from project target start time: %1", QLocale().toString( m_project->constraintStartTime(), QLocale::LongFormat ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::availableUntil( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return QLocale().toString( res->availableUntil(), QLocale::ShortFormat ); case Qt::EditRole: return res->availableUntil(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: { if ( res->availableUntil().isValid() ) { return xi18nc( "infor:tooltip", "Available until: %1", QLocale().toString( res->availableUntil(), QLocale::LongFormat ) ); } - return xi18nc( "infor:tooltip", "Available from project target finish time: %1", QLocale().toString( m_project->constraintEndTime(), QLocale::LongFormat ) ); + return xi18nc( "infor:tooltip", "Available until project target finish time: %1", QLocale().toString( m_project->constraintEndTime(), QLocale::LongFormat ) ); } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::normalRate( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( res->normalRate() ); case Qt::EditRole: return res->normalRate(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: return i18n( "Cost per hour, normal time: %1", m_project->locale()->formatMoney( res->normalRate() ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::overtimeRate( const Resource *res, int role ) const { switch ( role ) { case Qt::DisplayRole: return m_project->locale()->formatMoney( res->overtimeRate() ); case Qt::EditRole: return res->overtimeRate(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::ToolTipRole: return i18n( "Cost per hour, overtime: %1", m_project->locale()->formatMoney( res->overtimeRate() ) ); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::account( const Resource *resource, int role ) const { switch ( role ) { case Qt::DisplayRole: { Account *a = resource->account(); return a == 0 ? i18n( "None" ) : a->name(); } case Qt::ToolTipRole: { Account *a = resource->account(); return i18n( "Account: %1", (a == 0 ? i18n( "None" ) : a->name() ) ); } case Role::EnumListValue: case Qt::EditRole: { Account *a = resource->account(); return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 ); } case Role::EnumList: { QStringList lst; lst << i18n("None"); lst += m_project->accounts().costElements(); return lst; } case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } QVariant ResourceModel::data( const Resource *resource, int property, int role ) const { if ( role == Role::ObjectType ) { return OT_Resource; } QVariant result; if ( resource == 0 ) { return result; } switch ( property ) { case ResourceName: result = name( resource, role ); break; case ResourceScope: result = scope( resource, role ); break; case ResourceType: result = type( resource, role ); break; case ResourceInitials: result = initials( resource, role ); break; case ResourceEmail: result = email( resource, role ); break; case ResourceCalendar: result = calendar( resource, role ); break; case ResourceLimit: result = units( resource, role ); break; case ResourceAvailableFrom: result = availableFrom( resource, role ); break; case ResourceAvailableUntil: result = availableUntil( resource, role ); break; case ResourceNormalRate: result = normalRate( resource, role ); break; case ResourceOvertimeRate: result = overtimeRate( resource, role ); break; case ResourceAccount: result = account( resource, role ); break; default: debugPlan<<"data: invalid display value: property="<name()<<","<(group); beginInsertRows( index( group ), row, row ); } void ResourceItemModel::slotResourceInserted( const Resource *resource ) { //debugPlan<name(); Q_ASSERT( resource->parentGroup() == m_group ); #ifdef NDEBUG Q_UNUSED(resource) #endif endInsertRows(); m_group = 0; emit layoutChanged(); //HACK to make the right view react! Bug in qt? } void ResourceItemModel::slotResourceToBeRemoved( const Resource *resource ) { //debugPlan<name(); Q_ASSERT( m_resource == 0 ); #ifdef NDEBUG Q_UNUSED(resource) #endif m_resource = const_cast(resource); int row = index( resource ).row(); beginRemoveRows( index( resource->parentGroup() ), row, row ); } void ResourceItemModel::slotResourceRemoved( const Resource *resource ) { //debugPlan<name(); Q_ASSERT( resource == m_resource ); #ifdef NDEBUG Q_UNUSED(resource) #endif endRemoveRows(); m_resource = 0; } void ResourceItemModel::slotResourceGroupToBeInserted( const ResourceGroup *group, int row ) { //debugPlan<name(); Q_ASSERT( m_group == 0 ); m_group = const_cast(group); beginInsertRows( QModelIndex(), row, row ); } void ResourceItemModel::slotResourceGroupInserted( const ResourceGroup *group ) { //debugPlan<name(); Q_ASSERT( group == m_group ); #ifdef NDEBUG Q_UNUSED(group) #endif endInsertRows(); m_group = 0; } void ResourceItemModel::slotResourceGroupToBeRemoved( const ResourceGroup *group ) { //debugPlan<name(); Q_ASSERT( m_group == 0 ); m_group = const_cast(group); int row = index( group ).row(); beginRemoveRows( QModelIndex(), row, row ); } void ResourceItemModel::slotResourceGroupRemoved( const ResourceGroup *group ) { //debugPlan<name(); Q_ASSERT( group == m_group ); #ifdef NDEBUG Q_UNUSED(group) #endif endRemoveRows(); m_group = 0; } void ResourceItemModel::setProject( Project *project ) { beginResetModel(); if ( m_project ) { disconnect(m_project, &Project::aboutToBeDeleted, this, &ResourceItemModel::projectDeleted); disconnect( m_project, &Project::localeChanged, this, &ResourceItemModel::slotLayoutChanged ); disconnect( m_project, &Project::resourceChanged, this, &ResourceItemModel::slotResourceChanged ); disconnect( m_project, &Project::resourceGroupChanged, this, &ResourceItemModel::slotResourceGroupChanged ); disconnect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceItemModel::slotResourceGroupToBeInserted ); disconnect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceItemModel::slotResourceGroupToBeRemoved ); disconnect( m_project, &Project::resourceToBeAdded, this, &ResourceItemModel::slotResourceToBeInserted ); disconnect( m_project, &Project::resourceToBeRemoved, this, &ResourceItemModel::slotResourceToBeRemoved ); disconnect( m_project, &Project::resourceGroupAdded, this, &ResourceItemModel::slotResourceGroupInserted ); disconnect( m_project, &Project::resourceGroupRemoved, this, &ResourceItemModel::slotResourceGroupRemoved ); disconnect( m_project, &Project::resourceAdded, this, &ResourceItemModel::slotResourceInserted ); disconnect( m_project, &Project::resourceRemoved, this, &ResourceItemModel::slotResourceRemoved ); disconnect( m_project, &Project::defaultCalendarChanged, this, &ResourceItemModel::slotCalendarChanged ); } m_project = project; if ( m_project ) { connect(m_project, &Project::aboutToBeDeleted, this, &ResourceItemModel::projectDeleted); connect( m_project, &Project::localeChanged, this, &ResourceItemModel::slotLayoutChanged ); connect( m_project, &Project::resourceChanged, this, &ResourceItemModel::slotResourceChanged ); connect( m_project, &Project::resourceGroupChanged, this, &ResourceItemModel::slotResourceGroupChanged ); connect( m_project, &Project::resourceGroupToBeAdded, this, &ResourceItemModel::slotResourceGroupToBeInserted ); connect( m_project, &Project::resourceGroupToBeRemoved, this, &ResourceItemModel::slotResourceGroupToBeRemoved ); connect( m_project, &Project::resourceToBeAdded, this, &ResourceItemModel::slotResourceToBeInserted ); connect( m_project, &Project::resourceToBeRemoved, this, &ResourceItemModel::slotResourceToBeRemoved ); connect( m_project, &Project::resourceGroupAdded, this, &ResourceItemModel::slotResourceGroupInserted ); connect( m_project, &Project::resourceGroupRemoved, this, &ResourceItemModel::slotResourceGroupRemoved ); connect( m_project, &Project::resourceAdded, this, &ResourceItemModel::slotResourceInserted ); connect( m_project, &Project::resourceRemoved, this, &ResourceItemModel::slotResourceRemoved ); connect( m_project, &Project::defaultCalendarChanged, this, &ResourceItemModel::slotCalendarChanged ); } m_model.setProject( m_project ); endResetModel(); } Qt::ItemFlags ResourceItemModel::flags( const QModelIndex &index ) const { Qt::ItemFlags flags = ItemModelBase::flags( index ); if ( !m_readWrite ) { //debugPlan<<"read only"<( object ( index ) ); if ( r != 0 ) { flags |= Qt::ItemIsDragEnabled; if (r->isShared()) { flags &= ~Qt::ItemIsEditable; if (index.column() == ResourceModel::ResourceName) { flags |= Qt::ItemIsUserCheckable; } return flags; } switch ( index.column() ) { case ResourceModel::ResourceName: flags |= Qt::ItemIsEditable | Qt::ItemIsUserCheckable; break; case ResourceModel::ResourceScope: flags &= ~Qt::ItemIsEditable; break; case ResourceModel::ResourceType: if ( ! r->isBaselined() ) { flags |= Qt::ItemIsEditable; } break; case ResourceModel::ResourceAccount: if ( ! r->isBaselined() ) { flags |= Qt::ItemIsEditable; } break; case ResourceModel::ResourceNormalRate: if ( ! r->isBaselined() ) { flags |= Qt::ItemIsEditable; } break; case ResourceModel::ResourceOvertimeRate: if ( ! r->isBaselined() ) { flags |= Qt::ItemIsEditable; } break; default: flags |= Qt::ItemIsEditable; } //debugPlan<<"resource"<( object( index ) ); if ( g ) { flags |= Qt::ItemIsDragEnabled; if (g->isShared()) { flags &= ~Qt::ItemIsEditable; return flags; } flags |= Qt::ItemIsDropEnabled; switch ( index.column() ) { case ResourceModel::ResourceName: flags |= Qt::ItemIsEditable; break; case ResourceModel::ResourceType: flags |= Qt::ItemIsEditable; break; default: flags &= ~Qt::ItemIsEditable; } //debugPlan<<"group"<parentGroup() ) { // only resources have parent int row = m_project->indexOf( r->parentGroup() ); return createIndex( row, 0, r->parentGroup() ); } return QModelIndex(); } QModelIndex ResourceItemModel::index( int row, int column, const QModelIndex &parent ) const { if ( m_project == 0 || column < 0 || column >= columnCount() || row < 0 ) { return QModelIndex(); } if ( ! parent.isValid() ) { if ( row < m_project->numResourceGroups() ) { return createIndex( row, column, m_project->resourceGroupAt( row ) ); } return QModelIndex(); } ResourceGroup *g = group( parent ); if ( g ) { if ( row < g->numResources() ) { return createIndex( row, column, g->resourceAt( row ) ); } return QModelIndex(); } return QModelIndex(); } QModelIndex ResourceItemModel::index( const Resource *resource, int column ) 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 createIndex( row, column, r ); } return QModelIndex(); } QModelIndex ResourceItemModel::index( const ResourceGroup *group, int column ) const { if ( m_project == 0 || group == 0 ) { return QModelIndex(); } ResourceGroup *g = const_cast(group); int row = m_project->indexOf( g ); return createIndex( row, column, g ); } int ResourceItemModel::columnCount( const QModelIndex &/*parent*/ ) const { return m_model.propertyCount(); } int ResourceItemModel::rowCount( const QModelIndex &parent ) const { if ( m_project == 0 ) { return 0; } if ( ! parent.isValid() ) { return m_project->numResourceGroups(); } ResourceGroup *g = group( parent ); if ( g ) { return g->numResources(); } return 0; } QVariant ResourceItemModel::name( const ResourceGroup *res, int role ) const { //debugPlan<name()<<","<name(); case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool ResourceItemModel::setName( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == res->name() ) { return false; } emit executeCommand( new ModifyResourceNameCmd( res, value.toString(), kundo2_i18n( "Modify resource name" ) ) ); return true; case Qt::CheckStateRole: emit executeCommand( new ModifyResourceAutoAllocateCmd( res, value.toBool(), kundo2_i18n( "Modify resource auto allocate" ) ) ); return true; } return false; } bool ResourceItemModel::setName( ResourceGroup *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == res->name() ) { return false; } emit executeCommand( new ModifyResourceGroupNameCmd( res, value.toString(), kundo2_i18n( "Modify resourcegroup name" ) ) ); return true; } return false; } QVariant ResourceItemModel::type( const ResourceGroup *res, int role ) const { switch ( role ) { case Qt::DisplayRole: case Qt::ToolTipRole: return res->typeToString( true ); case Qt::EditRole: return res->typeToString( false ); case Role::EnumList: return res->typeToStringList( true ); case Role::EnumListValue: return (int)res->type(); case Qt::TextAlignmentRole: return Qt::AlignCenter; case Qt::StatusTipRole: case Qt::WhatsThisRole: return QVariant(); } return QVariant(); } bool ResourceItemModel::setType( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Resource::Type v; QStringList lst = res->typeToStringList( false ); if ( lst.contains( value.toString() ) ) { v = static_cast( lst.indexOf( value.toString() ) ); } else { v = static_cast( value.toInt() ); } if ( v == res->type() ) { return false; } emit executeCommand( new ModifyResourceTypeCmd( res, v, kundo2_i18n( "Modify resource type" ) ) ); return true; } } return false; } bool ResourceItemModel::setType( ResourceGroup *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { ResourceGroup::Type v; QStringList lst = res->typeToStringList( false ); if ( lst.contains( value.toString() ) ) { v = static_cast( lst.indexOf( value.toString() ) ); } else { v = static_cast( value.toInt() ); } if ( v == res->type() ) { return false; } emit executeCommand( new ModifyResourceGroupTypeCmd( res, v, kundo2_i18n( "Modify resourcegroup type" ) ) ); return true; } } return false; } bool ResourceItemModel::setInitials( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == res->initials() ) { return false; } emit executeCommand( new ModifyResourceInitialsCmd( res, value.toString(), kundo2_i18n( "Modify resource initials" ) ) ); return true; } return false; } bool ResourceItemModel::setEmail( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toString() == res->email() ) { return false; } emit executeCommand( new ModifyResourceEmailCmd( res, value.toString(), kundo2_i18n( "Modify resource email" ) ) ); return true; } return false; } bool ResourceItemModel::setCalendar( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Calendar *c = 0; if ( value.toInt() > 0 ) { QStringList lst = m_model.calendar( res, Role::EnumList ).toStringList(); if ( value.toInt() < lst.count() ) { c = m_project->calendarByName( lst.at( value.toInt() ) ); } } if ( c == res->calendar( true ) ) { return false; } emit executeCommand( new ModifyResourceCalendarCmd( res, c, kundo2_i18n( "Modify resource calendar" ) ) ); return true; } } return false; } bool ResourceItemModel::setUnits( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toInt() == res->units() ) { return false; } emit executeCommand( new ModifyResourceUnitsCmd( res, value.toInt(), kundo2_i18n( "Modify resource available units" ) ) ); return true; } return false; } bool ResourceItemModel::setAvailableFrom( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toDateTime() == res->availableFrom() ) { return false; } emit executeCommand( new ModifyResourceAvailableFromCmd( res, value.toDateTime(), kundo2_i18n( "Modify resource available from" ) ) ); return true; } return false; } bool ResourceItemModel::setAvailableUntil( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toDateTime() == res->availableUntil() ) { return false; } emit executeCommand( new ModifyResourceAvailableUntilCmd( res, value.toDateTime(), kundo2_i18n( "Modify resource available until" ) ) ); return true; } return false; } bool ResourceItemModel::setNormalRate( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toDouble() == res->normalRate() ) { return false; } emit executeCommand( new ModifyResourceNormalRateCmd( res, value.toDouble(), kundo2_i18n( "Modify resource normal rate" ) ) ); return true; } return false; } bool ResourceItemModel::setOvertimeRate( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: if ( value.toDouble() == res->overtimeRate() ) { return false; } emit executeCommand( new ModifyResourceOvertimeRateCmd( res, value.toDouble(), kundo2_i18n( "Modify resource overtime rate" ) ) ); return true; } return false; } bool ResourceItemModel::setAccount( Resource *res, const QVariant &value, int role ) { switch ( role ) { case Qt::EditRole: { Account *a = 0; if ( value.type() == QVariant::Int ) { QStringList lst = m_model.account( res, Role::EnumList ).toStringList(); if ( value.toInt() >= lst.count() ) { return false; } a = m_project->accounts().findAccount( lst.at( value.toInt() ) ); } else if ( value.type() == QVariant::String ) { a = m_project->accounts().findAccount( value.toString() ); } Account *old = res->account(); if ( old != a ) { emit executeCommand( new ResourceModifyAccountCmd( *res, old, a, kundo2_i18n( "Modify resource account" ) ) ); return true; } } default: break; } return false; } QVariant ResourceItemModel::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 ResourceItemModel::data( const QModelIndex &index, int role ) const { QVariant result; QObject *obj = object( index ); if ( obj == 0 ) { return QVariant(); } if ( role == Qt::TextAlignmentRole ) { // use same alignment as in header (headers always horizontal) return headerData( index.column(), Qt::Horizontal, role ); } Resource *r = qobject_cast( obj ); if ( r ) { result = m_model.data( r, index.column(), role ); } else { ResourceGroup *g = qobject_cast( obj ); if ( g ) { result = m_model.data( g, index.column(), role ); } } return result; } bool ResourceItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) { if ( ! index.isValid() ) { return ItemModelBase::setData( index, value, role ); } if (role != Qt::EditRole && role != Qt::CheckStateRole) { return false; } if ((flags( index ) & (Qt::ItemIsEditable | Qt::ItemIsUserCheckable)) == 0) { return false; } QObject *obj = object( index ); Resource *r = qobject_cast( obj ); if ( r ) { switch (index.column()) { case ResourceModel::ResourceName: return setName( r, value, role ); case ResourceModel::ResourceScope: return false; // Not editable case ResourceModel::ResourceType: return setType( r, value, role ); case ResourceModel::ResourceInitials: return setInitials( r, value, role ); case ResourceModel::ResourceEmail: return setEmail( r, value, role ); case ResourceModel::ResourceCalendar: return setCalendar( r, value, role ); case ResourceModel::ResourceLimit: return setUnits( r, value, role ); case ResourceModel::ResourceAvailableFrom: return setAvailableFrom( r, value, role ); case ResourceModel::ResourceAvailableUntil: return setAvailableUntil( r, value, role ); case ResourceModel::ResourceNormalRate: return setNormalRate( r, value, role ); case ResourceModel::ResourceOvertimeRate: return setOvertimeRate( r, value, role ); case ResourceModel::ResourceAccount: return setAccount( r, value, role ); default: qWarning("data: invalid display value column %d", index.column()); return false; } } else { ResourceGroup *g = qobject_cast( obj ); if ( g ) { switch (index.column()) { case ResourceModel::ResourceName: return setName( g, value, role ); case ResourceModel::ResourceScope: return false; // Not editable case ResourceModel::ResourceType: return setType( g, value, role ); default: qWarning("data: invalid display value column %d", index.column()); return false; } } } return false; } QVariant ResourceItemModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Horizontal ) { if ( role == Qt::DisplayRole || role == Qt::TextAlignmentRole ) { return m_model.headerData( section, role ); } } if ( role == Qt::ToolTipRole ) { return m_model.headerData( section, role ); } return ItemModelBase::headerData(section, orientation, role); } QAbstractItemDelegate *ResourceItemModel::createDelegate( int col, QWidget *parent ) const { switch ( col ) { case ResourceModel::ResourceType: return new EnumDelegate( parent ); case ResourceModel::ResourceCalendar: return new EnumDelegate( parent ); case ResourceModel::ResourceAvailableFrom: return new DateTimeCalendarDelegate( parent ); case ResourceModel::ResourceAvailableUntil: return new DateTimeCalendarDelegate( parent ); case ResourceModel::ResourceAccount: return new EnumDelegate( parent ); default: break; } return 0; } QObject *ResourceItemModel::object( const QModelIndex &index ) const { QObject *o = 0; if ( index.isValid() ) { Q_ASSERT( m_project ); //debugPlan<<(void*)index.internalPointer()<resourceGroups()<resourceList(); Q_ASSERT(m_project->resourceGroups().contains(static_cast(index.internalPointer())) || m_project->resourceList().contains(static_cast(index.internalPointer()))); o = static_cast( index.internalPointer() ); Q_ASSERT( o ); } return o; } ResourceGroup *ResourceItemModel::group( const QModelIndex &index ) const { return qobject_cast( object( index ) ); } Resource *ResourceItemModel::resource( const QModelIndex &index ) const { return qobject_cast( object( index ) ); } void ResourceItemModel::slotCalendarChanged( Calendar* ) { foreach ( Resource *r, m_project->resourceList() ) { if ( r->calendar( true ) == 0 ) { slotResourceChanged( r ); } } } void ResourceItemModel::slotResourceChanged( Resource *res ) { ResourceGroup *g = res->parentGroup(); if ( g ) { int row = g->indexOf( res ); emit dataChanged( createIndex( row, 0, res ), createIndex( row, columnCount() - 1, res ) ); return; } } void ResourceItemModel::slotResourceGroupChanged( ResourceGroup *res ) { Project *p = res->project(); if ( p ) { int row = p->resourceGroups().indexOf( res ); emit dataChanged( createIndex( row, 0, res ), createIndex( row, columnCount() - 1, res ) ); } } Qt::DropActions ResourceItemModel::supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; } bool ResourceItemModel::dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data ) { if ( data->hasFormat( "application/x-vnd.kde.plan.resourceitemmodel.internal" ) ) { QByteArray encodedData = data->data( "application/x-vnd.kde.plan.resourceitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); int i = 0; foreach ( Resource *r, resourceList( stream ) ) { if (r->isShared()) { return false; } } } //debugPlan<( object( index ) ); // Allow only on group default: break; } return false; } QStringList ResourceItemModel::mimeTypes() const { return ItemModelBase::mimeTypes() #ifdef PLAN_KDEPIMLIBS_FOUND << "text/x-vcard" << "text/directory" << "text/uri-list" #endif << "application/x-vnd.kde.plan.resourceitemmodel.internal"; } void ResourceItemModel::slotDataArrived( KIO::Job *job, const QByteArray &data ) { if ( m_dropDataMap.contains( job ) ) { m_dropDataMap[ job ].data += data; } } void ResourceItemModel::slotJobFinished( KJob *job ) { if ( job->error() || ! m_dropDataMap.contains( job ) ) { debugPlan<<(job->error() ? "Job error":"Error: no such job"); } else if ( QMimeDatabase().mimeTypeForData( m_dropDataMap[ job ].data ).inherits(QStringLiteral("text/x-vcard") ) ) { ResourceGroup *g = 0; if ( m_dropDataMap[ job ].parent.isValid() ) { g = qobject_cast( object( m_dropDataMap[ job ].parent ) ); } else { g = qobject_cast( object( index( m_dropDataMap[ job ].row, m_dropDataMap[ job ].column, m_dropDataMap[ job ].parent ) ) ); } if ( g == 0 ) { debugPlan<<"No group"<findResource( uid ) ) { r->setId( uid ); } r->setName( lst[a].formattedName() ); r->setEmail( lst[a].preferredEmail() ); m->addCommand( new AddResourceCmd( group, r ) ); } if ( m->isEmpty() ) { delete m; return false; } emit executeCommand( m ); return true; #else Q_UNUSED(group); Q_UNUSED(data); return false; #endif } bool ResourceItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent ) { debugPlan< 0) { return false; } ResourceGroup *g = 0; if ( parent.isValid() ) { g = qobject_cast( object( parent ) ); } else { g = qobject_cast( object( index( row, column, parent ) ) ); } if ( g == 0 ) { debugPlan<<"No group"<formats()<name(); if ( data->hasFormat( "application/x-vnd.kde.plan.resourceitemmodel.internal" ) ) { debugPlan<data( "application/x-vnd.kde.plan.resourceitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); int i = 0; foreach ( Resource *r, resourceList( stream ) ) { if ( r->parentGroup() == g ) { continue; } if ( m == 0 ) m = new MacroCommand( KUndo2MagicString() ); m->addCommand( new MoveResourceCmd( g, r ) ); ++i; } if ( m ) { KUndo2MagicString msg = kundo2_i18np( "Move resource", "Move %1 resources", i ); MacroCommand *c = new MacroCommand( msg ); c->addCommand( m ); emit executeCommand( c ); } return true; } if ( action == Qt::CopyAction ) { MacroCommand *m = 0; QByteArray encodedData = data->data( "application/x-vnd.kde.plan.resourceitemmodel.internal" ); QDataStream stream(&encodedData, QIODevice::ReadOnly); int i = 0; foreach ( Resource *r, resourceList( stream ) ) { Resource *nr = new Resource( r ); if ( m == 0 ) m = new MacroCommand( KUndo2MagicString() ); m->addCommand( new AddResourceCmd( g, nr ) ); ++i; } if ( m ) { KUndo2MagicString msg = kundo2_i18np( "Copy resource", "Copy %1 resources", i ); MacroCommand *c = new MacroCommand( msg ); c->addCommand( m ); emit executeCommand( c ); } return true; } return true; } if ( data->hasFormat( "text/x-vcard" ) || data->hasFormat( "text/directory" ) ) { if ( action != Qt::CopyAction ) { return false; } QString f = data->hasFormat( "text/x-vcard" ) ? "text/x-vcard" : "text/directory"; return createResources( g, data->data( f ) ); } if ( data->hasFormat( "text/uri-list" ) ) { const QList urls = data->urls(); if ( urls.isEmpty() ) { return false; } bool result = false; foreach ( const QUrl &url, urls ) { if ( url.scheme() != "akonadi" ) { debugPlan<setSide( KIO::StatJob::SourceSide ); const bool isUrlReadable = statJob->exec(); if (! isUrlReadable ) { debugPlan<start(); result = true; } return result; } return false; } QList ResourceItemModel::resourceList( QDataStream &stream ) { QList lst; while (!stream.atEnd()) { QString id; stream >> id; Resource *r = m_project->findResource( id ); if ( r ) { lst << r; } } debugPlan< rows; foreach (const QModelIndex &index, indexes) { if ( index.isValid() && !rows.contains( index.row() ) ) { //debugPlan<( object( index ) ); if ( r ) { rows << index.row(); stream << r->id(); } else if ( ::qobject_cast( object( index ) ) ) { rows.clear(); break; } } } if (!rows.isEmpty()) { m->setData("application/x-vnd.kde.plan.resourceitemmodel.internal", encodedData); } return m; } QModelIndex ResourceItemModel::insertGroup( ResourceGroup *g ) { //debugPlan; emit executeCommand( new AddResourceGroupCmd( m_project, g, kundo2_i18n( "Add resource group" ) ) ); int row = m_project->resourceGroups().indexOf( g ); if ( row != -1 ) { return createIndex( row, 0, g ); } return QModelIndex(); } QModelIndex ResourceItemModel::insertResource( ResourceGroup *g, Resource *r, Resource * /*after*/ ) { //debugPlan; emit executeCommand( new AddResourceCmd( g, r, kundo2_i18n( "Add resource" ) ) ); int row = g->indexOf( r ); if ( row != -1 ) { return createIndex( row, 0, r ); } return QModelIndex(); } int ResourceItemModel::sortRole( int column ) const { switch ( column ) { case ResourceModel::ResourceAvailableFrom: case ResourceModel::ResourceAvailableUntil: return Qt::EditRole; default: break; } return Qt::DisplayRole; } //------------------- ResourceItemSFModel::ResourceItemSFModel( QObject *parent ) : QSortFilterProxyModel( parent ) { setDynamicSortFilter( true ); setSourceModel( new ResourceItemModel( this ) ); } void ResourceItemSFModel::setProject( Project *project ) { static_cast( sourceModel() )->setProject( project ); } Resource *ResourceItemSFModel::resource( const QModelIndex &idx ) const { return static_cast( sourceModel() )->resource( mapToSource( idx ) ); } QModelIndex ResourceItemSFModel::index( Resource *r ) const { return mapFromSource( static_cast( sourceModel() )->index( r ) ); } Qt::ItemFlags ResourceItemSFModel::flags( const QModelIndex & index ) const { Qt::ItemFlags f = QSortFilterProxyModel::flags( index ); if ( index.isValid() && ! parent( index ).isValid() ) { // group, not selectable f &= ~Qt::ItemIsSelectable; } return f; } void ResourceItemSFModel::addFilteredResource( const Resource *r ) { if ( ! m_filteredResources.contains( r ) ) { m_filteredResources << r; } } bool ResourceItemSFModel::filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const { //TODO make this general filter ResourceItemModel *m = static_cast( sourceModel() ); if ( m->index( source_row, ResourceModel::ResourceType, source_parent ).data( Role::EnumListValue ).toInt() == ResourceGroup::Type_Work ) { return false; } QModelIndex idx = m->index( source_row, 0, source_parent ); return ! m_filteredResources.contains( m->resource( idx ) ); } //----------------------- AllocatedResourceItemModel::AllocatedResourceItemModel( QObject *parent ) : QSortFilterProxyModel( parent ), m_task( 0 ) { setDynamicSortFilter( true ); setSourceModel( new ResourceItemModel( this ) ); } int AllocatedResourceItemModel::columnCount( const QModelIndex &idx ) const { Q_UNUSED(idx); return 2; } Project *AllocatedResourceItemModel::project() const { return static_cast( sourceModel() )->project(); } void AllocatedResourceItemModel::setProject( Project *project ) { debugPlan<project()<<"="<project(); if ( p ) { disconnect(p, &Project::nodeChanged, this, &AllocatedResourceItemModel::slotNodeChanged); } static_cast( sourceModel() )->setProject( project ); if ( project ) { connect(project, &Project::nodeChanged, this, &AllocatedResourceItemModel::slotNodeChanged); } debugPlan<rowCount(); } void AllocatedResourceItemModel::reset() { beginResetModel(); endResetModel(); emit expandAll(); emit resizeColumnToContents( 0 ); } void AllocatedResourceItemModel::slotNodeChanged( Node *n ) { debugPlan<<(n==m_task)<name(); if ( n != m_task ) { return; } reset(); } Task *AllocatedResourceItemModel::task() const { return m_task; } void AllocatedResourceItemModel::setTask( Task *task ) { debugPlan<name():""); m_task = task; reset(); debugPlan<rowCount(); } QObject* AllocatedResourceItemModel::object(const QModelIndex& idx) const { return static_cast( sourceModel() )->object( mapToSource( idx ) ); } Resource *AllocatedResourceItemModel::resource( const QModelIndex &idx ) const { return qobject_cast( object( idx ) ); } QModelIndex AllocatedResourceItemModel::index( Resource *r ) const { return mapFromSource( static_cast( sourceModel() )->index( r ) ); } Qt::ItemFlags AllocatedResourceItemModel::flags( const QModelIndex & index ) const { Qt::ItemFlags f = QSortFilterProxyModel::flags( index ); f &= ~Qt::ItemIsUserCheckable; return f; } QVariant AllocatedResourceItemModel::headerData(int section, Qt::Orientation orientation, int role) const { if ( section == 1 ) { if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) { return xi18nc( "@title:column", "Allocation" ); } return QVariant(); } return QSortFilterProxyModel::headerData( section, orientation, role ); } QVariant AllocatedResourceItemModel::allocation( const Resource *res, int role ) const { ResourceRequest *rr = m_task->requests().find( res ); ResourceGroupRequest *gr = m_task->requests().find( res->parentGroup() ); if ( rr == 0 || gr == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: { case Qt::EditRole: // xgettext: no-c-format return i18nc( "%", "%1%",rr->units() ); } case Qt::ToolTipRole: { if ( rr->units() == 0 ) { return xi18nc( "@info:tooltip", "Not allocated" ); } return xi18nc( "@info:tooltip", "%1 allocated out of %2 available", gr->count(), res->parentGroup()->numResources() ); } default: break; } return QVariant(); } QVariant AllocatedResourceItemModel::allocation( const ResourceGroup *res, int role ) const { ResourceGroupRequest *gr = m_task->requests().find( res ); if ( gr == 0 ) { return QVariant(); } switch ( role ) { case Qt::DisplayRole: case Qt::EditRole: return QString( "%1 (%2)" ).arg( gr->units() ).arg( gr->count() ); case Qt::ToolTipRole: { QString s1 = i18ncp( "@info:tooltip", "%1 resource requested for dynamic allocation", "%1 resources requested for dynamic allocation", gr->units() ); QString s2 = i18ncp( "@info:tooltip", "%1 resource allocated", "%1 resources allocated", gr->count() ); return xi18nc( "@info:tooltip", "%1%2", s1, s2 ); } case Qt::WhatsThisRole: { return xi18nc( "@info:whatsthis", "Group allocations" "You can allocate a number of resources from a group and let" " the scheduler select from the available resources at the time of scheduling." " These dynamically allocated resources will be in addition to any resource you have allocated specifically." ); } case Role::Minimum: { return 0; } case Role::Maximum: { return res->numResources() - gr->units(); } default: break; } return QVariant(); } QVariant AllocatedResourceItemModel::data(const QModelIndex& idx, int role) const { if ( m_task == 0 || role == Qt::CheckStateRole || role == Qt::DecorationRole ) { return QVariant(); } if ( idx.column() == 1 ) { switch ( role ) { case Qt::TextAlignmentRole: return Qt::AlignLeft; default: { QObject *o = object( idx ); Resource *r = qobject_cast( o ); if ( r ) { return allocation( r, role ); } ResourceGroup *g = qobject_cast( o ); if ( g ) { return allocation( g, role ); } break; } return QVariant(); } } return QSortFilterProxyModel::data( idx, role ); } bool AllocatedResourceItemModel::filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const { if ( m_task == 0 ) { return false; } QModelIndex idx = sourceModel()->index( source_row, 0, source_parent ); if ( ! idx.isValid() ) { return false; } bool result = false; const ResourceRequestCollection &req = m_task->requests(); if ( source_parent.isValid() ) { const Resource *r = static_cast( sourceModel() )->resource( idx ); result = (bool) req.find( r ); } else { const ResourceGroup *g = static_cast( sourceModel() )->group( idx ); ResourceGroupRequest *gr = req.find( g ); result = (bool) gr && ( gr->units() > 0 || gr->count() > 0 ); } debugPlan<