1/* This file is part of the KDE project
2 Copyright (C) 2007 Dag Andersen <danders@get2net.dk>
3 Copyright (C) 2011, 2012 Dag Andersen <danders@get2net.dk>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18* Boston, MA 02110-1301, USA.
19*/
20
21#include "kptresourcemodel.h"
22
23#include "kptcommonstrings.h"
24#include "kptcommand.h"
25#include "kptitemmodelbase.h"
26#include "kptcalendar.h"
27#include "kptduration.h"
28#include "kptnode.h"
29#include "kptproject.h"
30#include "kpttask.h"
31#include "kptresource.h"
32#include "kptdatetime.h"
33#include "kptdebug.h"
34
35#include <KoIcon.h>
36
37#include <QMimeData>
38#include <QObject>
39#include <QStringList>
40
41#include <kaction.h>
42#include <kglobal.h>
43#include <klocale.h>
44#include <kactioncollection.h>
45#include <kio/netaccess.h>
46#include <kmimetype.h>
47#include <kio/job.h>
48
49#ifdef PLAN_KDEPIMLIBS_FOUND
50#include <kabc/addressee.h>
51#include <kabc/vcardconverter.h>
52#endif
53
54
55namespace KPlato
56{
57
58//--------------------------------------
59
60ResourceModel::ResourceModel( QObject *parent )
61 : QObject( parent ),
62 m_project( 0 )
63{
64}
65
66ResourceModel::~ResourceModel()
67{
68}
69
70const QMetaEnum ResourceModel::columnMap() const
71{
72 return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") );
73}
74
75void ResourceModel::setProject( Project *project )
76{
77 m_project = project;
78}
79
80int ResourceModel::propertyCount() const
81{
82 return columnMap().keyCount();
83}
84
85QVariant ResourceModel::name( const Resource *res, int role ) const
86{
87 //kDebug(planDbg())<<res->name()<<","<<role;
88 switch ( role ) {
89 case Qt::DisplayRole:
90 case Qt::EditRole:
91 return res->name();
92 case Qt::ToolTipRole:
93 if ( res->autoAllocate() ) {
94 return i18nc( "@info:tooltip", "%1:<nl/>This resource will be automatically allocated to new tasks", res->name() );
95 }
96 return res->name();
97 case Qt::StatusTipRole:
98 case Qt::WhatsThisRole:
99 return QVariant();
100 case Qt::DecorationRole:
101 if ( res->isBaselined() ) {
102 return koIcon("view-time-schedule-baselined");
103 }
104 break;
105 case Qt::CheckStateRole:
106 return res->autoAllocate() ? Qt::Checked : Qt::Unchecked;
107 default:
108 break;
109 }
110 return QVariant();
111}
112
113QVariant ResourceModel::name( const ResourceGroup *res, int role ) const
114{
115 //kDebug(planDbg())<<res->name()<<","<<role;
116 switch ( role ) {
117 case Qt::DisplayRole:
118 case Qt::EditRole:
119 case Qt::ToolTipRole:
120 return res->name();
121 break;
122 case Qt::StatusTipRole:
123 case Qt::WhatsThisRole:
124 return QVariant();
125 }
126 return QVariant();
127}
128
129QVariant ResourceModel::type( const Resource *res, int role ) const
130{
131 switch ( role ) {
132 case Qt::DisplayRole:
133 case Qt::ToolTipRole:
134 return res->typeToString( true );
135 case Qt::EditRole:
136 return res->typeToString( false );
137 case Role::EnumList:
138 return res->typeToStringList( true );
139 case Role::EnumListValue:
140 return (int)res->type();
141 case Qt::TextAlignmentRole:
142 return Qt::AlignCenter;
143 case Qt::StatusTipRole:
144 case Qt::WhatsThisRole:
145 return QVariant();
146 }
147 return QVariant();
148}
149
150QVariant ResourceModel::type( const ResourceGroup *res, int role ) const
151{
152 switch ( role ) {
153 case Qt::DisplayRole:
154 case Qt::ToolTipRole:
155 return res->typeToString( true );
156 case Qt::EditRole:
157 return res->typeToString( false );
158 case Role::EnumList:
159 return res->typeToStringList( true );
160 case Role::EnumListValue:
161 return (int)res->type();
162 case Qt::TextAlignmentRole:
163 return Qt::AlignCenter;
164 case Qt::StatusTipRole:
165 case Qt::WhatsThisRole:
166 return QVariant();
167 }
168 return QVariant();
169}
170
171
172QVariant ResourceModel::initials( const Resource *res, int role ) const
173{
174 switch ( role ) {
175 case Qt::DisplayRole:
176 case Qt::EditRole:
177 case Qt::ToolTipRole:
178 return res->initials();
179 case Qt::TextAlignmentRole:
180 return Qt::AlignCenter;
181 case Qt::StatusTipRole:
182 case Qt::WhatsThisRole:
183 return QVariant();
184 }
185 return QVariant();
186}
187
188QVariant ResourceModel::email( const Resource *res, int role ) const
189{
190 switch ( role ) {
191 case Qt::DisplayRole:
192 case Qt::EditRole:
193 case Qt::ToolTipRole:
194 return res->email();
195 case Qt::TextAlignmentRole:
196 return Qt::AlignCenter;
197 case Qt::StatusTipRole:
198 case Qt::WhatsThisRole:
199 return QVariant();
200 }
201 return QVariant();
202}
203
204QVariant ResourceModel::calendar( const Resource *res, int role ) const
205{
206 switch ( role ) {
207 case Qt::DisplayRole: {
208 if ( res->type() == Resource::Type_Team ) {
209 return " ";
210 }
211 QString s = i18n( "None" );
212 Calendar *cal = res->calendar( true ); // don't check for default calendar
213 if ( cal ) {
214 s = cal->name();
215 } else if ( res->type() == Resource::Type_Work ) {
216 // Do we get a default calendar
217 cal = res->calendar();
218 if ( cal ) {
219 s = i18nc( "Default (calendar name)", "Default (%1)", cal->name() );
220 }
221 }
222 return s;
223 }
224 case Qt::ToolTipRole: {
225 if ( res->type() == Resource::Type_Team ) {
226 return i18nc( "@info:tooltip", "A team resource does not have a calendar" );
227 }
228 QString s = i18nc( "@info:tooltip", "No calendar" );
229 Calendar *cal = res->calendar( true ); // don't check for default calendar
230 if ( cal ) {
231 s = cal->name();
232 } else if ( res->type() == Resource::Type_Work ) {
233 // Do we get a default calendar
234 cal = res->calendar();
235 if ( cal ) {
236 s = i18nc( "@info:tooltip 1=calendar name", "Using default calendar: %1", cal->name() );
237 }
238 }
239 return s;
240 }
241 case Role::EnumList: {
242 Calendar *cal = m_project->defaultCalendar();
243 QString s = i18n( "None" );
244 if ( cal && res->type() == Resource::Type_Work ) {
245 s = i18nc( "Default (calendar name)", "Default (%1)", cal->name() );
246 }
247 return QStringList() << s << m_project->calendarNames();
248 }
249 case Qt::EditRole:
250 case Role::EnumListValue: {
251 Calendar *cal = res->calendar( true ); // don't check for default calendar
252 return cal == 0 ? 0 : m_project->calendarNames().indexOf( cal->name() ) + 1;
253 }
254 case Qt::TextAlignmentRole:
255 return Qt::AlignCenter;
256 case Qt::StatusTipRole:
257 case Qt::WhatsThisRole:
258 return QVariant();
259 }
260 return QVariant();
261}
262
263QVariant ResourceModel::units( const Resource *res, int role ) const
264{
265 switch ( role ) {
266 case Qt::DisplayRole:
267 case Qt::EditRole:
268 return res->units();
269 case Qt::TextAlignmentRole:
270 return Qt::AlignCenter;
271 case Qt::ToolTipRole:
272 case Qt::StatusTipRole:
273 case Qt::WhatsThisRole:
274 return QVariant();
275 }
276 return QVariant();
277}
278
279QVariant ResourceModel::availableFrom( const Resource *res, int role ) const
280{
281 switch ( role ) {
282 case Qt::DisplayRole:
283 return KGlobal::locale()->formatDateTime( res->availableFrom() );
284 case Qt::EditRole:
285 return res->availableFrom();
286 case Qt::TextAlignmentRole:
287 return Qt::AlignCenter;
288 case Qt::ToolTipRole: {
289 if ( res->availableFrom().isValid() ) {
290 return i18nc( "infor:tooltip", "Available from: %1", KGlobal::locale()->formatDateTime( res->availableFrom(), KLocale::LongDate, KLocale::TimeZone ) );
291 }
292 return i18nc( "infor:tooltip", "Available from project target start time: %1", KGlobal::locale()->formatDateTime( m_project->constraintStartTime(), KLocale::LongDate, KLocale::TimeZone ) );
293 }
294 case Qt::StatusTipRole:
295 case Qt::WhatsThisRole:
296 return QVariant();
297 }
298 return QVariant();
299}
300
301QVariant ResourceModel::availableUntil( const Resource *res, int role ) const
302{
303 switch ( role ) {
304 case Qt::DisplayRole:
305 return KGlobal::locale()->formatDateTime( res->availableUntil() );
306 case Qt::EditRole:
307 return res->availableUntil();
308 case Qt::TextAlignmentRole:
309 return Qt::AlignCenter;
310 case Qt::ToolTipRole: {
311 if ( res->availableUntil().isValid() ) {
312 return i18nc( "infor:tooltip", "Available until: %1", KGlobal::locale()->formatDateTime( res->availableUntil(), KLocale::LongDate, KLocale::TimeZone ) );
313 }
314 return i18nc( "infor:tooltip", "Available from project target finish time: %1", KGlobal::locale()->formatDateTime( m_project->constraintEndTime(), KLocale::LongDate, KLocale::TimeZone ) );
315 }
316 case Qt::StatusTipRole:
317 case Qt::WhatsThisRole:
318 return QVariant();
319 }
320 return QVariant();
321}
322
323QVariant ResourceModel::normalRate( const Resource *res, int role ) const
324{
325 switch ( role ) {
326 case Qt::DisplayRole:
327 return m_project->locale()->formatMoney( res->normalRate() );
328 case Qt::EditRole:
329 return res->normalRate();
330 case Qt::TextAlignmentRole:
331 return Qt::AlignCenter;
332 case Qt::ToolTipRole:
333 return i18n( "Cost per hour, normal time: %1", m_project->locale()->formatMoney( res->normalRate() ) );
334 case Qt::StatusTipRole:
335 case Qt::WhatsThisRole:
336 return QVariant();
337 }
338 return QVariant();
339}
340
341QVariant ResourceModel::overtimeRate( const Resource *res, int role ) const
342{
343 switch ( role ) {
344 case Qt::DisplayRole:
345 return m_project->locale()->formatMoney( res->overtimeRate() );
346 case Qt::EditRole:
347 return res->overtimeRate();
348 case Qt::TextAlignmentRole:
349 return Qt::AlignCenter;
350 case Qt::ToolTipRole:
351 return i18n( "Cost per hour, overtime: %1", m_project->locale()->formatMoney( res->overtimeRate() ) );
352 case Qt::StatusTipRole:
353 case Qt::WhatsThisRole:
354 return QVariant();
355 }
356 return QVariant();
357}
358
359QVariant ResourceModel::account( const Resource *resource, int role ) const
360{
361 switch ( role ) {
362 case Qt::DisplayRole: {
363 Account *a = resource->account();
364 return a == 0 ? i18n( "None" ) : a->name();
365 }
366 case Qt::ToolTipRole: {
367 Account *a = resource->account();
368 return i18n( "Account: %1", (a == 0 ? i18n( "None" ) : a->name() ) );
369 }
370 case Role::EnumListValue:
371 case Qt::EditRole: {
372 Account *a = resource->account();
373 return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 );
374 }
375 case Role::EnumList: {
376 QStringList lst;
377 lst << i18n("None");
378 lst += m_project->accounts().costElements();
379 return lst;
380 }
381 case Qt::StatusTipRole:
382 case Qt::WhatsThisRole:
383 return QVariant();
384 }
385 return QVariant();
386}
387
388QVariant ResourceModel::data( const Resource *resource, int property, int role ) const
389{
390 if ( role == Role::ObjectType ) {
391 return OT_Resource;
392 }
393 QVariant result;
394 if ( resource == 0 ) {
395 return result;
396 }
397 switch ( property ) {
398 case ResourceName: result = name( resource, role ); break;
399 case ResourceType: result = type( resource, role ); break;
400 case ResourceInitials: result = initials( resource, role ); break;
401 case ResourceEmail: result = email( resource, role ); break;
402 case ResourceCalendar: result = calendar( resource, role ); break;
403 case ResourceLimit: result = units( resource, role ); break;
404 case ResourceAvailableFrom: result = availableFrom( resource, role ); break;
405 case ResourceAvailableUntil: result = availableUntil( resource, role ); break;
406 case ResourceNormalRate: result = normalRate( resource, role ); break;
407 case ResourceOvertimeRate: result = overtimeRate( resource, role ); break;
408 case ResourceAccount: result = account( resource, role ); break;
409 default:
410 kDebug(planDbg())<<"data: invalid display value: property="<<property;
411 break;
412 }
413 return result;
414}
415
416QVariant ResourceModel::data( const ResourceGroup *group, int property, int role ) const
417{
418 if ( role == Role::ObjectType ) {
419 return OT_ResourceGroup;
420 }
421 QVariant result;
422 if ( group == 0 ) {
423 return result;
424 }
425 switch ( property ) {
426 case ResourceModel::ResourceName: result = name( group, role ); break;
427 case ResourceModel::ResourceType: result = type( group, role ); break;
428 default:
429 if ( role == Qt::DisplayRole ) {
430 if ( property < propertyCount() ) {
431 result = QString();
432 } else {
433 kDebug(planDbg())<<"data: invalid display value column"<<property;;
434 return QVariant();
435 }
436 }
437 break;
438 }
439 return result;
440}
441
442
443QVariant ResourceModel::headerData( int section, int role )
444{
445 if ( role == Qt::DisplayRole ) {
446 switch ( section ) {
447 case ResourceName: return i18n( "Name" );
448 case ResourceType: return i18n( "Type" );
449 case ResourceInitials: return i18n( "Initials" );
450 case ResourceEmail: return i18n( "Email" );
451 case ResourceCalendar: return i18n( "Calendar" );
452 case ResourceLimit: return i18n( "Limit (%)" );
453 case ResourceAvailableFrom: return i18n( "Available From" );
454 case ResourceAvailableUntil: return i18n( "Available Until" );
455 case ResourceNormalRate: return i18n( "Normal Rate" );
456 case ResourceOvertimeRate: return i18n( "Overtime Rate" );
457 case ResourceAccount: return i18n( "Account" );
458 default: return QVariant();
459 }
460 } else if ( role == Qt::TextAlignmentRole ) {
461 switch (section) {
462 case ResourceName:
463 case ResourceType:
464 case ResourceInitials:
465 case ResourceEmail:
466 case ResourceCalendar:
467 return QVariant();
468 case ResourceLimit:
469 return (int)(Qt::AlignRight|Qt::AlignVCenter);
470 case ResourceAvailableFrom:
471 case ResourceAvailableUntil:
472 return QVariant();
473 case ResourceNormalRate:
474 case ResourceOvertimeRate:
475 return (int)(Qt::AlignRight|Qt::AlignVCenter);
476 case ResourceAccount:
477 return QVariant();
478 default:
479 return QVariant();
480 }
481 } else if ( role == Qt::ToolTipRole ) {
482 switch ( section ) {
483 case ResourceName: return ToolTip::resourceName();
484 case ResourceType: return ToolTip::resourceType();
485 case ResourceInitials: return ToolTip::resourceInitials();
486 case ResourceEmail: return ToolTip::resourceEMail();
487 case ResourceCalendar: return ToolTip::resourceCalendar();
488 case ResourceLimit: return ToolTip::resourceUnits();
489 case ResourceAvailableFrom: return ToolTip::resourceAvailableFrom();
490 case ResourceAvailableUntil: return ToolTip::resourceAvailableUntil();
491 case ResourceNormalRate: return ToolTip::resourceNormalRate();
492 case ResourceOvertimeRate: return ToolTip::resourceOvertimeRate();
493 case ResourceAccount: return ToolTip::resourceAccount();
494 default: return QVariant();
495 }
496 }
497 return QVariant();
498}
499
500//--------------------------------------
501
502ResourceItemModel::ResourceItemModel( QObject *parent )
503 : ItemModelBase( parent ),
504 m_group( 0 ),
505 m_resource( 0 )
506{
507}
508
509ResourceItemModel::~ResourceItemModel()
510{
511}
512
513void ResourceItemModel::slotResourceToBeInserted( const ResourceGroup *group, int row )
514{
515 //kDebug(planDbg())<<group->name()<<","<<row;
516 Q_ASSERT( m_group == 0 );
517 m_group = const_cast<ResourceGroup*>(group);
518 beginInsertRows( index( group ), row, row );
519}
520
521void ResourceItemModel::slotResourceInserted( const Resource *resource )
522{
523 //kDebug(planDbg())<<resource->name();
524 Q_ASSERT( resource->parentGroup() == m_group );
525#ifdef NDEBUG
526 Q_UNUSED(resource)
527#endif
528 endInsertRows();
529 m_group = 0;
530 emit layoutChanged(); //HACK to make the right view react! Bug in qt?
531}
532
533void ResourceItemModel::slotResourceToBeRemoved( const Resource *resource )
534{
535 //kDebug(planDbg())<<resource->name();
536 Q_ASSERT( m_resource == 0 );
537#ifdef NDEBUG
538 Q_UNUSED(resource)
539#endif
540 m_resource = const_cast<Resource*>(resource);
541 int row = index( resource ).row();
542 beginRemoveRows( index( resource->parentGroup() ), row, row );
543}
544
545void ResourceItemModel::slotResourceRemoved( const Resource *resource )
546{
547 //kDebug(planDbg())<<resource->name();
548 Q_ASSERT( resource == m_resource );
549#ifdef NDEBUG
550 Q_UNUSED(resource)
551#endif
552 endRemoveRows();
553 m_resource = 0;
554}
555
556void ResourceItemModel::slotResourceGroupToBeInserted( const ResourceGroup *group, int row )
557{
558 //kDebug(planDbg())<<group->name();
559 Q_ASSERT( m_group == 0 );
560 m_group = const_cast<ResourceGroup*>(group);
561 beginInsertRows( QModelIndex(), row, row );
562}
563
564void ResourceItemModel::slotResourceGroupInserted( const ResourceGroup *group )
565{
566 //kDebug(planDbg())<<group->name();
567 Q_ASSERT( group == m_group );
568#ifdef NDEBUG
569 Q_UNUSED(group)
570#endif
571 endInsertRows();
572 m_group = 0;
573}
574
575void ResourceItemModel::slotResourceGroupToBeRemoved( const ResourceGroup *group )
576{
577 //kDebug(planDbg())<<group->name();
578 Q_ASSERT( m_group == 0 );
579 m_group = const_cast<ResourceGroup*>(group);
580 int row = index( group ).row();
581 beginRemoveRows( QModelIndex(), row, row );
582}
583
584void ResourceItemModel::slotResourceGroupRemoved( const ResourceGroup *group )
585{
586 //kDebug(planDbg())<<group->name();
587 Q_ASSERT( group == m_group );
588#ifdef NDEBUG
589 Q_UNUSED(group)
590#endif
591
592 endRemoveRows();
593 m_group = 0;
594}
595
596void ResourceItemModel::slotLayoutChanged()
597{
598 emit layoutAboutToBeChanged();
599 emit layoutChanged();
600}
601
602void ResourceItemModel::setProject( Project *project )
603{
604 if ( m_project ) {
605 disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) );
606 disconnect( m_project, SIGNAL(resourceChanged(Resource*)), this, SLOT(slotResourceChanged(Resource*)) );
607 disconnect( m_project, SIGNAL(resourceGroupChanged(ResourceGroup*)), this, SLOT(slotResourceGroupChanged(ResourceGroup*)) );
608
609 disconnect( m_project, SIGNAL(resourceGroupToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(const ResourceGroup*,int)) );
610
611 disconnect( m_project, SIGNAL(resourceGroupToBeRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(const ResourceGroup*)) );
612
613 disconnect( m_project, SIGNAL(resourceToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(const ResourceGroup*,int)) );
614
615 disconnect( m_project, SIGNAL(resourceToBeRemoved(const Resource*)), this, SLOT(slotResourceToBeRemoved(const Resource*)) );
616
617 disconnect( m_project, SIGNAL(resourceGroupAdded(const ResourceGroup*)), this, SLOT(slotResourceGroupInserted(const ResourceGroup*)) );
618
619 disconnect( m_project, SIGNAL(resourceGroupRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(const ResourceGroup*)) );
620
621 disconnect( m_project, SIGNAL(resourceAdded(const Resource*)), this, SLOT(slotResourceInserted(const Resource*)) );
622
623 disconnect( m_project, SIGNAL(resourceRemoved(const Resource*)), this, SLOT(slotResourceRemoved(const Resource*)) );
624
625 disconnect( m_project, SIGNAL(defaultCalendarChanged(Calendar*)), this, SLOT(slotCalendarChanged(Calendar*)) );
626 }
627 m_project = project;
628 if ( m_project ) {
629 connect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) );
630 connect( m_project, SIGNAL(resourceChanged(Resource*)), this, SLOT(slotResourceChanged(Resource*)) );
631 connect( m_project, SIGNAL(resourceGroupChanged(ResourceGroup*)), this, SLOT(slotResourceGroupChanged(ResourceGroup*)) );
632
633 connect( m_project, SIGNAL(resourceGroupToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceGroupToBeInserted(const ResourceGroup*,int)) );
634
635 connect( m_project, SIGNAL(resourceGroupToBeRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupToBeRemoved(const ResourceGroup*)) );
636
637 connect( m_project, SIGNAL(resourceToBeAdded(const ResourceGroup*,int)), this, SLOT(slotResourceToBeInserted(const ResourceGroup*,int)) );
638
639 connect( m_project, SIGNAL(resourceToBeRemoved(const Resource*)), this, SLOT(slotResourceToBeRemoved(const Resource*)) );
640
641 connect( m_project, SIGNAL(resourceGroupAdded(const ResourceGroup*)), this, SLOT(slotResourceGroupInserted(const ResourceGroup*)) );
642
643 connect( m_project, SIGNAL(resourceGroupRemoved(const ResourceGroup*)), this, SLOT(slotResourceGroupRemoved(const ResourceGroup*)) );
644
645 connect( m_project, SIGNAL(resourceAdded(const Resource*)), this, SLOT(slotResourceInserted(const Resource*)) );
646
647 connect( m_project, SIGNAL(resourceRemoved(const Resource*)), this, SLOT(slotResourceRemoved(const Resource*)) );
648
649 connect( m_project, SIGNAL(defaultCalendarChanged(Calendar*)), this, SLOT(slotCalendarChanged(Calendar*)) );
650 }
651 m_model.setProject( m_project );
652 reset();
653}
654
655Qt::ItemFlags ResourceItemModel::flags( const QModelIndex &index ) const
656{
657 Qt::ItemFlags flags = ItemModelBase::flags( index );
658 if ( !m_readWrite ) {
659 //kDebug(planDbg())<<"read only"<<flags;
660 return flags &= ~Qt::ItemIsEditable;
661 }
662 if ( !index.isValid() ) {
663 //kDebug(planDbg())<<"invalid"<<flags;
664 return flags;
665 }
666 Resource *r = qobject_cast<Resource*>( object ( index ) );
667 if ( r != 0 ) {
668 flags |= Qt::ItemIsDragEnabled;
669 switch ( index.column() ) {
670 case ResourceModel::ResourceName:
671 flags |= Qt::ItemIsEditable | Qt::ItemIsUserCheckable;
672 break;
673 case ResourceModel::ResourceType:
674 if ( ! r->isBaselined() ) {
675 flags |= Qt::ItemIsEditable;
676 }
677 break;
678 case ResourceModel::ResourceAccount:
679 if ( ! r->isBaselined() ) {
680 flags |= Qt::ItemIsEditable;
681 }
682 break;
683 case ResourceModel::ResourceNormalRate:
684 if ( ! r->isBaselined() ) {
685 flags |= Qt::ItemIsEditable;
686 }
687 break;
688 case ResourceModel::ResourceOvertimeRate:
689 if ( ! r->isBaselined() ) {
690 flags |= Qt::ItemIsEditable;
691 }
692 break;
693 default:
694 flags |= Qt::ItemIsEditable;
695 }
696 //kDebug(planDbg())<<"resource"<<flags;
697 } else if ( qobject_cast<ResourceGroup*>( object( index ) ) ) {
698 flags |= Qt::ItemIsDropEnabled;
699 switch ( index.column() ) {
700 case ResourceModel::ResourceName: flags |= Qt::ItemIsEditable; break;
701 case ResourceModel::ResourceType: flags |= Qt::ItemIsEditable; break;
702 default: flags &= ~Qt::ItemIsEditable;
703 }
704 //kDebug(planDbg())<<"group"<<flags;
705 }
706 return flags;
707}
708
709
710QModelIndex ResourceItemModel::parent( const QModelIndex &index ) const
711{
712 if ( !index.isValid() || m_project == 0 ) {
713 return QModelIndex();
714 }
715 //kDebug(planDbg())<<index.internalPointer()<<":"<<index.row()<<","<<index.column();
716
717 Resource *r = qobject_cast<Resource*>( object( index ) );
718 if ( r && r->parentGroup() ) {
719 // only resources have parent
720 int row = m_project->indexOf( r->parentGroup() );
721 return createIndex( row, 0, r->parentGroup() );
722 }
723
724 return QModelIndex();
725}
726
727QModelIndex ResourceItemModel::index( int row, int column, const QModelIndex &parent ) const
728{
729 if ( m_project == 0 || column < 0 || column >= columnCount() || row < 0 ) {
730 return QModelIndex();
731 }
732 if ( ! parent.isValid() ) {
733 if ( row < m_project->numResourceGroups() ) {
734 return createIndex( row, column, m_project->resourceGroupAt( row ) );
735 }
736 return QModelIndex();
737 }
738 QObject *p = object( parent );
739 ResourceGroup *g = qobject_cast<ResourceGroup*>( p );
740 if ( g ) {
741 if ( row < g->numResources() ) {
742 return createIndex( row, column, g->resourceAt( row ) );
743 }
744 return QModelIndex();
745 }
746 return QModelIndex();
747}
748
749QModelIndex ResourceItemModel::index( const Resource *resource, int column ) const
750{
751 if ( m_project == 0 || resource == 0 ) {
752 return QModelIndex();
753 }
754 Resource *r = const_cast<Resource*>(resource);
755 int row = -1;
756 ResourceGroup *par = r->parentGroup();
757 if ( par ) {
758 row = par->indexOf( r );
759 return createIndex( row, column, r );
760 }
761 return QModelIndex();
762}
763
764QModelIndex ResourceItemModel::index( const ResourceGroup *group, int column ) const
765{
766 if ( m_project == 0 || group == 0 ) {
767 return QModelIndex();
768 }
769 ResourceGroup *g = const_cast<ResourceGroup*>(group);
770 int row = m_project->indexOf( g );
771 return createIndex( row, column, g );
772
773}
774
775int ResourceItemModel::columnCount( const QModelIndex &/*parent*/ ) const
776{
777 return m_model.propertyCount();
778}
779
780int ResourceItemModel::rowCount( const QModelIndex &parent ) const
781{
782 if ( m_project == 0 ) {
783 return 0;
784 }
785 if ( ! parent.isValid() ) {
786 return m_project->numResourceGroups();
787 }
788 QObject *p = object( parent );
789 ResourceGroup *g = qobject_cast<ResourceGroup*>( p );
790 if ( g ) {
791 return g->numResources();
792 }
793 return 0;
794}
795
796QVariant ResourceItemModel::name( const ResourceGroup *res, int role ) const
797{
798 //kDebug(planDbg())<<res->name()<<","<<role;
799 switch ( role ) {
800 case Qt::DisplayRole:
801 case Qt::EditRole:
802 case Qt::ToolTipRole:
803 return res->name();
804 case Qt::StatusTipRole:
805 case Qt::WhatsThisRole:
806 return QVariant();
807 }
808 return QVariant();
809}
810
811bool ResourceItemModel::setName( Resource *res, const QVariant &value, int role )
812{
813 switch ( role ) {
814 case Qt::EditRole:
815 if ( value.toString() == res->name() ) {
816 return false;
817 }
818 emit executeCommand( new ModifyResourceNameCmd( res, value.toString(), kundo2_i18n( "Modify resource name" ) ) );
819 return true;
820 case Qt::CheckStateRole:
821 emit executeCommand( new ModifyResourceAutoAllocateCmd( res, value.toBool(), kundo2_i18n( "Modify resource auto allocate" ) ) );
822 return true;
823 }
824 return false;
825}
826
827bool ResourceItemModel::setName( ResourceGroup *res, const QVariant &value, int role )
828{
829 switch ( role ) {
830 case Qt::EditRole:
831 if ( value.toString() == res->name() ) {
832 return false;
833 }
834 emit executeCommand( new ModifyResourceGroupNameCmd( res, value.toString(), kundo2_i18n( "Modify resourcegroup name" ) ) );
835 return true;
836 }
837 return false;
838}
839
840QVariant ResourceItemModel::type( const ResourceGroup *res, int role ) const
841{
842 switch ( role ) {
843 case Qt::DisplayRole:
844 case Qt::ToolTipRole:
845 return res->typeToString( true );
846 case Qt::EditRole:
847 return res->typeToString( false );
848 case Role::EnumList:
849 return res->typeToStringList( true );
850 case Role::EnumListValue:
851 return (int)res->type();
852 case Qt::TextAlignmentRole:
853 return Qt::AlignCenter;
854 case Qt::StatusTipRole:
855 case Qt::WhatsThisRole:
856 return QVariant();
857 }
858 return QVariant();
859}
860
861bool ResourceItemModel::setType( Resource *res, const QVariant &value, int role )
862{
863 switch ( role ) {
864 case Qt::EditRole: {
865 Resource::Type v;
866 QStringList lst = res->typeToStringList( false );
867 if ( lst.contains( value.toString() ) ) {
868 v = static_cast<Resource::Type>( lst.indexOf( value.toString() ) );
869 } else {
870 v = static_cast<Resource::Type>( value.toInt() );
871 }
872 if ( v == res->type() ) {
873 return false;
874 }
875 emit executeCommand( new ModifyResourceTypeCmd( res, v, kundo2_i18n( "Modify resource type" ) ) );
876 return true;
877 }
878 }
879 return false;
880}
881
882bool ResourceItemModel::setType( ResourceGroup *res, const QVariant &value, int role )
883{
884 switch ( role ) {
885 case Qt::EditRole: {
886 ResourceGroup::Type v;
887 QStringList lst = res->typeToStringList( false );
888 if ( lst.contains( value.toString() ) ) {
889 v = static_cast<ResourceGroup::Type>( lst.indexOf( value.toString() ) );
890 } else {
891 v = static_cast<ResourceGroup::Type>( value.toInt() );
892 }
893 if ( v == res->type() ) {
894 return false;
895 }
896 emit executeCommand( new ModifyResourceGroupTypeCmd( res, v, kundo2_i18n( "Modify resourcegroup type" ) ) );
897 return true;
898 }
899 }
900 return false;
901}
902
903bool ResourceItemModel::setInitials( Resource *res, const QVariant &value, int role )
904{
905 switch ( role ) {
906 case Qt::EditRole:
907 if ( value.toString() == res->initials() ) {
908 return false;
909 }
910 emit executeCommand( new ModifyResourceInitialsCmd( res, value.toString(), kundo2_i18n( "Modify resource initials" ) ) );
911 return true;
912 }
913 return false;
914}
915
916bool ResourceItemModel::setEmail( Resource *res, const QVariant &value, int role )
917{
918 switch ( role ) {
919 case Qt::EditRole:
920 if ( value.toString() == res->email() ) {
921 return false;
922 }
923 emit executeCommand( new ModifyResourceEmailCmd( res, value.toString(), kundo2_i18n( "Modify resource email" ) ) );
924 return true;
925 }
926 return false;
927}
928
929bool ResourceItemModel::setCalendar( Resource *res, const QVariant &value, int role )
930{
931 switch ( role ) {
932 case Qt::EditRole:
933 {
934 Calendar *c = 0;
935 if ( value.toInt() > 0 ) {
936 QStringList lst = m_model.calendar( res, Role::EnumList ).toStringList();
937 if ( value.toInt() < lst.count() ) {
938 c = m_project->calendarByName( lst.at( value.toInt() ) );
939 }
940 }
941 if ( c == res->calendar( true ) ) {
942 return false;
943 }
944 emit executeCommand( new ModifyResourceCalendarCmd( res, c, kundo2_i18n( "Modify resource calendar" ) ) );
945 return true;
946 }
947 }
948 return false;
949}
950
951
952bool ResourceItemModel::setUnits( Resource *res, const QVariant &value, int role )
953{
954 switch ( role ) {
955 case Qt::EditRole:
956 if ( value.toInt() == res->units() ) {
957 return false;
958 }
959 emit executeCommand( new ModifyResourceUnitsCmd( res, value.toInt(), kundo2_i18n( "Modify resource available units" ) ) );
960 return true;
961 }
962 return false;
963}
964
965bool ResourceItemModel::setAvailableFrom( Resource *res, const QVariant &value, int role )
966{
967 switch ( role ) {
968 case Qt::EditRole:
969 if ( value.toDateTime() == res->availableFrom() ) {
970 return false;
971 }
972 emit executeCommand( new ModifyResourceAvailableFromCmd( res, value.toDateTime(), kundo2_i18n( "Modify resource available from" ) ) );
973 return true;
974 }
975 return false;
976}
977
978bool ResourceItemModel::setAvailableUntil( Resource *res, const QVariant &value, int role )
979{
980 switch ( role ) {
981 case Qt::EditRole:
982 if ( value.toDateTime() == res->availableUntil() ) {
983 return false;
984 }
985 emit executeCommand( new ModifyResourceAvailableUntilCmd( res, value.toDateTime(), kundo2_i18n( "Modify resource available until" ) ) );
986 return true;
987 }
988 return false;
989}
990
991bool ResourceItemModel::setNormalRate( Resource *res, const QVariant &value, int role )
992{
993 switch ( role ) {
994 case Qt::EditRole:
995 if ( value.toDouble() == res->normalRate() ) {
996 return false;
997 }
998 emit executeCommand( new ModifyResourceNormalRateCmd( res, value.toDouble(), kundo2_i18n( "Modify resource normal rate" ) ) );
999 return true;
1000 }
1001 return false;
1002}
1003
1004bool ResourceItemModel::setOvertimeRate( Resource *res, const QVariant &value, int role )
1005{
1006 switch ( role ) {
1007 case Qt::EditRole:
1008 if ( value.toDouble() == res->overtimeRate() ) {
1009 return false;
1010 }
1011 emit executeCommand( new ModifyResourceOvertimeRateCmd( res, value.toDouble(), kundo2_i18n( "Modify resource overtime rate" ) ) );
1012 return true;
1013 }
1014 return false;
1015}
1016
1017bool ResourceItemModel::setAccount( Resource *res, const QVariant &value, int role )
1018{
1019 switch ( role ) {
1020 case Qt::EditRole: {
1021 Account *a = 0;
1022 if ( value.type() == QVariant::Int ) {
1023 QStringList lst = m_model.account( res, Role::EnumList ).toStringList();
1024 if ( value.toInt() >= lst.count() ) {
1025 return false;
1026 }
1027 a = m_project->accounts().findAccount( lst.at( value.toInt() ) );
1028 } else if ( value.type() == QVariant::String ) {
1029 a = m_project->accounts().findAccount( value.toString() );
1030 }
1031 Account *old = res->account();
1032 if ( old != a ) {
1033 emit executeCommand( new ResourceModifyAccountCmd( *res, old, a, kundo2_i18n( "Modify resource account" ) ) );
1034 return true;
1035 }
1036 }
1037 default:
1038 break;
1039 }
1040 return false;
1041}
1042
1043QVariant ResourceItemModel::notUsed( const ResourceGroup *, int role ) const
1044{
1045 switch ( role ) {
1046 case Qt::DisplayRole:
1047 return QString(" ");
1048 case Qt::TextAlignmentRole:
1049 return Qt::AlignCenter;
1050 case Qt::EditRole:
1051 case Qt::ToolTipRole:
1052 case Qt::StatusTipRole:
1053 case Qt::WhatsThisRole:
1054 return QVariant();
1055 }
1056 return QVariant();
1057}
1058
1059QVariant ResourceItemModel::data( const QModelIndex &index, int role ) const
1060{
1061 QVariant result;
1062 QObject *obj = object( index );
1063 if ( obj == 0 ) {
1064 return QVariant();
1065 }
1066 if ( role == Qt::TextAlignmentRole ) {
1067 // use same alignment as in header (headers always horizontal)
1068 return headerData( index.column(), Qt::Horizontal, role );
1069 }
1070 Resource *r = qobject_cast<Resource*>( obj );
1071 if ( r ) {
1072 result = m_model.data( r, index.column(), role );
1073 } else {
1074 ResourceGroup *g = qobject_cast<ResourceGroup*>( obj );
1075 if ( g ) {
1076 result = m_model.data( g, index.column(), role );
1077 }
1078 }
1079 return result;
1080}
1081
1082bool ResourceItemModel::setData( const QModelIndex &index, const QVariant &value, int role )
1083{
1084 if ( ! index.isValid() ) {
1085 return ItemModelBase::setData( index, value, role );
1086 }
1087 if ( ( flags( index ) &Qt::ItemIsEditable ) == 0 || ! ( role == Qt::EditRole || role == Qt::CheckStateRole ) ) {
1088 return false;
1089 }
1090 QObject *obj = object( index );
1091 Resource *r = qobject_cast<Resource*>( obj );
1092 if ( r ) {
1093 switch (index.column()) {
1094 case ResourceModel::ResourceName: return setName( r, value, role );
1095 case ResourceModel::ResourceType: return setType( r, value, role );
1096 case ResourceModel::ResourceInitials: return setInitials( r, value, role );
1097 case ResourceModel::ResourceEmail: return setEmail( r, value, role );
1098 case ResourceModel::ResourceCalendar: return setCalendar( r, value, role );
1099 case ResourceModel::ResourceLimit: return setUnits( r, value, role );
1100 case ResourceModel::ResourceAvailableFrom: return setAvailableFrom( r, value, role );
1101 case ResourceModel::ResourceAvailableUntil: return setAvailableUntil( r, value, role );
1102 case ResourceModel::ResourceNormalRate: return setNormalRate( r, value, role );
1103 case ResourceModel::ResourceOvertimeRate: return setOvertimeRate( r, value, role );
1104 case ResourceModel::ResourceAccount: return setAccount( r, value, role );
1105 default:
1106 qWarning("data: invalid display value column %d", index.column());
1107 return false;
1108 }
1109 } else {
1110 ResourceGroup *g = qobject_cast<ResourceGroup*>( obj );
1111 if ( g ) {
1112 switch (index.column()) {
1113 case ResourceModel::ResourceName: return setName( g, value, role );
1114 case ResourceModel::ResourceType: return setType( g, value, role );
1115 default:
1116 qWarning("data: invalid display value column %d", index.column());
1117 return false;
1118 }
1119 }
1120 }
1121 return false;
1122}
1123
1124QVariant ResourceItemModel::headerData( int section, Qt::Orientation orientation, int role ) const
1125{
1126 if ( orientation == Qt::Horizontal ) {
1127 if ( role == Qt::DisplayRole || role == Qt::TextAlignmentRole ) {
1128 return m_model.headerData( section, role );
1129 }
1130 }
1131 if ( role == Qt::ToolTipRole ) {
1132 return m_model.headerData( section, role );
1133 }
1134 return ItemModelBase::headerData(section, orientation, role);
1135}
1136
1137QAbstractItemDelegate *ResourceItemModel::createDelegate( int col, QWidget *parent ) const
1138{
1139 switch ( col ) {
1140 case ResourceModel::ResourceType: return new EnumDelegate( parent );
1141 case ResourceModel::ResourceCalendar: return new EnumDelegate( parent );
1142 case ResourceModel::ResourceAvailableFrom: return new DateTimeCalendarDelegate( parent );
1143 case ResourceModel::ResourceAvailableUntil: return new DateTimeCalendarDelegate( parent );
1144 case ResourceModel::ResourceAccount: return new EnumDelegate( parent );
1145 default: break;
1146 }
1147 return 0;
1148}
1149
1150QObject *ResourceItemModel::object( const QModelIndex &index ) const
1151{
1152 QObject *o = 0;
1153 if ( index.isValid() ) {
1154 o = static_cast<QObject*>( index.internalPointer() );
1155 Q_ASSERT( o );
1156 }
1157 return o;
1158}
1159
1160ResourceGroup *ResourceItemModel::group( const QModelIndex &index ) const
1161{
1162 return qobject_cast<ResourceGroup*>( object( index ) );
1163}
1164
1165Resource *ResourceItemModel::resource( const QModelIndex &index ) const
1166{
1167 return qobject_cast<Resource*>( object( index ) );
1168}
1169
1170void ResourceItemModel::slotCalendarChanged( Calendar* )
1171{
1172 foreach ( Resource *r, m_project->resourceList() ) {
1173 if ( r->calendar( true ) == 0 ) {
1174 slotResourceChanged( r );
1175 }
1176 }
1177}
1178
1179void ResourceItemModel::slotResourceChanged( Resource *res )
1180{
1181 ResourceGroup *g = res->parentGroup();
1182 if ( g ) {
1183 int row = g->indexOf( res );
1184 emit dataChanged( createIndex( row, 0, res ), createIndex( row, columnCount() - 1, res ) );
1185 return;
1186 }
1187}
1188
1189void ResourceItemModel::slotResourceGroupChanged( ResourceGroup *res )
1190{
1191 Project *p = res->project();
1192 if ( p ) {
1193 int row = p->resourceGroups().indexOf( res );
1194 emit dataChanged( createIndex( row, 0, res ), createIndex( row, columnCount() - 1, res ) );
1195 }
1196}
1197
1198Qt::DropActions ResourceItemModel::supportedDropActions() const
1199{
1200 return Qt::MoveAction | Qt::CopyAction;
1201}
1202
1203bool ResourceItemModel::dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data )
1204{
1205 Q_UNUSED(data);
1206
1207 //kDebug(planDbg())<<index<<data;
1208 // TODO: if internal, don't allow dropping on my own parent
1209 switch ( dropIndicatorPosition ) {
1210 case ItemModelBase::OnItem:
1211 return qobject_cast<ResourceGroup*>( object( index ) ); // Allow only on group
1212 default:
1213 break;
1214 }
1215 return false;
1216}
1217
1218QStringList ResourceItemModel::mimeTypes() const
1219{
1220 return QStringList()
1221#ifdef PLAN_KDEPIMLIBS_FOUND
1222 << "text/x-vcard"
1223 << "text/directory"
1224 << "text/uri-list"
1225#endif
1226 << "application/x-vnd.kde.plan.resourceitemmodel.internal";
1227}
1228
1229void ResourceItemModel::slotDataArrived( KIO::Job *job, const QByteArray &data )
1230{
1231 if ( m_dropDataMap.contains( job ) ) {
1232 m_dropDataMap[ job ].data += data;
1233 }
1234}
1235
1236void ResourceItemModel::slotJobFinished( KJob *job )
1237{
1238 if ( job->error() || ! m_dropDataMap.contains( job ) ) {
1239 kDebug(planDbg())<<(job->error() ? "Job error":"Error: no such job");
1240 } else if ( KMimeType::findByContent( m_dropDataMap[ job ].data )->is( "text/x-vcard" ) ) {
1241 ResourceGroup *g = 0;
1242 if ( m_dropDataMap[ job ].parent.isValid() ) {
1243 g = qobject_cast<ResourceGroup*>( object( m_dropDataMap[ job ].parent ) );
1244 } else {
1245 g = qobject_cast<ResourceGroup*>( object( index( m_dropDataMap[ job ].row, m_dropDataMap[ job ].column, m_dropDataMap[ job ].parent ) ) );
1246 }
1247 if ( g == 0 ) {
1248 kDebug(planDbg())<<"No group"<<m_dropDataMap[ job ].row<<m_dropDataMap[ job ].column<<m_dropDataMap[ job ].parent;
1249 } else {
1250 createResources( g, m_dropDataMap[ job ].data );
1251 }
1252 }
1253 if ( m_dropDataMap.contains( job ) ) {
1254 m_dropDataMap.remove( job );
1255 }
1256 disconnect(job, SIGNAL(result(KJob*)), this, SLOT(slotJobFinished(KJob*)));
1257 disconnect(job, SIGNAL(data(KIO::Job*,QByteArray)), this, SLOT(slotDataArrived(KIO::Job*,QByteArray)));
1258}
1259
1260bool ResourceItemModel::createResources( ResourceGroup *group, const QByteArray &data )
1261{
1262#ifdef PLAN_KDEPIMLIBS_FOUND
1263 KABC::VCardConverter vc;
1264 KABC::Addressee::List lst = vc.parseVCards( data );
1265 MacroCommand *m = new MacroCommand( kundo2_i18np( "Add resource from address book", "Add %1 resources from address book", lst.count() ) );
1266 foreach( const KABC::Addressee &a, lst ) {
1267 Resource *r = new Resource();
1268 QString uid = a.uid();
1269 if ( ! m_project->findResource( uid ) ) {
1270 r->setId( uid );
1271 }
1272 r->setName( a.formattedName() );
1273 r->setEmail( a.preferredEmail() );
1274 m->addCommand( new AddResourceCmd( group, r ) );
1275 }
1276 if ( m->isEmpty() ) {
1277 delete m;
1278 return false;
1279 }
1280 emit executeCommand( m );
1281 return true;
1282#else
1283 return false;
1284#endif
1285}
1286
1287bool ResourceItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
1288{
1289 kDebug(planDbg())<<row<<column<<parent;
1290 if (action == Qt::IgnoreAction) {
1291 return true;
1292 }
1293 if (column > 0) {
1294 return false;
1295 }
1296 ResourceGroup *g = 0;
1297 if ( parent.isValid() ) {
1298 g = qobject_cast<ResourceGroup*>( object( parent ) );
1299 } else {
1300 g = qobject_cast<ResourceGroup*>( object( index( row, column, parent ) ) );
1301 }
1302 if ( g == 0 ) {
1303 kDebug(planDbg())<<"No group"<<row<<column<<parent;
1304 return false;
1305 }
1306 kDebug(planDbg())<<data->formats()<<g->name();
1307 if ( data->hasFormat( "application/x-vnd.kde.plan.resourceitemmodel.internal" ) ) {
1308 kDebug(planDbg())<<action<<Qt::MoveAction;
1309 if ( action == Qt::MoveAction ) {
1310 MacroCommand *m = 0;
1311 QByteArray encodedData = data->data( "application/x-vnd.kde.plan.resourceitemmodel.internal" );
1312 QDataStream stream(&encodedData, QIODevice::ReadOnly);
1313 int i = 0;
1314 foreach ( Resource *r, resourceList( stream ) ) {
1315 if ( r->parentGroup() == g ) {
1316 continue;
1317 }
1318 if ( m == 0 ) m = new MacroCommand( KUndo2MagicString() );
1319 m->addCommand( new MoveResourceCmd( g, r ) );
1320 ++i;
1321 }
1322 if ( m ) {
1323 KUndo2MagicString msg = kundo2_i18np( "Move resource", "Move %1 resources", i );
1324 MacroCommand *c = new MacroCommand( msg );
1325 c->addCommand( m );
1326 emit executeCommand( c );
1327 }
1328 return true;
1329 }
1330 if ( action == Qt::CopyAction ) {
1331 MacroCommand *m = 0;
1332 QByteArray encodedData = data->data( "application/x-vnd.kde.plan.resourceitemmodel.internal" );
1333 QDataStream stream(&encodedData, QIODevice::ReadOnly);
1334 int i = 0;
1335 foreach ( Resource *r, resourceList( stream ) ) {
1336 Resource *nr = new Resource( r );
1337 if ( m == 0 ) m = new MacroCommand( KUndo2MagicString() );
1338 m->addCommand( new AddResourceCmd( g, nr ) );
1339 ++i;
1340 }
1341 if ( m ) {
1342 KUndo2MagicString msg = kundo2_i18np( "Copy resource", "Copy %1 resources", i );
1343 MacroCommand *c = new MacroCommand( msg );
1344 c->addCommand( m );
1345 emit executeCommand( c );
1346 }
1347 return true;
1348 }
1349 return true;
1350 }
1351 if ( data->hasFormat( "text/x-vcard" ) || data->hasFormat( "text/directory" ) ) {
1352 if ( action != Qt::CopyAction ) {
1353 return false;
1354 }
1355 QString f = data->hasFormat( "text/x-vcard" ) ? "text/x-vcard" : "text/directory";
1356 return createResources( g, data->data( f ) );
1357 }
1358 if ( data->hasFormat( "text/uri-list" ) ) {
1359 const KUrl::List urls = KUrl::List::fromMimeData( data );
1360 if ( urls.isEmpty() ) {
1361 return false;
1362 }
1363 bool result = false;
1364 foreach ( const KUrl &url, urls ) {
1365 if ( url.protocol() != "akonadi" || ! KIO::NetAccess::exists( url, KIO::NetAccess::SourceSide, 0 ) ) {
1366 kDebug(planDbg())<<url<<"is not 'akonadi' or does not exist";
1367 continue;
1368 }
1369 KIO::TransferJob *job = KIO::get( url, KIO::NoReload, KIO::HideProgressInfo );
1370 bool res = connect(job, SIGNAL(data(KIO::Job*,QByteArray)), this, SLOT(slotDataArrived(KIO::Job*,QByteArray)));
1371 Q_ASSERT( res );
1372 Q_UNUSED( res );
1373 res = connect(job, SIGNAL(result(KJob*)), this, SLOT(slotJobFinished(KJob*)));
1374 Q_ASSERT( res );
1375
1376 m_dropDataMap[ job ].action = action;
1377 m_dropDataMap[ job ].row = row;
1378 m_dropDataMap[ job ].column = column;
1379 m_dropDataMap[ job ].parent = parent;
1380
1381 job->start();
1382 result = true;
1383 }
1384 return result;
1385 }
1386 return false;
1387}
1388
1389QList<Resource*> ResourceItemModel::resourceList( QDataStream &stream )
1390{
1391 QList<Resource*> lst;
1392 while (!stream.atEnd()) {
1393 QString id;
1394 stream >> id;
1395 Resource *r = m_project->findResource( id );
1396 if ( r ) {
1397 lst << r;
1398 }
1399 }
1400 kDebug(planDbg())<<lst;
1401 return lst;
1402}
1403
1404QMimeData *ResourceItemModel::mimeData( const QModelIndexList & indexes ) const
1405{
1406 QMimeData *m = new QMimeData();
1407 QByteArray encodedData;
1408 QDataStream stream(&encodedData, QIODevice::WriteOnly);
1409 QList<int> rows;
1410 foreach (const QModelIndex &index, indexes) {
1411 if ( index.isValid() && !rows.contains( index.row() ) ) {
1412 //kDebug(planDbg())<<index.row();
1413 Resource *r = ::qobject_cast<Resource*>( object( index ) );
1414 if ( r ) {
1415 rows << index.row();
1416 stream << r->id();
1417 } else if ( ::qobject_cast<ResourceGroup*>( object( index ) ) ) {
1418 rows.clear();
1419 break;
1420 }
1421 }
1422 }
1423 if ( rows.isEmpty() ) {
1424 delete m;
1425 return 0;
1426 }
1427 m->setData("application/x-vnd.kde.plan.resourceitemmodel.internal", encodedData);
1428 return m;
1429}
1430
1431QModelIndex ResourceItemModel::insertGroup( ResourceGroup *g )
1432{
1433 //kDebug(planDbg());
1434 emit executeCommand( new AddResourceGroupCmd( m_project, g, kundo2_i18n( "Add resource group" ) ) );
1435 int row = m_project->resourceGroups().indexOf( g );
1436 if ( row != -1 ) {
1437 return createIndex( row, 0, g );
1438 }
1439 return QModelIndex();
1440}
1441
1442QModelIndex ResourceItemModel::insertResource( ResourceGroup *g, Resource *r, Resource * /*after*/ )
1443{
1444 //kDebug(planDbg());
1445 emit executeCommand( new AddResourceCmd( g, r, kundo2_i18n( "Add resource" ) ) );
1446 int row = g->indexOf( r );
1447 if ( row != -1 ) {
1448 return createIndex( row, 0, r );
1449 }
1450 return QModelIndex();
1451}
1452
1453int ResourceItemModel::sortRole( int column ) const
1454{
1455 switch ( column ) {
1456 case ResourceModel::ResourceAvailableFrom:
1457 case ResourceModel::ResourceAvailableUntil:
1458 return Qt::EditRole;
1459 default:
1460 break;
1461 }
1462 return Qt::DisplayRole;
1463}
1464
1465
1466//-------------------
1467ResourceItemSFModel::ResourceItemSFModel( QObject *parent )
1468 : QSortFilterProxyModel( parent )
1469{
1470 setDynamicSortFilter( true );
1471 setSourceModel( new ResourceItemModel( this ) );
1472}
1473
1474void ResourceItemSFModel::setProject( Project *project )
1475{
1476 static_cast<ResourceItemModel*>( sourceModel() )->setProject( project );
1477}
1478
1479Resource *ResourceItemSFModel::resource( const QModelIndex &idx ) const
1480{
1481 return static_cast<ResourceItemModel*>( sourceModel() )->resource( mapToSource( idx ) );
1482}
1483
1484QModelIndex ResourceItemSFModel::index( Resource *r ) const
1485{
1486 return mapFromSource( static_cast<ResourceItemModel*>( sourceModel() )->index( r ) );
1487}
1488
1489Qt::ItemFlags ResourceItemSFModel::flags( const QModelIndex & index ) const
1490{
1491 Qt::ItemFlags f = QSortFilterProxyModel::flags( index );
1492 if ( index.isValid() && ! parent( index ).isValid() ) {
1493 // group, not selectable
1494 f &= ~Qt::ItemIsSelectable;
1495 }
1496 return f;
1497}
1498
1499void ResourceItemSFModel::addFilteredResource( const Resource *r )
1500{
1501 if ( ! m_filteredResources.contains( r ) ) {
1502 m_filteredResources << r;
1503 }
1504}
1505
1506bool ResourceItemSFModel::filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const
1507{
1508 //TODO make this general filter
1509 ResourceItemModel *m = static_cast<ResourceItemModel*>( sourceModel() );
1510 if ( m->index( source_row, ResourceModel::ResourceType, source_parent ).data( Role::EnumListValue ).toInt() == ResourceGroup::Type_Work ) {
1511 return false;
1512 }
1513 QModelIndex idx = m->index( source_row, 0, source_parent );
1514 return ! m_filteredResources.contains( m->resource( idx ) );
1515}
1516
1517//-----------------------
1518AllocatedResourceItemModel::AllocatedResourceItemModel( QObject *parent )
1519 : QSortFilterProxyModel( parent ),
1520 m_task( 0 )
1521{
1522 setDynamicSortFilter( true );
1523 setSourceModel( new ResourceItemModel( this ) );
1524}
1525
1526int AllocatedResourceItemModel::columnCount( const QModelIndex &idx ) const
1527{
1528 Q_UNUSED(idx);
1529 return 2;
1530}
1531
1532Project *AllocatedResourceItemModel::project() const
1533{
1534 return static_cast<ResourceItemModel*>( sourceModel() )->project();
1535}
1536
1537void AllocatedResourceItemModel::setProject( Project *project )
1538{
1539 kDebug(planDbg())<<this->project()<<"="<<project;
1540 Project *p =this->project();
1541 if ( p ) {
1542 disconnect(p, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)));
1543 }
1544 static_cast<ResourceItemModel*>( sourceModel() )->setProject( project );
1545 if ( project ) {
1546 connect(project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)));
1547 }
1548 kDebug(planDbg())<<rowCount()<<":"<<sourceModel()->rowCount();
1549}
1550
1551void AllocatedResourceItemModel::reset()
1552{
1553 QSortFilterProxyModel::reset();
1554 emit expandAll();
1555 emit resizeColumnToContents( 0 );
1556}
1557
1558void AllocatedResourceItemModel::slotNodeChanged( Node *n )
1559{
1560 kDebug(planDbg())<<(n==m_task)<<n<<n->name();
1561 if ( n != m_task ) {
1562 return;
1563 }
1564 reset();
1565}
1566
1567Task *AllocatedResourceItemModel::task() const
1568{
1569 return m_task;
1570}
1571
1572void AllocatedResourceItemModel::setTask( Task *task )
1573{
1574 kDebug(planDbg())<<m_task<<"="<<task<<(task?task->name():"");
1575 m_task = task;
1576 reset();
1577 kDebug(planDbg())<<rowCount()<<":"<<sourceModel()->rowCount();
1578}
1579
1580QObject* AllocatedResourceItemModel::object(const QModelIndex& idx) const
1581{
1582 return static_cast<ResourceItemModel*>( sourceModel() )->object( mapToSource( idx ) );
1583}
1584
1585Resource *AllocatedResourceItemModel::resource( const QModelIndex &idx ) const
1586{
1587 return qobject_cast<Resource*>( object( idx ) );
1588}
1589
1590QModelIndex AllocatedResourceItemModel::index( Resource *r ) const
1591{
1592 return mapFromSource( static_cast<ResourceItemModel*>( sourceModel() )->index( r ) );
1593}
1594
1595Qt::ItemFlags AllocatedResourceItemModel::flags( const QModelIndex & index ) const
1596{
1597 Qt::ItemFlags f = QSortFilterProxyModel::flags( index );
1598 f &= ~Qt::ItemIsUserCheckable;
1599 return f;
1600}
1601
1602QVariant AllocatedResourceItemModel::headerData(int section, Qt::Orientation orientation, int role) const
1603{
1604 if ( section == 1 ) {
1605 if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) {
1606 return i18nc( "@title:column", "Allocation" );
1607 }
1608 return QVariant();
1609 }
1610 return QSortFilterProxyModel::headerData( section, orientation, role );
1611}
1612
1613QVariant AllocatedResourceItemModel::allocation( const Resource *res, int role ) const
1614{
1615 ResourceRequest *rr = m_task->requests().find( res );
1616 ResourceGroupRequest *gr = m_task->requests().find( res->parentGroup() );
1617 if ( rr == 0 || gr == 0 ) {
1618 return QVariant();
1619 }
1620 switch ( role ) {
1621 case Qt::DisplayRole: {
1622 case Qt::EditRole:
1623 // xgettext: no-c-format
1624 return i18nc( "<value>%", "%1%",rr->units() );
1625 }
1626 case Qt::ToolTipRole: {
1627 if ( rr->units() == 0 ) {
1628 return i18nc( "@info:tooltip", "Not allocated" );
1629 }
1630 return i18nc( "@info:tooltip", "%1 allocated out of %2 available", gr->count(), res->parentGroup()->numResources() );
1631 }
1632 default:
1633 break;
1634 }
1635 return QVariant();
1636}
1637
1638QVariant AllocatedResourceItemModel::allocation( const ResourceGroup *res, int role ) const
1639{
1640 ResourceGroupRequest *gr = m_task->requests().find( res );
1641 if ( gr == 0 ) {
1642 return QVariant();
1643 }
1644 switch ( role ) {
1645 case Qt::DisplayRole:
1646 case Qt::EditRole:
1647 return QString( "%1 (%2)" ).arg( gr->units() ).arg( gr->count() );
1648 case Qt::ToolTipRole: {
1649 QString s1 = i18ncp( "@info:tooltip",
1650 "%1 resource requested for dynamic allocation",
1651 "%1 resources requested for dynamic allocation",
1652 gr->units() );
1653 QString s2 = i18ncp( "@info:tooltip",
1654 "%1 resource allocated",
1655 "%1 resources allocated",
1656 gr->count() );
1657
1658 return i18nc( "@info:tooltip", "%1<nl/>%2", s1, s2 );
1659 }
1660 case Qt::WhatsThisRole: {
1661 return i18nc( "@info:whatsthis",
1662 "<title>Group allocations</title>"
1663 "<para>You can allocate a number of resources from a group and let"
1664 " the scheduler select from the available resources at the time of scheduling.</para>"
1665 " These dynamically allocated resources will be in addition to any resource you have allocated specifically." );
1666 }
1667 case Role::Minimum: {
1668 return 0;
1669 }
1670 case Role::Maximum: {
1671 return res->numResources() - gr->units();
1672 }
1673 default:
1674 break;
1675 }
1676 return QVariant();
1677}
1678
1679QVariant AllocatedResourceItemModel::data(const QModelIndex& idx, int role) const
1680{
1681 if ( m_task == 0 || role == Qt::CheckStateRole || role == Qt::DecorationRole ) {
1682 return QVariant();
1683 }
1684 if ( idx.column() == 1 ) {
1685 switch ( role ) {
1686 case Qt::TextAlignmentRole:
1687 return Qt::AlignLeft;
1688 default: {
1689 QObject *o = object( idx );
1690 Resource *r = qobject_cast<Resource*>( o );
1691 if ( r ) {
1692 return allocation( r, role );
1693 }
1694 ResourceGroup *g = qobject_cast<ResourceGroup*>( o );
1695 if ( g ) {
1696 return allocation( g, role );
1697 }
1698 break;
1699 }
1700 return QVariant();
1701 }
1702 }
1703 return QSortFilterProxyModel::data( idx, role );
1704}
1705
1706bool AllocatedResourceItemModel::filterAcceptsRow( int source_row, const QModelIndex & source_parent ) const
1707{
1708 if ( m_task == 0 ) {
1709 return false;
1710 }
1711 QModelIndex idx = sourceModel()->index( source_row, 0, source_parent );
1712 if ( ! idx.isValid() ) {
1713 return false;
1714 }
1715 bool result = false;
1716 const ResourceRequestCollection &req = m_task->requests();
1717 if ( source_parent.isValid() ) {
1718 const Resource *r = static_cast<ResourceItemModel*>( sourceModel() )->resource( idx );
1719 result = (bool) req.find( r );
1720 } else {
1721 const ResourceGroup *g = static_cast<ResourceItemModel*>( sourceModel() )->group( idx );
1722 ResourceGroupRequest *gr = req.find( g );
1723 result = (bool) gr && ( gr->units() > 0 || gr->count() > 0 );
1724 }
1725 kDebug(planDbg())<<result<<":"<<source_parent<<idx;
1726 return result;
1727}
1728
1729} // namespace KPlato
1730
1731#include "kptresourcemodel.moc"
1732