1/* This file is part of the KDE project
2 Copyright (C) 2007 - 2009, 2012 Dag Andersen <danders@get2net.dk>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17* Boston, MA 02110-1301, USA.
18*/
19
20#include "kptnodeitemmodel.h"
21
22#include "kptglobal.h"
23#include "kptcommonstrings.h"
24#include "kptcommand.h"
25#include "kptduration.h"
26#include "kptproject.h"
27#include "kptnode.h"
28#include "kpttaskcompletedelegate.h"
29#include "kptxmlloaderobject.h"
30#include "kptdebug.h"
31
32#include "KoStore.h"
33#include <KoIcon.h>
34
35#include <QAbstractItemModel>
36#include <QMimeData>
37#include <QModelIndex>
38#include <QWidget>
39#include <QPair>
40#include <QByteArray>
41
42#include <kaction.h>
43#include <kglobal.h>
44#include <klocale.h>
45#include <ktoggleaction.h>
46#include <kactionmenu.h>
47#include <kstandardaction.h>
48#include <kstandardshortcut.h>
49#include <kaccelgen.h>
50#include <kactioncollection.h>
51#include <krichtextwidget.h>
52#include <kmimetype.h>
53
54#include <kdganttglobal.h>
55#include <math.h>
56
57
58namespace KPlato
59{
60
61
62//--------------------------------------
63NodeModel::NodeModel()
64 : QObject(),
65 m_project( 0 ),
66 m_manager( 0 ),
67 m_now( QDate::currentDate() ),
68 m_prec( 1 )
69{
70}
71
72const QMetaEnum NodeModel::columnMap() const
73{
74 return metaObject()->enumerator( metaObject()->indexOfEnumerator("Properties") );
75}
76
77void NodeModel::setProject( Project *project )
78{
79 kDebug(planDbg())<<m_project<<"->"<<project;
80 m_project = project;
81}
82
83void NodeModel::setManager( ScheduleManager *sm )
84{
85 kDebug(planDbg())<<m_manager<<"->"<<sm;
86 m_manager = sm;
87}
88
89QVariant NodeModel::name( const Node *node, int role ) const
90{
91 switch ( role ) {
92 case Qt::DisplayRole:
93 case Qt::EditRole:
94 case Qt::ToolTipRole:
95 return node->name();
96 case Qt::StatusTipRole:
97 case Qt::WhatsThisRole:
98 return QVariant();
99 case Qt::DecorationRole:
100 if ( node->isBaselined() ) {
101 return koIcon("view-time-schedule-baselined");
102 }
103 break;
104 case Role::Foreground: {
105 if ( ! m_project ) {
106 break;
107 }
108 switch ( node->type() ) {
109 case Node::Type_Task:
110 return static_cast<const Task*>( node )->completion().isFinished() ? m_project->config().taskFinishedColor() : m_project->config().taskNormalColor();
111 case Node::Type_Milestone:
112 return static_cast<const Task*>( node )->completion().isFinished() ? m_project->config().milestoneFinishedColor() : m_project->config().milestoneNormalColor();
113 case Node::Type_Summarytask:
114 return m_project->config().summaryTaskLevelColor( node->level() );
115 default:
116 break;
117 }
118 break;
119 }
120 }
121 return QVariant();
122}
123
124QVariant NodeModel::leader( const Node *node, int role ) const
125{
126 switch ( role ) {
127 case Qt::DisplayRole:
128 case Qt::EditRole:
129 case Qt::ToolTipRole:
130 return node->leader();
131 case Qt::StatusTipRole:
132 case Qt::WhatsThisRole:
133 return QVariant();
134 }
135 return QVariant();
136}
137
138QVariant NodeModel::allocation( const Node *node, int role ) const
139{
140 if ( node->type() == Node::Type_Task ) {
141 switch ( role ) {
142 case Qt::DisplayRole:
143 case Qt::EditRole:
144 return node->requests().requestNameList().join( "," );
145 case Qt::ToolTipRole: {
146 QMap<QString, QStringList> lst;
147 foreach ( ResourceRequest *rr, node->requests().resourceRequests( false ) ) {
148 QStringList sl;
149 foreach( Resource *r, rr->requiredResources() ) {
150 sl << r->name();
151 }
152 lst.insert( rr->resource()->name(), sl );
153 }
154 if ( lst.isEmpty() ) {
155 return i18nc( "@info:tooltip", "No resources has been allocated" );
156 }
157 QStringList sl;
158 for ( QMap<QString, QStringList>::ConstIterator it = lst.constBegin(); it != lst.constEnd(); ++it ) {
159 if ( it.value().isEmpty() ) {
160 sl << it.key();
161 } else {
162 sl << i18nc( "@info:tooltip 1=resource name, 2=list of requiered resources", "%1 (%2)", it.key(), it.value().join(", ") );
163 }
164 }
165 if ( sl.count() == 1 ) {
166 return i18nc( "@info:tooltip 1=resource name", "Allocated resource:<nl/>%1", sl.first() );
167 }
168 return i18nc( "@info:tooltip 1=list of resources", "Allocated resources:<nl/>%1", sl.join( "<nl/>" ) );
169 }
170 case Qt::StatusTipRole:
171 case Qt::WhatsThisRole:
172 return QVariant();
173 }
174 }
175 return QVariant();
176}
177
178QVariant NodeModel::description( const Node *node, int role ) const
179{
180 switch ( role ) {
181 case Qt::DisplayRole: {
182 KRichTextWidget w( node->description(), 0 );
183 w.switchToPlainText();
184 QString s = w.textOrHtml();
185 int i = s.indexOf( '\n' );
186 s = s.left( i );
187 if ( i > 0 ) {
188 s += "...";
189 }
190 return s;
191 }
192 case Qt::ToolTipRole: {
193 KRichTextWidget w( node->description(), 0 );
194 w.switchToPlainText();
195 if ( w.textOrHtml().isEmpty() ) {
196 return QVariant();
197 }
198 return node->description();
199 }
200 case Qt::EditRole:
201 return node->description();
202 case Qt::StatusTipRole:
203 case Qt::WhatsThisRole:
204 return QVariant();
205 }
206 return QVariant();
207}
208
209QVariant NodeModel::type( const Node *node, int role ) const
210{
211 //kDebug(planDbg())<<node->name()<<", "<<role;
212 switch ( role ) {
213 case Qt::DisplayRole:
214 case Qt::ToolTipRole:
215 return node->typeToString( true );
216 case Qt::EditRole:
217 return node->type();
218 case Qt::TextAlignmentRole:
219 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
220 case Qt::StatusTipRole:
221 case Qt::WhatsThisRole:
222 return QVariant();
223 }
224 return QVariant();
225}
226
227QVariant NodeModel::constraint( const Node *node, int role ) const
228{
229 if ( node->type() == Node::Type_Project ) {
230 switch ( role ) {
231 case Qt::DisplayRole:
232 return i18n( "Target times" );
233 case Qt::ToolTipRole:
234 return i18nc( "@info:tooltip", "Earliest start and latest finish" );
235 case Role::EnumList:
236 case Qt::EditRole:
237 case Role::EnumListValue:
238 return QVariant();
239 case Qt::TextAlignmentRole:
240 return Qt::AlignCenter;
241 case Qt::StatusTipRole:
242 case Qt::WhatsThisRole:
243 return QVariant();
244 }
245 } else if ( node->type() != Node::Type_Summarytask ) {
246 switch ( role ) {
247 case Qt::DisplayRole:
248 case Qt::ToolTipRole:
249 return node->constraintToString( true );
250 case Role::EnumList:
251 return Node::constraintList( true );
252 case Qt::EditRole:
253 return node->constraint();
254 case Role::EnumListValue:
255 return (int)node->constraint();
256 case Qt::TextAlignmentRole:
257 return Qt::AlignCenter;
258 case Qt::StatusTipRole:
259 case Qt::WhatsThisRole:
260 return QVariant();
261 }
262 }
263 return QVariant();
264}
265
266QVariant NodeModel::constraintStartTime( const Node *node, int role ) const
267{
268 if ( node->type() == Node::Type_Project ) {
269 switch ( role ) {
270 case Qt::DisplayRole: {
271 return KGlobal::locale()->formatDateTime( node->constraintStartTime() );
272 }
273 case Qt::ToolTipRole: {
274 return KGlobal::locale()->formatDateTime( node->constraintStartTime(), KLocale::LongDate, KLocale::TimeZone );
275 }
276 case Qt::EditRole:
277 return node->constraintStartTime();
278 case Qt::StatusTipRole:
279 case Qt::WhatsThisRole:
280 return QVariant();
281 }
282 return QVariant();
283 } else if ( node->type() != Node::Type_Summarytask ) {
284 switch ( role ) {
285 case Qt::DisplayRole: {
286 QString s = KGlobal::locale()->formatDateTime( node->constraintStartTime() );
287 switch ( node->constraint() ) {
288 case Node::StartNotEarlier:
289 case Node::MustStartOn:
290 case Node::FixedInterval:
291 return s;
292 default:
293 break;
294 }
295 return QString( "(%1)" ).arg( s );
296 }
297 case Qt::ToolTipRole: {
298 int c = node->constraint();
299 if ( c == Node::MustStartOn || c == Node::StartNotEarlier || c == Node::FixedInterval ) {
300 return KGlobal::locale()->formatDateTime( node->constraintStartTime(), KLocale::LongDate, KLocale::TimeZone );
301 }
302 break;
303 }
304 case Qt::EditRole:
305 return node->constraintStartTime();
306 case Qt::StatusTipRole:
307 case Qt::WhatsThisRole:
308 return QVariant();
309 }
310 }
311 return QVariant();
312}
313
314QVariant NodeModel::constraintEndTime( const Node *node, int role ) const
315{
316 if ( node->type() == Node::Type_Project ) {
317 switch ( role ) {
318 case Qt::DisplayRole: {
319 return KGlobal::locale()->formatDateTime( node->constraintEndTime() );
320 }
321 case Qt::ToolTipRole: {
322 return KGlobal::locale()->formatDateTime( node->constraintEndTime(), KLocale::LongDate, KLocale::TimeZone );
323 }
324 case Qt::EditRole:
325 return node->constraintEndTime();
326 case Qt::StatusTipRole:
327 case Qt::WhatsThisRole:
328 return QVariant();
329 }
330 return QVariant();
331 } else if ( node->type() != Node::Type_Summarytask ) {
332 switch ( role ) {
333 case Qt::DisplayRole: {
334 QString s = KGlobal::locale()->formatDateTime( node->constraintEndTime() );
335 switch ( node->constraint() ) {
336 case Node::FinishNotLater:
337 case Node::MustFinishOn:
338 case Node::FixedInterval:
339 return s;
340 default:
341 break;
342 }
343 return QString( "(%1)" ).arg( s );
344 }
345 case Qt::ToolTipRole: {
346 int c = node->constraint();
347 if ( c == Node::FinishNotLater || c == Node::MustFinishOn || c == Node::FixedInterval ) {
348 return KGlobal::locale()->formatDateTime( node->constraintEndTime(), KLocale::LongDate, KLocale::TimeZone );
349 }
350 break;
351 }
352 case Qt::EditRole:
353 return node->constraintEndTime();
354 case Qt::StatusTipRole:
355 case Qt::WhatsThisRole:
356 return QVariant();
357 }
358 }
359 return QVariant();
360}
361
362QVariant NodeModel::estimateType( const Node *node, int role ) const
363{
364 if ( node->estimate() == 0 ) {
365 return QVariant();
366 }
367 switch ( role ) {
368 case Qt::DisplayRole:
369 case Qt::ToolTipRole:
370 if ( node->type() == Node::Type_Task ) {
371 return node->estimate()->typeToString( true );
372 }
373 return QString();
374 case Role::EnumList:
375 return Estimate::typeToStringList( true );
376 case Qt::EditRole:
377 if ( node->type() == Node::Type_Task ) {
378 return node->estimate()->typeToString();
379 }
380 return QString();
381 case Role::EnumListValue:
382 return (int)node->estimate()->type();
383 case Qt::StatusTipRole:
384 case Qt::WhatsThisRole:
385 return QVariant();
386 }
387 return QVariant();
388}
389
390QVariant NodeModel::estimateCalendar( const Node *node, int role ) const
391{
392 if ( node->estimate() == 0 ) {
393 return QVariant();
394 }
395 switch ( role ) {
396 case Qt::DisplayRole:
397 if ( node->type() == Node::Type_Task ) {
398 if ( node->estimate()->calendar() ) {
399 return node->estimate()->calendar()->name();
400 }
401 return i18n( "None" );
402 }
403 return QString();
404 case Qt::ToolTipRole:
405 if ( node->type() == Node::Type_Task ) {
406 if ( node->estimate()->type() == Estimate::Type_Effort ) {
407 return i18nc( "@info:tooltip", "Not applicable, estimate type is Effort" );
408 }
409 if ( node->estimate()->calendar() ) {
410 return node->estimate()->calendar()->name();
411 }
412 return QVariant();
413 }
414 return QString();
415 case Role::EnumList:
416 {
417 QStringList lst; lst << i18n( "None" );
418 const Node *n = const_cast<Node*>( node )->projectNode();
419 if ( n ) {
420 lst += static_cast<const Project*>( n )->calendarNames();
421 }
422 return lst;
423 }
424 case Qt::EditRole:
425 if ( node->type() == Node::Type_Task ) {
426 if ( node->estimate()->calendar() == 0 ) {
427 return i18n( "None" );
428 }
429 return node->estimate()->calendar()->name();
430 }
431 return QString();
432 case Role::EnumListValue:
433 {
434 if ( node->estimate()->calendar() == 0 ) {
435 return 0;
436 }
437 QStringList lst;
438 const Node *n = const_cast<Node*>( node )->projectNode();
439 if ( n ) {
440 lst = static_cast<const Project*>( n )->calendarNames();
441 }
442 return lst.indexOf( node->estimate()->calendar()->name() ) + 1;
443 }
444 case Qt::StatusTipRole:
445 case Qt::WhatsThisRole:
446 return QVariant();
447 }
448 return QVariant();
449}
450
451QVariant NodeModel::estimate( const Node *node, int role ) const
452{
453 if ( node->estimate() == 0 ) {
454 return QVariant();
455 }
456 switch ( role ) {
457 case Qt::DisplayRole:
458 if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) {
459 Duration::Unit unit = node->estimate()->unit();
460 QString s = KGlobal::locale()->formatNumber( node->estimate()->expectedEstimate(), m_prec ) + Duration::unitToString( unit, true );
461 if ( node->constraint() == Node::FixedInterval && node->estimate()->type() == Estimate::Type_Duration ) {
462 s = '(' + s + ')';
463 }
464 return s;
465 }
466 break;
467 case Qt::ToolTipRole:
468 if ( node->type() == Node::Type_Task ) {
469 Duration::Unit unit = node->estimate()->unit();
470 QString s = KGlobal::locale()->formatNumber( node->estimate()->expectedEstimate(), m_prec ) + Duration::unitToString( unit, true );
471 Estimate::Type t = node->estimate()->type();
472 if ( node->constraint() == Node::FixedInterval && t == Estimate::Type_Duration ) {
473 s = i18nc( "@info:tooltip", "Not applicable, constraint is Fixed Interval" );
474 } else if ( t == Estimate::Type_Effort ) {
475 s = i18nc( "@info:tooltip", "Estimated effort: %1", s );
476 } else {
477 s = i18nc( "@info:tooltip", "Estimated duration: %1", s );
478 }
479 return s;
480 }
481 break;
482 case Qt::EditRole:
483 return node->estimate()->expectedEstimate();
484 case Role::DurationUnit:
485 return static_cast<int>( node->estimate()->unit() );
486 case Role::Minimum:
487 return m_project->config().minimumDurationUnit();
488 case Role::Maximum:
489 return m_project->config().maximumDurationUnit();
490 case Qt::StatusTipRole:
491 case Qt::WhatsThisRole:
492 return QVariant();
493 }
494 return QVariant();
495}
496
497QVariant NodeModel::optimisticRatio( const Node *node, int role ) const
498{
499 if ( node->estimate() == 0 || node->type() == Node::Type_Summarytask || node->type() == Node::Type_Milestone ) {
500 return QVariant();
501 }
502 switch ( role ) {
503 case Qt::DisplayRole:
504 if ( node->type() == Node::Type_Task && node->constraint() == Node::FixedInterval && node->estimate()->type() == Estimate::Type_Duration ) {
505 QString s = QString::number( node->estimate()->optimisticRatio() );
506 s = '(' + s + ')';
507 return s;
508 }
509 if ( node->estimate() ) {
510 return node->estimate()->optimisticRatio();
511 }
512 break;
513 case Qt::EditRole:
514 if ( node->estimate() ) {
515 return node->estimate()->optimisticRatio();
516 }
517 break;
518 case Qt::ToolTipRole:
519 if ( node->type() == Node::Type_Task ) {
520 Duration::Unit unit = node->estimate()->unit();
521 QString s = KGlobal::locale()->formatNumber( node->estimate()->optimisticEstimate(), m_prec ) + Duration::unitToString( unit, true );
522 Estimate::Type t = node->estimate()->type();
523 if ( node->constraint() == Node::FixedInterval && t == Estimate::Type_Duration ) {
524 s = i18nc( "@info:tooltip", "Not applicable, constraint is Fixed Interval" );
525 } else if ( t == Estimate::Type_Effort ) {
526 s = i18nc( "@info:tooltip", "Optimistic effort: %1", s );
527 } else {
528 s = i18nc( "@info:tooltip", "Optimistic duration: %1", s );
529 }
530 return s;
531 }
532 break;
533 case Role::Minimum:
534 return -99;
535 case Role::Maximum:
536 return 0;
537 case Qt::StatusTipRole:
538 case Qt::WhatsThisRole:
539 return QVariant();
540 }
541 return QVariant();
542}
543
544QVariant NodeModel::pessimisticRatio( const Node *node, int role ) const
545{
546 if ( node->estimate() == 0 || node->type() == Node::Type_Summarytask || node->type() == Node::Type_Milestone ) {
547 return QVariant();
548 }
549 switch ( role ) {
550 case Qt::DisplayRole:
551 if ( node->type() == Node::Type_Task && node->constraint() == Node::FixedInterval && node->estimate()->type() == Estimate::Type_Duration ) {
552 QString s = QString::number( node->estimate()->pessimisticRatio() );
553 s = '(' + s + ')';
554 return s;
555 }
556 if ( node->estimate() ) {
557 return node->estimate()->pessimisticRatio();
558 }
559 break;
560 case Qt::EditRole:
561 if ( node->estimate() ) {
562 return node->estimate()->pessimisticRatio();
563 }
564 break;
565 case Qt::ToolTipRole:
566 if ( node->type() == Node::Type_Task ) {
567 Duration::Unit unit = node->estimate()->unit();
568 QString s = KGlobal::locale()->formatNumber( node->estimate()->pessimisticEstimate(), m_prec ) + Duration::unitToString( unit, true );
569 Estimate::Type t = node->estimate()->type();
570 if ( node->constraint() == Node::FixedInterval && t == Estimate::Type_Duration ) {
571 s = i18nc( "@info:tooltip", "Not applicable, constraint is Fixed Interval" );
572 } else if ( t == Estimate::Type_Effort ) {
573 s = i18nc( "@info:tooltip", "Pessimistic effort: %1", s );
574 } else {
575 s = i18nc( "@info:tooltip", "Pessimistic duration: %1", s );
576 }
577 return s;
578 }
579 break;
580 case Role::Minimum:
581 return 0;
582 case Role::Maximum:
583 return INT_MAX;
584 case Qt::StatusTipRole:
585 case Qt::WhatsThisRole:
586 return QVariant();
587 }
588 return QVariant();
589}
590
591QVariant NodeModel::riskType( const Node *node, int role ) const
592{
593 if ( node->estimate() == 0 ) {
594 return QVariant();
595 }
596 switch ( role ) {
597 case Qt::DisplayRole:
598 case Qt::ToolTipRole:
599 if ( node->type() == Node::Type_Task ) {
600 return node->estimate()->risktypeToString( true );
601 }
602 return QString();
603 case Role::EnumList:
604 return Estimate::risktypeToStringList( true );
605 case Qt::EditRole:
606 if ( node->type() == Node::Type_Task ) {
607 return node->estimate()->risktypeToString();
608 }
609 return QString();
610 case Role::EnumListValue:
611 return (int)node->estimate()->risktype();
612 case Qt::StatusTipRole:
613 case Qt::WhatsThisRole:
614 return QVariant();
615 }
616 return QVariant();
617}
618
619QVariant NodeModel::runningAccount( const Node *node, int role ) const
620{
621 switch ( role ) {
622 case Qt::DisplayRole:
623 if ( node->type() == Node::Type_Task ) {
624 Account *a = node->runningAccount();
625 return a == 0 ? i18n( "None" ) : a->name();
626 }
627 break;
628 case Qt::ToolTipRole:
629 if ( node->type() == Node::Type_Task ) {
630 Account *a = node->runningAccount();
631 return a ? i18nc( "@info:tooltip", "Account for resource cost: %1", a->name() )
632 : i18nc( "@info:tooltip", "Account for resource cost" );
633 }
634 break;
635 case Role::EnumListValue:
636 case Qt::EditRole: {
637 Account *a = node->runningAccount();
638 return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 );
639 }
640 case Role::EnumList: {
641 QStringList lst;
642 lst << i18n("None");
643 lst += m_project->accounts().costElements();
644 return lst;
645 }
646 case Qt::StatusTipRole:
647 case Qt::WhatsThisRole:
648 return QVariant();
649 }
650 return QVariant();
651}
652
653QVariant NodeModel::startupAccount( const Node *node, int role ) const
654{
655 switch ( role ) {
656 case Qt::DisplayRole:
657 if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) {
658 Account *a = node->startupAccount();
659 //kDebug(planDbg())<<node->name()<<": "<<a;
660 return a == 0 ? i18n( "None" ) : a->name();
661 }
662 break;
663 case Qt::ToolTipRole:
664 if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) {
665 Account *a = node->startupAccount();
666 //kDebug(planDbg())<<node->name()<<": "<<a;
667 return a ? i18nc( "@info:tooltip", "Account for task startup cost: %1", a->name() )
668 : i18nc( "@info:tooltip", "Account for task startup cost" );
669 }
670 break;
671 case Role::EnumListValue:
672 case Qt::EditRole: {
673 Account *a = node->startupAccount();
674 return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 );
675 }
676 case Role::EnumList: {
677 QStringList lst;
678 lst << i18n("None");
679 lst += m_project->accounts().costElements();
680 return lst;
681 }
682 case Qt::StatusTipRole:
683 case Qt::WhatsThisRole:
684 return QVariant();
685 }
686 return QVariant();
687}
688
689QVariant NodeModel::startupCost( const Node *node, int role ) const
690{
691 switch ( role ) {
692 case Qt::DisplayRole:
693 case Qt::ToolTipRole:
694 if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) {
695 return m_project->locale()->formatMoney( node->startupCost() );
696 }
697 break;
698 case Qt::EditRole:
699 return node->startupCost();
700 case Qt::StatusTipRole:
701 case Qt::WhatsThisRole:
702 return QVariant();
703 }
704 return QVariant();
705}
706
707QVariant NodeModel::shutdownAccount( const Node *node, int role ) const
708{
709 switch ( role ) {
710 case Qt::DisplayRole:
711 if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) {
712 Account *a = node->shutdownAccount();
713 return a == 0 ? i18n( "None" ) : a->name();
714 }
715 break;
716 case Qt::ToolTipRole:
717 if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) {
718 Account *a = node->shutdownAccount();
719 return a ? i18nc( "@info:tooltip", "Account for task shutdown cost: %1", a->name() )
720 : i18nc( "@info:tooltip", "Account for task shutdown cost" );
721 }
722 break;
723 case Role::EnumListValue:
724 case Qt::EditRole: {
725 Account *a = node->shutdownAccount();
726 return a == 0 ? 0 : ( m_project->accounts().costElements().indexOf( a->name() ) + 1 );
727 }
728 case Role::EnumList: {
729 QStringList lst;
730 lst << i18n("None");
731 lst += m_project->accounts().costElements();
732 return lst;
733 }
734 case Qt::StatusTipRole:
735 case Qt::WhatsThisRole:
736 return QVariant();
737 }
738 return QVariant();
739}
740
741QVariant NodeModel::shutdownCost( const Node *node, int role ) const
742{
743 switch ( role ) {
744 case Qt::DisplayRole:
745 case Qt::ToolTipRole:
746 if ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) {
747 return m_project->locale()->formatMoney( node->shutdownCost() );
748 }
749 break;
750 case Qt::EditRole:
751 return node->shutdownCost();
752 case Qt::StatusTipRole:
753 case Qt::WhatsThisRole:
754 return QVariant();
755 }
756 return QVariant();
757}
758
759QVariant NodeModel::startTime( const Node *node, int role ) const
760{
761 switch ( role ) {
762 case Qt::DisplayRole:
763 return KGlobal::locale()->formatDateTime( node->startTime( id() ) );
764 case Qt::ToolTipRole:
765 //kDebug(planDbg())<<node->name()<<", "<<role;
766 return i18nc( "@info:tooltip", "Scheduled start: %1", KGlobal::locale()->formatDateTime( node->startTime( id() ), KLocale::LongDate, KLocale::TimeZone ) );
767 case Qt::EditRole:
768 return node->startTime( id() );
769 case Qt::StatusTipRole:
770 case Qt::WhatsThisRole:
771 return QVariant();
772 }
773 return QVariant();
774}
775
776QVariant NodeModel::endTime( const Node *node, int role ) const
777{
778 switch ( role ) {
779 case Qt::DisplayRole:
780 return KGlobal::locale()->formatDateTime( node->endTime( id() ) );
781 case Qt::ToolTipRole:
782 //kDebug(planDbg())<<node->name()<<", "<<role;
783 return i18nc( "@info:tooltip", "Scheduled finish: %1", KGlobal::locale()->formatDateTime( node->endTime( id() ), KLocale::LongDate, KLocale::TimeZone ) );
784 case Qt::EditRole:
785 return node->endTime( id() );
786 case Qt::StatusTipRole:
787 case Qt::WhatsThisRole:
788 return QVariant();
789 }
790 return QVariant();
791}
792
793QVariant NodeModel::duration( const Node *node, int role ) const
794{
795 switch ( role ) {
796 case Qt::DisplayRole:
797 if ( node->type() == Node::Type_Task ) {
798 Duration::Unit unit = node->estimate()->unit();
799 double v = node->duration( id() ).toDouble( unit );
800 return QVariant(KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ));
801 } else if ( node->type() == Node::Type_Project ) {
802 Duration::Unit unit = Duration::Unit_d;
803 double v = node->duration( id() ).toDouble( unit );
804 return QVariant(KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ));
805 }
806 break;
807 case Qt::ToolTipRole:
808 if ( node->type() == Node::Type_Task ) {
809 Duration::Unit unit = node->estimate()->unit();
810 double v = node->duration( id() ).toDouble( unit );
811 return i18nc( "@info:tooltip", "Scheduled duration: %1", KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ) );
812 } else if ( node->type() == Node::Type_Project ) {
813 Duration::Unit unit = Duration::Unit_d;
814 double v = node->duration( id() ).toDouble( unit );
815 return i18nc( "@info:tooltip", "Scheduled duration: %1", KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ) );
816 }
817 break;
818 case Qt::EditRole: {
819 return node->duration( id() ).toDouble( Duration::Unit_h );
820 }
821 case Qt::StatusTipRole:
822 case Qt::WhatsThisRole:
823 return QVariant();
824 }
825 return QVariant();
826}
827
828QVariant NodeModel::varianceDuration( const Node *node, int role ) const
829{
830 switch ( role ) {
831 case Qt::DisplayRole:
832 if ( node->type() == Node::Type_Task ) {
833 Duration::Unit unit = node->estimate()->unit();
834 double v = node->variance( id(), unit );
835 return KGlobal::locale()->formatNumber( v );
836 }
837 break;
838 case Qt::EditRole:
839 if ( node->type() == Node::Type_Task ) {
840 Duration::Unit unit = node->estimate()->unit();
841 return node->variance( id(), unit );
842 }
843 return 0.0;
844 case Qt::ToolTipRole:
845 if ( node->type() == Node::Type_Task ) {
846 Duration::Unit unit = node->estimate()->unit();
847 double v = node->variance( id(), unit );
848 return i18nc( "@info:tooltip", "PERT duration variance: %1", KGlobal::locale()->formatNumber( v ) );
849 }
850 break;
851 case Qt::StatusTipRole:
852 case Qt::WhatsThisRole:
853 return QVariant();
854 }
855 return QVariant();
856}
857
858QVariant NodeModel::varianceEstimate( const Estimate *est, int role ) const
859{
860 switch ( role ) {
861 case Qt::DisplayRole: {
862 if ( est == 0 ) {
863 return QVariant();
864 }
865 Duration::Unit unit = est->unit();
866 double v = est->variance( unit );
867 //kDebug(planDbg())<<node->name()<<": "<<v<<" "<<unit<<" : "<<scales;
868 return KGlobal::locale()->formatNumber( v );
869 }
870 case Qt::EditRole: {
871 if ( est == 0 ) {
872 return 0.0;
873 }
874 return est->variance( est->unit() );
875 }
876 case Qt::ToolTipRole: {
877 if ( est == 0 ) {
878 return QVariant();
879 }
880 Duration::Unit unit = est->unit();
881 double v = est->variance( unit );
882 return i18nc( "@info:tooltip", "PERT estimate variance: %1", KGlobal::locale()->formatNumber( v ) + Duration::unitToString( unit, true ) );
883 }
884 case Qt::StatusTipRole:
885 case Qt::WhatsThisRole:
886 return QVariant();
887 }
888 return QVariant();
889}
890
891QVariant NodeModel::optimisticDuration( const Node *node, int role ) const
892{
893 switch ( role ) {
894 case Qt::DisplayRole: {
895 if ( node->type() != Node::Type_Task ) {
896 return QVariant();
897 }
898 Duration d = node->duration( id() );
899 d = ( d * ( 100 + node->estimate()->optimisticRatio() ) ) / 100;
900 Duration::Unit unit = node->estimate()->unit();
901 double v = d.toDouble( unit );
902 //kDebug(planDbg())<<node->name()<<": "<<v<<" "<<unit<<" : "<<scales;
903 return QVariant(KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ));
904 break;
905 }
906 case Qt::EditRole: {
907 if ( node->type() != Node::Type_Task ) {
908 return 0.0;
909 }
910 Duration d = node->duration( id() );
911 d = ( d * ( 100 + node->estimate()->optimisticRatio() ) ) / 100;
912 Duration::Unit unit = node->estimate()->unit();
913 return d.toDouble( unit );
914 }
915 case Qt::ToolTipRole: {
916 if ( node->type() != Node::Type_Task ) {
917 return QVariant();
918 }
919 Duration d = node->duration( id() );
920 d = ( d * ( 100 + node->estimate()->optimisticRatio() ) ) / 100;
921 Duration::Unit unit = node->estimate()->unit();
922 double v = d.toDouble( unit );
923 //kDebug(planDbg())<<node->name()<<": "<<v<<" "<<unit<<" : "<<scales;
924 return i18nc( "@info:tooltip", "PERT optimistic duration: %1", KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ) );
925 break;
926 }
927 case Qt::StatusTipRole:
928 case Qt::WhatsThisRole:
929 return QVariant();
930 }
931 return QVariant();
932}
933
934QVariant NodeModel::optimisticEstimate( const Estimate *est, int role ) const
935{
936 switch ( role ) {
937 case Qt::DisplayRole: {
938 if ( est == 0 ) {
939 return QVariant();
940 }
941 Duration::Unit unit = est->unit();
942 return QVariant(KGlobal::locale()->formatNumber( est->optimisticEstimate(), m_prec ) + Duration::unitToString( unit, true ));
943 break;
944 }
945 case Qt::EditRole: {
946 if ( est == 0 ) {
947 return 0.0;
948 }
949 return est->optimisticEstimate();
950 }
951 case Qt::ToolTipRole: {
952 if ( est == 0 ) {
953 return QVariant();
954 }
955 Duration::Unit unit = est->unit();
956 return i18nc( "@info:tooltip", "Optimistic estimate: %1", KGlobal::locale()->formatNumber( est->optimisticEstimate(), m_prec ) + Duration::unitToString( unit, true ) );
957 break;
958 }
959 case Qt::StatusTipRole:
960 case Qt::WhatsThisRole:
961 return QVariant();
962 }
963 return QVariant();
964}
965
966QVariant NodeModel::pertExpected( const Estimate *est, int role ) const
967{
968 switch ( role ) {
969 case Qt::DisplayRole: {
970 if ( est == 0 ) {
971 return QVariant();
972 }
973 Duration::Unit unit = est->unit();
974 double v = Estimate::scale( est->pertExpected(), unit, est->scales() );
975 return QVariant(KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ));
976 }
977 case Qt::EditRole: {
978 if ( est == 0 ) {
979 return 0.0;
980 }
981 return Estimate::scale( est->pertExpected(), est->unit(), est->scales() );
982 }
983 case Qt::ToolTipRole: {
984 if ( est == 0 ) {
985 return QVariant();
986 }
987 Duration::Unit unit = est->unit();
988 double v = Estimate::scale( est->pertExpected(), unit, est->scales() );
989 return i18nc( "@info:tooltip", "PERT expected estimate: %1", KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ) );
990 }
991 case Qt::StatusTipRole:
992 case Qt::WhatsThisRole:
993 return QVariant();
994 }
995 return QVariant();
996}
997
998QVariant NodeModel::pessimisticDuration( const Node *node, int role ) const
999{
1000 switch ( role ) {
1001 case Qt::DisplayRole: {
1002 if ( node->type() != Node::Type_Task ) {
1003 return QVariant();
1004 }
1005 Duration d = node->duration( id() );
1006 d = ( d * ( 100 + node->estimate()->pessimisticRatio() ) ) / 100;
1007 Duration::Unit unit = node->estimate()->unit();
1008 double v = d.toDouble( unit );
1009 //kDebug(planDbg())<<node->name()<<": "<<v<<" "<<unit<<" : "<<scales;
1010 return QVariant(KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ));
1011 break;
1012 }
1013 case Qt::EditRole: {
1014 if ( node->type() != Node::Type_Task ) {
1015 return 0.0;
1016 }
1017 Duration d = node->duration( id() );
1018 d = ( d * ( 100 + node->estimate()->pessimisticRatio() ) ) / 100;
1019 return d.toDouble( node->estimate()->unit() );
1020 }
1021 case Qt::ToolTipRole: {
1022 if ( node->type() != Node::Type_Task ) {
1023 return QVariant();
1024 }
1025 Duration d = node->duration( id() );
1026 d = ( d * ( 100 + node->estimate()->pessimisticRatio() ) ) / 100;
1027 Duration::Unit unit = node->estimate()->unit();
1028 double v = d.toDouble( unit );
1029 //kDebug(planDbg())<<node->name()<<": "<<v<<" "<<unit<<" : "<<scales;
1030 return i18nc( "@info:tooltip", "PERT pessimistic duration: %1", KGlobal::locale()->formatNumber( v, m_prec ) + Duration::unitToString( unit, true ) );
1031 break;
1032 }
1033 case Qt::StatusTipRole:
1034 case Qt::WhatsThisRole:
1035 return QVariant();
1036 }
1037 return QVariant();
1038}
1039
1040QVariant NodeModel::pessimisticEstimate( const Estimate *est, int role ) const
1041{
1042 switch ( role ) {
1043 case Qt::DisplayRole: {
1044 if ( est == 0 ) {
1045 return QVariant();
1046 }
1047 Duration::Unit unit = est->unit();
1048 return QVariant(KGlobal::locale()->formatNumber( est->pessimisticEstimate(), m_prec ) + Duration::unitToString( unit, true ));
1049 break;
1050 }
1051 case Qt::EditRole: {
1052 if ( est == 0 ) {
1053 return 0.0;
1054 }
1055 return est->pessimisticEstimate();
1056 }
1057 case Qt::ToolTipRole: {
1058 if ( est == 0 ) {
1059 return QVariant();
1060 }
1061 Duration::Unit unit = est->unit();
1062 return i18nc( "@info:tooltip", "Pessimistic estimate: %1", KGlobal::locale()->formatNumber( est->pessimisticEstimate(), m_prec ) + Duration::unitToString( unit, true ) );
1063 break;
1064 }
1065 case Qt::StatusTipRole:
1066 case Qt::WhatsThisRole:
1067 return QVariant();
1068 }
1069 return QVariant();
1070}
1071
1072QVariant NodeModel::earlyStart( const Node *node, int role ) const
1073{
1074 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1075 return QVariant();
1076 }
1077 const Task *t = static_cast<const Task*>( node );
1078 switch ( role ) {
1079 case Qt::DisplayRole:
1080 return KGlobal::locale()->formatDateTime( t->earlyStart( id() ) );
1081 case Qt::ToolTipRole:
1082 return KGlobal::locale()->formatDate( t->earlyStart( id() ).date() );
1083 case Qt::EditRole:
1084 return t->earlyStart( id() );
1085 case Qt::StatusTipRole:
1086 case Qt::WhatsThisRole:
1087 return QVariant();
1088 }
1089 return QVariant();
1090}
1091
1092QVariant NodeModel::earlyFinish( const Node *node, int role ) const
1093{
1094 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1095 return QVariant();
1096 }
1097 const Task *t = static_cast<const Task*>( node );
1098 switch ( role ) {
1099 case Qt::DisplayRole:
1100 return KGlobal::locale()->formatDateTime( t->earlyFinish( id() ) );
1101 case Qt::ToolTipRole:
1102 return KGlobal::locale()->formatDate( t->earlyFinish( id() ).date() );
1103 case Qt::EditRole:
1104 return t->earlyFinish( id() );
1105 case Qt::StatusTipRole:
1106 case Qt::WhatsThisRole:
1107 return QVariant();
1108 }
1109 return QVariant();
1110}
1111
1112QVariant NodeModel::lateStart( const Node *node, int role ) const
1113{
1114 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1115 return QVariant();
1116 }
1117 const Task *t = static_cast<const Task*>( node );
1118 switch ( role ) {
1119 case Qt::DisplayRole:
1120 return KGlobal::locale()->formatDateTime( t->lateStart( id() ) );
1121 case Qt::ToolTipRole:
1122 return KGlobal::locale()->formatDate( t->lateStart( id() ).date() );
1123 case Qt::EditRole:
1124 return t->lateStart( id() );
1125 case Qt::StatusTipRole:
1126 case Qt::WhatsThisRole:
1127 return QVariant();
1128 }
1129 return QVariant();
1130}
1131
1132QVariant NodeModel::lateFinish( const Node *node, int role ) const
1133{
1134 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1135 return QVariant();
1136 }
1137 const Task *t = static_cast<const Task*>( node );
1138 switch ( role ) {
1139 case Qt::DisplayRole:
1140 return KGlobal::locale()->formatDateTime( t->lateFinish( id() ) );
1141 case Qt::ToolTipRole:
1142 return KGlobal::locale()->formatDate( t->lateFinish( id() ).date() );
1143 case Qt::EditRole:
1144 return t->lateFinish( id() );
1145 case Qt::StatusTipRole:
1146 case Qt::WhatsThisRole:
1147 return QVariant();
1148 }
1149 return QVariant();
1150}
1151
1152QVariant NodeModel::positiveFloat( const Node *node, int role ) const
1153{
1154 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1155 return QVariant();
1156 }
1157 const Task *t = static_cast<const Task*>( node );
1158 switch ( role ) {
1159 case Qt::DisplayRole:
1160 return t->positiveFloat( id() ).toString( Duration::Format_i18nHourFraction );
1161 case Qt::ToolTipRole:
1162 return t->positiveFloat( id() ).toString( Duration::Format_i18nDayTime );
1163 case Qt::EditRole:
1164 return t->positiveFloat( id() ).toDouble( Duration::Unit_h );
1165 case Qt::StatusTipRole:
1166 case Qt::WhatsThisRole:
1167 return QVariant();
1168 }
1169 return QVariant();
1170}
1171
1172QVariant NodeModel::freeFloat( const Node *node, int role ) const
1173{
1174 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1175 return QVariant();
1176 }
1177 const Task *t = static_cast<const Task*>( node );
1178 switch ( role ) {
1179 case Qt::DisplayRole:
1180 return t->freeFloat( id() ).toString( Duration::Format_i18nHourFraction );
1181 case Qt::ToolTipRole:
1182 return t->freeFloat( id() ).toString( Duration::Format_i18nDayTime );
1183 case Qt::EditRole:
1184 return t->freeFloat( id() ).toDouble( Duration::Unit_h );
1185 case Qt::StatusTipRole:
1186 case Qt::WhatsThisRole:
1187 return QVariant();
1188 }
1189 return QVariant();
1190}
1191
1192QVariant NodeModel::negativeFloat( const Node *node, int role ) const
1193{
1194 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1195 return QVariant();
1196 }
1197 const Task *t = static_cast<const Task*>( node );
1198 switch ( role ) {
1199 case Qt::DisplayRole:
1200 return t->negativeFloat( id() ).toString( Duration::Format_i18nHourFraction );
1201 case Qt::ToolTipRole:
1202 return t->negativeFloat( id() ).toString( Duration::Format_i18nDayTime );
1203 case Qt::EditRole:
1204 return t->negativeFloat( id() ).toDouble( Duration::Unit_h );
1205 case Qt::StatusTipRole:
1206 case Qt::WhatsThisRole:
1207 return QVariant();
1208 }
1209 return QVariant();
1210}
1211
1212QVariant NodeModel::startFloat( const Node *node, int role ) const
1213{
1214 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1215 return QVariant();
1216 }
1217 const Task *t = static_cast<const Task*>( node );
1218 switch ( role ) {
1219 case Qt::DisplayRole:
1220 return t->startFloat( id() ).toString( Duration::Format_i18nHourFraction );
1221 case Qt::ToolTipRole:
1222 return t->startFloat( id() ).toString( Duration::Format_i18nDayTime );
1223 case Qt::EditRole:
1224 return t->startFloat( id() ).toDouble( Duration::Unit_h );
1225 case Qt::StatusTipRole:
1226 case Qt::WhatsThisRole:
1227 return QVariant();
1228 }
1229 return QVariant();
1230}
1231
1232QVariant NodeModel::finishFloat( const Node *node, int role ) const
1233{
1234 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1235 return QVariant();
1236 }
1237 const Task *t = static_cast<const Task*>( node );
1238 switch ( role ) {
1239 case Qt::DisplayRole:
1240 return t->finishFloat( id() ).toString( Duration::Format_i18nHourFraction );
1241 case Qt::ToolTipRole:
1242 return t->finishFloat( id() ).toString( Duration::Format_i18nDayTime );
1243 case Qt::EditRole:
1244 t->finishFloat( id() ).toDouble( Duration::Unit_h );
1245 case Qt::StatusTipRole:
1246 case Qt::WhatsThisRole:
1247 return QVariant();
1248 }
1249 return QVariant();
1250}
1251
1252QVariant NodeModel::assignedResources( const Node *node, int role ) const
1253{
1254 if ( node->type() != Node::Type_Task ) {
1255 return QVariant();
1256 }
1257 switch ( role ) {
1258 case Qt::DisplayRole:
1259 case Qt::EditRole:
1260 return node->assignedNameList( id() ).join(",");
1261 case Qt::ToolTipRole: {
1262 QStringList lst = node->assignedNameList( id() );
1263 if ( ! lst.isEmpty() ) {
1264 return i18nc( "@info:tooltip 1=list of resources", "Assigned resources:<nl/>%1", node->assignedNameList( id() ).join("<nl/>") );
1265 }
1266 break;
1267 }
1268 case Qt::StatusTipRole:
1269 case Qt::WhatsThisRole:
1270 return QVariant();
1271 }
1272 return QVariant();
1273}
1274
1275
1276QVariant NodeModel::completed( const Node *node, int role ) const
1277{
1278 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1279 return QVariant();
1280 }
1281 const Task *t = static_cast<const Task*>( node );
1282 switch ( role ) {
1283 case Qt::DisplayRole:
1284 return t->completion().percentFinished();
1285 case Qt::EditRole:
1286 return t->completion().percentFinished();
1287 case Qt::ToolTipRole:
1288 return i18nc( "@info:tooltip", "Task is %1% completed", t->completion().percentFinished() );
1289 case Qt::StatusTipRole:
1290 case Qt::WhatsThisRole:
1291 return QVariant();
1292 }
1293 return QVariant();
1294}
1295
1296QVariant NodeModel::status( const Node *node, int role ) const
1297{
1298 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1299 return QVariant();
1300 }
1301 const Task *t = static_cast<const Task*>( node );
1302 switch ( role ) {
1303 case Qt::DisplayRole: {
1304 int st = t->state( id() );
1305 if ( st & Node::State_NotScheduled ) {
1306 return SchedulingState::notScheduled();
1307 }
1308 if ( st & Node::State_Finished ) {
1309 if ( st & Node::State_FinishedLate ) {
1310 return i18n( "Finished late" );
1311 }
1312 if ( st & Node::State_FinishedEarly ) {
1313 return i18n( "Finished early" );
1314 }
1315 return i18n( "Finished" );
1316 }
1317 if ( st & Node::State_Running ) {
1318 if ( st & Node::State_Late ) {
1319 return i18n( "Running late" );
1320 }
1321 return i18n( "Running" );
1322 }
1323 if ( st & Node::State_Started ) {
1324 if ( st & Node::State_StartedLate ) {
1325 return i18n( "Started late" );
1326 }
1327 if ( st & Node::State_StartedEarly ) {
1328 return i18n( "Started early" );
1329 }
1330 if ( st & Node::State_Late ) {
1331 return i18n( "Running late" );
1332 }
1333 return i18n( "Started" );
1334 }
1335 if ( st & Node::State_ReadyToStart ) {
1336 if ( st & Node::State_Late ) {
1337 return i18n( "Not started" );
1338 }
1339 return i18n( "Can start" );
1340 }
1341 if ( st & Node::State_NotReadyToStart ) {
1342 if ( st & Node::State_Late ) {
1343 return i18n( "Delayed" );
1344 }
1345 return i18n( "Cannot start" );
1346 }
1347 return i18n( "Not started" );
1348 break;
1349 }
1350 case Qt::ToolTipRole: {
1351 int st = t->state( id() );
1352 if ( st & Node::State_NotScheduled ) {
1353 return SchedulingState::notScheduled();
1354 }
1355 if ( st & Node::State_Finished ) {
1356 if ( st & Node::State_FinishedLate ) {
1357 Duration d = t->completion().finishTime() - t->endTime( id() );
1358 return i18nc( "@info:tooltip", "Finished %1 late", d.toString( Duration::Format_i18nDay ) );
1359 }
1360 if ( st & Node::State_FinishedEarly ) {
1361 Duration d = t->endTime( id() ) - t->completion().finishTime();
1362 return i18nc( "@info:tooltip", "Finished %1 early", d.toString( Duration::Format_i18nDay ) );
1363 }
1364 return i18nc( "@info:tooltip", "Finished" );
1365 }
1366 if ( st & Node::State_Started ) {
1367 if ( st & Node::State_StartedLate ) {
1368 Duration d = t->completion().startTime() - t->startTime( id() );
1369 return i18nc( "@info:tooltip", "Started %1 late", d.toString( Duration::Format_i18nDay ) );
1370 }
1371 if ( st & Node::State_StartedEarly ) {
1372 Duration d = t->startTime( id() ) - t->completion().startTime();
1373 return i18nc( "@info:tooltip", "Started %1 early", d.toString( Duration::Format_i18nDay ) );
1374 }
1375 return i18nc( "@info:tooltip", "Started" );
1376 }
1377 if ( st & Node::State_Running ) {
1378 return i18nc( "@info:tooltip", "Running" );
1379 }
1380 if ( st & Node::State_ReadyToStart ) {
1381 return i18nc( "@info:tooltip", "Can start" );
1382 }
1383 if ( st & Node::State_NotReadyToStart ) {
1384 QStringList names;
1385 // TODO: proxy relations
1386 foreach ( Relation *r, node->dependParentNodes() ) {
1387 switch ( r->type() ) {
1388 case Relation::FinishFinish:
1389 case Relation::FinishStart:
1390 if ( ! static_cast<Task*>( r->parent() )->completion().isFinished() ) {
1391 if ( ! names.contains( r->parent()->name() ) ) {
1392 names << r->parent()->name();
1393 }
1394 }
1395 break;
1396 case Relation::StartStart:
1397 if ( ! static_cast<Task*>( r->parent() )->completion().isStarted() ) {
1398 if ( ! names.contains( r->parent()->name() ) ) {
1399 names << r->parent()->name();
1400 }
1401 }
1402 break;
1403 }
1404 }
1405 return names.isEmpty()
1406 ? i18nc( "@info:tooltip", "Cannot start" )
1407 : i18nc( "@info:tooltip 1=list of task names", "Cannot start, waiting for:<nl/>%1", names.join( "<nl/>" ) );
1408 }
1409 return i18nc( "@info:tooltip", "Not started" );
1410 break;
1411 }
1412 case Qt::EditRole:
1413 return t->state( id() );
1414 case Qt::StatusTipRole:
1415 case Qt::WhatsThisRole:
1416 return QVariant();
1417 }
1418 return QVariant();
1419}
1420
1421QVariant NodeModel::startedTime( const Node *node, int role ) const
1422{
1423 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1424 return QVariant();
1425 }
1426 const Task *t = static_cast<const Task*>( node );
1427 switch ( role ) {
1428 case Qt::DisplayRole:
1429 if ( t->completion().isStarted() ) {
1430 return KGlobal::locale()->formatDateTime( t->completion().startTime() );
1431 }
1432 break;
1433 case Qt::ToolTipRole:
1434 if ( t->completion().isStarted() ) {
1435 return i18nc( "@info:tooltip", "Actual start: %1", KGlobal::locale()->formatDate( t->completion().startTime().date(), KLocale::LongDate ) );
1436 }
1437 break;
1438 case Qt::EditRole:
1439 if ( t->completion().isStarted() ) {
1440 return t->completion().startTime();
1441 }
1442 return QDateTime::currentDateTime();
1443 case Qt::StatusTipRole:
1444 case Qt::WhatsThisRole:
1445 return QVariant();
1446 }
1447 return QVariant();
1448}
1449
1450QVariant NodeModel::isStarted( const Node *node, int role ) const
1451{
1452 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1453 return QVariant();
1454 }
1455 const Task *t = static_cast<const Task*>( node );
1456 switch ( role ) {
1457 case Qt::DisplayRole:
1458 case Qt::EditRole:
1459 return t->completion().isStarted();
1460 case Qt::ToolTipRole:
1461 if ( t->completion().isStarted() ) {
1462 return i18nc( "@info:tooltip", "The task started at: %1", KGlobal::locale()->formatDate( t->completion().startTime().date(), KLocale::LongDate ) );
1463 }
1464 return i18nc( "@info:tooltip", "The task is not started" );
1465 case Qt::StatusTipRole:
1466 case Qt::WhatsThisRole:
1467 return QVariant();
1468 }
1469 return QVariant();
1470}
1471
1472QVariant NodeModel::finishedTime( const Node *node, int role ) const
1473{
1474 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1475 return QVariant();
1476 }
1477 const Task *t = static_cast<const Task*>( node );
1478 switch ( role ) {
1479 case Qt::DisplayRole:
1480 if ( t->completion().isFinished() ) {
1481 return KGlobal::locale()->formatDateTime( t->completion().finishTime() );
1482 }
1483 break;
1484 case Qt::ToolTipRole:
1485 if ( t->completion().isFinished() ) {
1486 return i18nc( "@info:tooltip", "Actual finish: %1", KGlobal::locale()->formatDateTime( t->completion().finishTime(), KLocale::LongDate, KLocale::TimeZone ) );
1487 }
1488 break;
1489 case Qt::EditRole:
1490 if ( t->completion().isFinished() ) {
1491 return t->completion().finishTime();
1492 }
1493 break;
1494 case Qt::StatusTipRole:
1495 case Qt::WhatsThisRole:
1496 return QVariant();
1497 }
1498 return QVariant();
1499}
1500
1501QVariant NodeModel::isFinished( const Node *node, int role ) const
1502{
1503 if ( ! ( node->type() == Node::Type_Task || node->type() == Node::Type_Milestone ) ) {
1504 return QVariant();
1505 }
1506 const Task *t = static_cast<const Task*>( node );
1507 switch ( role ) {
1508 case Qt::DisplayRole:
1509 case Qt::EditRole:
1510 return t->completion().isFinished();
1511 case Qt::ToolTipRole:
1512 if ( t->completion().isFinished() ) {
1513 return i18nc( "@info:tooltip", "The task finished at: %1", KGlobal::locale()->formatDate( t->completion().finishTime().date(), KLocale::LongDate ) );
1514 }
1515 return i18nc( "@info:tooltip", "The task is not finished" );
1516 case Qt::StatusTipRole:
1517 case Qt::WhatsThisRole:
1518 return QVariant();
1519 }
1520 return QVariant();
1521}
1522
1523QVariant NodeModel::plannedEffortTo( const Node *node, int role ) const
1524{
1525 KLocale *l = KGlobal::locale();
1526 switch ( role ) {
1527 case Qt::DisplayRole:
1528 return node->plannedEffortTo( m_now, id() ).format();
1529 case Qt::ToolTipRole:
1530 return i18nc( "@info:tooltip", "Planned effort until %1: %2", l->formatDate( m_now ), node->plannedEffortTo( m_now, id() ).toString( Duration::Format_i18nHour ) );
1531 case Qt::EditRole:
1532 return node->plannedEffortTo( m_now, id() ).toDouble( Duration::Unit_h );
1533 case Role::DurationUnit:
1534 return static_cast<int>( Duration::Unit_h );
1535 case Qt::StatusTipRole:
1536 case Qt::WhatsThisRole:
1537 return QVariant();
1538 }
1539 return QVariant();
1540}
1541
1542QVariant NodeModel::actualEffortTo( const Node *node, int role ) const
1543{
1544 KLocale *l = KGlobal::locale();
1545 switch ( role ) {
1546 case Qt::DisplayRole:
1547 return node->actualEffortTo( m_now ).format();
1548 case Qt::ToolTipRole:
1549 //kDebug(planDbg())<<m_now<<node;
1550 return i18nc( "@info:tooltip", "Actual effort used up to %1: %2", l->formatDate( m_now ), node->actualEffortTo( m_now ).toString( Duration::Format_i18nHour ) );
1551 case Qt::EditRole:
1552 return node->actualEffortTo( m_now ).toDouble( Duration::Unit_h );
1553 case Role::DurationUnit:
1554 return static_cast<int>( Duration::Unit_h );
1555 case Qt::StatusTipRole:
1556 case Qt::WhatsThisRole:
1557 return QVariant();
1558 }
1559 return QVariant();
1560}
1561
1562QVariant NodeModel::remainingEffort( const Node *node, int role ) const
1563{
1564 switch ( role ) {
1565 case Qt::DisplayRole: {
1566 const Task *t = dynamic_cast<const Task*>( node );
1567 if ( t ) {
1568 return t->completion().remainingEffort().format();
1569 }
1570 break;
1571 }
1572 case Qt::ToolTipRole: {
1573 const Task *t = dynamic_cast<const Task*>( node );
1574 if ( t ) {
1575 return i18nc( "@info:tooltip", "Remaining effort: %1", t->completion().remainingEffort().toString( Duration::Format_i18nHour ) );
1576 }
1577 break;
1578 }
1579 case Qt::EditRole: {
1580 const Task *t = dynamic_cast<const Task*>( node );
1581 return t->completion().remainingEffort().toDouble( Duration::Unit_h );
1582 }
1583 case Role::DurationUnit:
1584 return static_cast<int>( Duration::Unit_h );
1585 case Qt::StatusTipRole:
1586 case Qt::WhatsThisRole:
1587 return QVariant();
1588 }
1589 return QVariant();
1590}
1591
1592QVariant NodeModel::plannedCostTo( const Node *node, int role ) const
1593{
1594 KLocale *l = m_project->locale();
1595 switch ( role ) {
1596 case Qt::DisplayRole:
1597 return l->formatMoney( node->plannedCostTo( m_now, id() ) );
1598 case Qt::ToolTipRole:
1599 return i18nc( "@info:tooltip", "Planned cost until %1: %2", l->formatDate( m_now ), l->formatMoney( node->plannedCostTo( m_now, id() ) ) );
1600 case Qt::EditRole:
1601 return node->plannedCostTo( m_now );
1602 case Qt::StatusTipRole:
1603 case Qt::WhatsThisRole:
1604 return QVariant();
1605 }
1606 return QVariant();
1607}
1608
1609QVariant NodeModel::actualCostTo( const Node *node, int role ) const
1610{
1611 KLocale *l = m_project->locale();
1612 switch ( role ) {
1613 case Qt::DisplayRole:
1614 return l->formatMoney( node->actualCostTo( id(), m_now ).cost() );
1615 case Qt::ToolTipRole:
1616 return i18nc( "@info:tooltip", "Actual cost until %1: %2", l->formatDate( m_now ), l->formatMoney( node->actualCostTo( id(), m_now ).cost() ) );
1617 case Qt::EditRole:
1618 return node->actualCostTo( id(), m_now ).cost();
1619 case Qt::StatusTipRole:
1620 case Qt::WhatsThisRole:
1621 return QVariant();
1622 }
1623 return QVariant();
1624}
1625
1626QVariant NodeModel::note( const Node *node, int role ) const
1627{
1628 switch ( role ) {
1629 case Qt::DisplayRole:
1630 case Qt::EditRole:
1631 case Qt::ToolTipRole:
1632 if ( node->type() == Node::Type_Task ) {
1633 Node *n = const_cast<Node*>( node );
1634 return static_cast<Task*>( n )->completion().note();
1635 }
1636 break;
1637 case Qt::StatusTipRole:
1638 case Qt::WhatsThisRole:
1639 return QVariant();
1640 }
1641 return QVariant();
1642}
1643
1644QVariant NodeModel::nodeSchedulingStatus( const Node *node, int role ) const
1645{
1646 switch ( role ) {
1647 case Qt::DisplayRole:
1648 return node->schedulingStatus( id(), true ).value( 0 );
1649 case Qt::EditRole:
1650 return node->schedulingStatus( id(), false ).value( 0 );
1651 case Qt::ToolTipRole:
1652 return node->schedulingStatus( id(), true ).join( "\n" );
1653 case Qt::StatusTipRole:
1654 case Qt::WhatsThisRole:
1655 return QVariant();
1656 }
1657 return QVariant();
1658}
1659
1660QVariant NodeModel::resourceIsMissing( const Node *node, int role ) const
1661{
1662 switch ( role ) {
1663 case Qt::DisplayRole:
1664 if ( node->resourceError( id() ) ) {
1665 return i18n( "Error" );
1666 }
1667 break;
1668 case Qt::EditRole:
1669 return node->resourceError( id() );
1670 case Qt::ToolTipRole:
1671 if ( node->resourceError( id() ) ) {
1672 return i18nc( "@info:tooltip", "Resource allocation is expected when the task estimate type is <emphasis>Effort</emphasis>" );
1673 }
1674 break;
1675 case Qt::StatusTipRole:
1676 case Qt::WhatsThisRole:
1677 return QVariant();
1678 case Role::Foreground: {
1679 if ( ! m_project ) {
1680 break;
1681 }
1682 switch ( node->type() ) {
1683 case Node::Type_Task: return m_project->config().taskErrorColor();
1684 case Node::Type_Milestone: return m_project->config().milestoneErrorColor();
1685 default:
1686 break;
1687 }
1688 }
1689 }
1690 return QVariant();
1691}
1692
1693QVariant NodeModel::resourceIsOverbooked( const Node *node, int role ) const
1694{
1695 switch ( role ) {
1696 case Qt::DisplayRole:
1697 if ( node->resourceOverbooked( id() ) ) {
1698 return i18n( "Error" );
1699 }
1700 break;
1701 case Qt::EditRole:
1702 return node->resourceOverbooked( id() );
1703 case Qt::ToolTipRole:
1704 if ( node->resourceOverbooked( id() ) ) {
1705 return i18nc( "@info:tooltip", "A resource has been overbooked" );
1706 }
1707 break;
1708 case Qt::StatusTipRole:
1709 case Qt::WhatsThisRole:
1710 return QVariant();
1711 case Role::Foreground: {
1712 if ( ! m_project ) {
1713 break;
1714 }
1715 switch ( node->type() ) {
1716 case Node::Type_Task: return m_project->config().taskErrorColor();
1717 case Node::Type_Milestone: return m_project->config().milestoneErrorColor();
1718 default:
1719 break;
1720 }
1721 }
1722 }
1723 return QVariant();
1724}
1725
1726QVariant NodeModel::resourceIsNotAvailable( const Node *node, int role ) const
1727{
1728 switch ( role ) {
1729 case Qt::DisplayRole:
1730 if ( node->resourceNotAvailable( id() ) ) {
1731 return i18n( "Error" );
1732 }
1733 break;
1734 case Qt::EditRole:
1735 return node->resourceNotAvailable( id() );
1736 case Qt::ToolTipRole:
1737 if ( node->resourceNotAvailable( id() ) ) {
1738 return i18nc( "@info:tooltip", "No resource is available for this task" );
1739 }
1740 break;
1741 case Qt::StatusTipRole:
1742 case Qt::WhatsThisRole:
1743 return QVariant();
1744 case Role::Foreground: {
1745 if ( ! m_project ) {
1746 break;
1747 }
1748 switch ( node->type() ) {
1749 case Node::Type_Task: return m_project->config().taskErrorColor();
1750 case Node::Type_Milestone: return m_project->config().milestoneErrorColor();
1751 default:
1752 break;
1753 }
1754 }
1755 }
1756 return QVariant();
1757}
1758
1759QVariant NodeModel::schedulingConstraintsError( const Node *node, int role ) const
1760{
1761 switch ( role ) {
1762 case Qt::DisplayRole:
1763 if ( node->constraintError( id() ) ) {
1764 return i18n( "Error" );
1765 }
1766 break;
1767 case Qt::EditRole:
1768 return node->constraintError( id() );
1769 case Qt::ToolTipRole:
1770 if ( node->constraintError( id() ) ) {
1771 return i18nc( "@info:tooltip", "Failed to comply with a timing constraint" );
1772 }
1773 break;
1774 case Qt::StatusTipRole:
1775 case Qt::WhatsThisRole:
1776 return QVariant();
1777 case Role::Foreground: {
1778 if ( ! m_project ) {
1779 break;
1780 }
1781 switch ( node->type() ) {
1782 case Node::Type_Task: return m_project->config().taskErrorColor();
1783 case Node::Type_Milestone: return m_project->config().milestoneErrorColor();
1784 default:
1785 break;
1786 }
1787 }
1788 }
1789 return QVariant();
1790}
1791
1792QVariant NodeModel::nodeIsNotScheduled( const Node *node, int role ) const
1793{
1794 switch ( role ) {
1795 case Qt::DisplayRole:
1796 if ( node->notScheduled( id() ) ) {
1797 return i18n( "Error" );
1798 }
1799 break;
1800 case Qt::EditRole:
1801 return node->notScheduled( id() );
1802 case Qt::ToolTipRole:
1803 if ( node->notScheduled( id() ) ) {
1804 return i18nc( "@info:tooltip", "This task has not been scheduled" );
1805 }
1806 break;
1807 case Qt::StatusTipRole:
1808 case Qt::WhatsThisRole:
1809 return QVariant();
1810 case Role::Foreground: {
1811 if ( ! m_project ) {
1812 break;
1813 }
1814 switch ( node->type() ) {
1815 case Node::Type_Task: return m_project->config().taskErrorColor();
1816 case Node::Type_Milestone: return m_project->config().milestoneErrorColor();
1817 default:
1818 break;
1819 }
1820 }
1821 }
1822 return QVariant();
1823}
1824
1825QVariant NodeModel::effortNotMet( const Node *node, int role ) const
1826{
1827 switch ( role ) {
1828 case Qt::DisplayRole:
1829 if ( node->effortMetError( id() ) ) {
1830 return i18n( "Error" );
1831 }
1832 break;
1833 case Qt::EditRole:
1834 return node->effortMetError( id() );
1835 case Qt::ToolTipRole:
1836 if ( node->effortMetError( id() ) ) {
1837 return i18nc( "@info:tooltip", "The assigned resources cannot deliver the required estimated effort" );
1838 }
1839 break;
1840 case Qt::StatusTipRole:
1841 case Qt::WhatsThisRole:
1842 return QVariant();
1843 case Role::Foreground: {
1844 if ( ! m_project ) {
1845 break;
1846 }
1847 switch ( node->type() ) {
1848 case Node::Type_Task: return m_project->config().taskErrorColor();
1849 case Node::Type_Milestone: return m_project->config().milestoneErrorColor();
1850 default:
1851 break;
1852 }
1853 }
1854 }
1855 return QVariant();
1856}
1857
1858QVariant NodeModel::schedulingError( const Node *node, int role ) const
1859{
1860 switch ( role ) {
1861 case Qt::DisplayRole:
1862 if ( node->schedulingError( id() ) ) {
1863 return i18n( "Error" );
1864 }
1865 break;
1866 case Qt::EditRole:
1867 return node->schedulingError( id() );
1868 case Qt::ToolTipRole:
1869 if ( node->schedulingError( id() ) ) {
1870 return i18nc( "@info:tooltip", "Scheduling error" );
1871 }
1872 break;
1873 case Qt::StatusTipRole:
1874 case Qt::WhatsThisRole:
1875 return QVariant();
1876 case Role::Foreground: {
1877 if ( ! m_project ) {
1878 break;
1879 }
1880 switch ( node->type() ) {
1881 case Node::Type_Task: return m_project->config().taskErrorColor();
1882 case Node::Type_Milestone: return m_project->config().milestoneErrorColor();
1883 default:
1884 break;
1885 }
1886 }
1887 }
1888 return QVariant();
1889}
1890
1891QVariant NodeModel::wbsCode( const Node *node, int role ) const
1892{
1893 switch ( role ) {
1894 case Qt::DisplayRole:
1895 case Qt::EditRole:
1896 return node->wbsCode();
1897 case Qt::ToolTipRole:
1898 return i18nc( "@info:tooltip", "Work breakdown structure code: %1", node->wbsCode() );
1899 case Qt::StatusTipRole:
1900 case Qt::WhatsThisRole:
1901 return QVariant();
1902 }
1903 return QVariant();
1904}
1905
1906QVariant NodeModel::nodeLevel( const Node *node, int role ) const
1907{
1908 switch ( role ) {
1909 case Qt::DisplayRole:
1910 case Qt::EditRole:
1911 return node->level();
1912 case Qt::ToolTipRole:
1913 return i18nc( "@info:tooltip", "Task level: %1", node->level() );
1914 case Qt::StatusTipRole:
1915 case Qt::WhatsThisRole:
1916 return QVariant();
1917 }
1918 return QVariant();
1919}
1920
1921QVariant NodeModel::nodeBCWS( const Node *node, int role ) const
1922{
1923 switch ( role ) {
1924 case Qt::DisplayRole:
1925 return m_project->locale()->formatMoney( node->bcws( m_now, id() ), QString(), 0 );
1926 case Qt::EditRole:
1927 return node->bcws( m_now, id() );
1928 case Qt::ToolTipRole:
1929 return i18nc( "@info:tooltip", "Budgeted Cost of Work Scheduled at %1: %2", m_now.toString(), m_project->locale()->formatMoney( node->bcws( m_now, id() ), QString(), 0 ) );
1930 case Qt::StatusTipRole:
1931 case Qt::WhatsThisRole:
1932 return QVariant();
1933 }
1934 return QVariant();
1935}
1936
1937QVariant NodeModel::nodeBCWP( const Node *node, int role ) const
1938{
1939 switch ( role ) {
1940 case Qt::DisplayRole:
1941 return m_project->locale()->formatMoney( node->bcwp( id() ), QString(), 0 );
1942 case Qt::EditRole:
1943 return node->bcwp( id() );
1944 case Qt::ToolTipRole:
1945 return i18nc( "@info:tooltip", "Budgeted Cost of Work Performed at %1: %2", m_now.toString(), m_project->locale()->formatMoney( node->bcwp( id() ), QString(), 0 ) );
1946 case Qt::StatusTipRole:
1947 case Qt::WhatsThisRole:
1948 return QVariant();
1949 }
1950 return QVariant();
1951}
1952
1953QVariant NodeModel::nodeACWP( const Node *node, int role ) const
1954{
1955 switch ( role ) {
1956 case Qt::DisplayRole:
1957 return m_project->locale()->formatMoney( node->acwp( m_now, id() ).cost(), QString(), 0 );
1958 case Qt::EditRole:
1959 return node->acwp( m_now, id() ).cost();
1960 case Qt::ToolTipRole:
1961 return i18nc( "@info:tooltip", "Actual Cost of Work Performed at %1: %2", m_now.toString(), m_project->locale()->formatMoney( node->acwp( m_now, id() ).cost() ) );
1962 case Qt::StatusTipRole:
1963 case Qt::WhatsThisRole:
1964 return QVariant();
1965 }
1966 return QVariant();
1967}
1968
1969QVariant NodeModel::nodePerformanceIndex( const Node *node, int role ) const
1970{
1971 switch ( role ) {
1972 case Qt::DisplayRole:
1973 return KGlobal::locale()->formatNumber( node->schedulePerformanceIndex( m_now, id() ), 2 );
1974 case Qt::EditRole:
1975 return node->schedulePerformanceIndex( m_now, id() );
1976 case Qt::ToolTipRole:
1977 return i18nc( "@info:tooltip", "Schedule Performance Index at %1: %2", m_now.toString(), KGlobal::locale()->formatNumber( node->schedulePerformanceIndex( m_now, id() ), 2 ) );
1978 case Qt::StatusTipRole:
1979 case Qt::WhatsThisRole:
1980 return QVariant();
1981 case Qt::ForegroundRole:
1982 return node->schedulePerformanceIndex( m_now, id() ) < 1.0 ? Qt::red : Qt::black;
1983 }
1984 return QVariant();
1985}
1986
1987QVariant NodeModel::nodeIsCritical( const Node *node, int role ) const
1988{
1989 switch ( role ) {
1990 case Qt::DisplayRole:
1991 case Qt::EditRole:
1992 return node->isCritical( id() );
1993 case Qt::ToolTipRole:
1994 case Qt::StatusTipRole:
1995 case Qt::WhatsThisRole:
1996 return QVariant();
1997 case Role::Foreground: {
1998 if ( ! m_project ) {
1999 break;
2000 }
2001 switch ( node->type() ) {
2002 case Node::Type_Task: return m_project->config().taskNormalColor();
2003 case Node::Type_Milestone: return m_project->config().milestoneNormalColor();
2004 default:
2005 break;
2006 }
2007 }
2008 }
2009 return QVariant();
2010}
2011
2012QVariant NodeModel::nodeInCriticalPath( const Node *node, int role ) const
2013{
2014 switch ( role ) {
2015 case Qt::DisplayRole:
2016 case Qt::EditRole:
2017 return node->inCriticalPath( id() );
2018 case Qt::ToolTipRole:
2019 case Qt::StatusTipRole:
2020 case Qt::WhatsThisRole:
2021 return QVariant();
2022 case Role::Foreground: {
2023 if ( ! m_project ) {
2024 break;
2025 }
2026 switch ( node->type() ) {
2027 case Node::Type_Task: return m_project->config().taskNormalColor();
2028 case Node::Type_Milestone: return m_project->config().milestoneNormalColor();
2029 default:
2030 break;
2031 }
2032 }
2033 }
2034 return QVariant();
2035}
2036
2037QVariant NodeModel::wpOwnerName( const Node *node, int role ) const
2038{
2039 switch ( role ) {
2040 case Qt::DisplayRole:
2041 case Qt::EditRole: {
2042 const Task *t = dynamic_cast<const Task*>( node );
2043 if ( t == 0 ) {
2044 return QVariant();
2045 }
2046 if ( t->wpTransmitionStatus() == WorkPackage::TS_None ) {
2047 return i18nc( "Not available", "NA" );
2048 }
2049 return t->wpOwnerName();
2050 }
2051 case Qt::ToolTipRole: {
2052 const Task *task = dynamic_cast<const Task*>( node );
2053 if ( task == 0 ) {
2054 return QVariant();
2055 }
2056 int sts = task->wpTransmitionStatus();
2057 QString t = wpTransmitionTime( node, Qt::DisplayRole ).toString();
2058 if ( sts == WorkPackage::TS_Send ) {
2059 return i18nc( "@info:tooltip", "Latest work package sent to %1 at %2", static_cast<const Task*>( node )->wpOwnerName(), t );
2060 }
2061 if ( sts == WorkPackage::TS_Receive ) {
2062 return i18nc( "@info:tooltip", "Latest work package received from %1 at %2", static_cast<const Task*>( node )->wpOwnerName(), t );
2063 }
2064 return i18nc( "@info:tooltip", "Not available" );
2065 }
2066 case Qt::StatusTipRole:
2067 case Qt::WhatsThisRole:
2068 return QVariant();
2069 }
2070 return QVariant();
2071}
2072
2073QVariant NodeModel::wpTransmitionStatus( const Node *node, int role ) const
2074{
2075 switch ( role ) {
2076 case Qt::DisplayRole: {
2077 const Task *t = dynamic_cast<const Task*>( node );
2078 if ( t == 0 ) {
2079 return QVariant();
2080 }
2081 if ( t->wpTransmitionStatus() == WorkPackage::TS_None ) {
2082 return i18nc( "Not available", "NA" );
2083 }
2084 return WorkPackage::transmitionStatusToString( t->wpTransmitionStatus(), true );
2085 }
2086 case Qt::EditRole: {
2087 const Task *t = dynamic_cast<const Task*>( node );
2088 if ( t == 0 ) {
2089 return QVariant();
2090 }
2091 return WorkPackage::transmitionStatusToString( t->wpTransmitionStatus(), false );
2092 }
2093 case Qt::ToolTipRole:
2094 case Qt::StatusTipRole:
2095 case Qt::WhatsThisRole:
2096 return QVariant();
2097 }
2098 return QVariant();
2099}
2100
2101QVariant NodeModel::wpTransmitionTime( const Node *node, int role ) const
2102{
2103 switch ( role ) {
2104 case Qt::DisplayRole:
2105 case Qt::EditRole: {
2106 const Task *t = dynamic_cast<const Task*>( node );
2107 if ( t == 0 ) {
2108 return QVariant();
2109 }
2110 if ( t->wpTransmitionStatus() == WorkPackage::TS_None ) {
2111 return i18nc( "Not available", "NA" );
2112 }
2113 return KGlobal::locale()->formatDateTime( t->wpTransmitionTime() );
2114 }
2115 case Qt::ToolTipRole: {
2116 const Task *task = dynamic_cast<const Task*>( node );
2117 if ( task == 0 ) {
2118 return QVariant();
2119 }
2120 int sts = task->wpTransmitionStatus();
2121 QString t = wpTransmitionTime( node, Qt::DisplayRole ).toString();
2122 if ( sts == WorkPackage::TS_Send ) {
2123 return i18nc( "@info:tooltip", "Latest work package sent: %1", t );
2124 }
2125 if ( sts == WorkPackage::TS_Receive ) {
2126 return i18nc( "@info:tooltip", "Latest work package received: %1", t );
2127 }
2128 return i18nc( "@info:tooltip", "Not available" );
2129 }
2130 case Qt::StatusTipRole:
2131 case Qt::WhatsThisRole:
2132 return QVariant();
2133 }
2134 return QVariant();
2135}
2136
2137QVariant NodeModel::data( const Node *n, int property, int role ) const
2138{
2139 QVariant result;
2140 switch ( property ) {
2141 // Edited by user
2142 case NodeName: result = name( n, role ); break;
2143 case NodeType: result = type( n, role ); break;
2144 case NodeResponsible: result = leader( n, role ); break;
2145 case NodeAllocation: result = allocation( n, role ); break;
2146 case NodeEstimateType: result = estimateType( n, role ); break;
2147 case NodeEstimateCalendar: result = estimateCalendar( n, role ); break;
2148 case NodeEstimate: result = estimate( n, role ); break;
2149 case NodeOptimisticRatio: result = optimisticRatio( n, role ); break;
2150 case NodePessimisticRatio: result = pessimisticRatio( n, role ); break;
2151 case NodeRisk: result = riskType( n, role ); break;
2152 case NodeConstraint: result = constraint( n, role ); break;
2153 case NodeConstraintStart: result = constraintStartTime( n, role ); break;
2154 case NodeConstraintEnd: result = constraintEndTime( n, role ); break;
2155 case NodeRunningAccount: result = runningAccount( n, role ); break;
2156 case NodeStartupAccount: result = startupAccount( n, role ); break;
2157 case NodeStartupCost: result = startupCost( n, role ); break;
2158 case NodeShutdownAccount: result = shutdownAccount( n, role ); break;
2159 case NodeShutdownCost: result = shutdownCost( n, role ); break;
2160 case NodeDescription: result = description( n, role ); break;
2161
2162 // Based on edited values
2163 case NodeExpected: result = pertExpected( n->estimate(), role ); break;
2164 case NodeVarianceEstimate: result = varianceEstimate( n->estimate(), role ); break;
2165 case NodeOptimistic: result = optimisticEstimate( n->estimate(), role ); break;
2166 case NodePessimistic: result = pessimisticEstimate( n->estimate(), role ); break;
2167
2168 // After scheduling
2169 case NodeStartTime: result = startTime( n, role ); break;
2170 case NodeEndTime: result = endTime( n, role ); break;
2171 case NodeEarlyStart: result = earlyStart( n, role ); break;
2172 case NodeEarlyFinish: result = earlyFinish( n, role ); break;
2173 case NodeLateStart: result = lateStart( n, role ); break;
2174 case NodeLateFinish: result = lateFinish( n, role ); break;
2175 case NodePositiveFloat: result = positiveFloat( n, role ); break;
2176 case NodeFreeFloat: result = freeFloat( n, role ); break;
2177 case NodeNegativeFloat: result = negativeFloat( n, role ); break;
2178 case NodeStartFloat: result = startFloat( n, role ); break;
2179 case NodeFinishFloat: result = finishFloat( n, role ); break;
2180 case NodeAssignments: result = assignedResources( n, role ); break;
2181
2182 // Based on scheduled values
2183 case NodeDuration: result = duration( n, role ); break;
2184 case NodeVarianceDuration: result = varianceDuration( n, role ); break;
2185 case NodeOptimisticDuration: result = optimisticDuration( n, role ); break;
2186 case NodePessimisticDuration: result = pessimisticDuration( n, role ); break;
2187
2188 // Completion
2189 case NodeStatus: result = status( n, role ); break;
2190 case NodeCompleted: result = completed( n, role ); break;
2191 case NodePlannedEffort: result = plannedEffortTo( n, role ); break;
2192 case NodeActualEffort: result = actualEffortTo( n, role ); break;
2193 case NodeRemainingEffort: result = remainingEffort( n, role ); break;
2194 case NodePlannedCost: result = plannedCostTo( n, role ); break;
2195 case NodeActualCost: result = actualCostTo( n, role ); break;
2196 case NodeActualStart: result = startedTime( n, role ); break;
2197 case NodeStarted: result = isStarted( n, role ); break;
2198 case NodeActualFinish: result = finishedTime( n, role ); break;
2199 case NodeFinished: result = isFinished( n, role ); break;
2200 case NodeStatusNote: result = note( n, role ); break;
2201
2202 // Scheduling errors
2203 case NodeSchedulingStatus: result = nodeSchedulingStatus( n, role ); break;
2204 case NodeNotScheduled: result = nodeIsNotScheduled( n, role ); break;
2205 case NodeAssignmentMissing: result = resourceIsMissing( n, role ); break;
2206 case NodeResourceOverbooked: result = resourceIsOverbooked( n, role ); break;
2207 case NodeResourceUnavailable: result = resourceIsNotAvailable( n, role ); break;
2208 case NodeConstraintsError: result = schedulingConstraintsError( n, role ); break;
2209 case NodeEffortNotMet: result = effortNotMet( n, role ); break;
2210 case NodeSchedulingError: result = schedulingError( n, role ); break;
2211
2212 case NodeWBSCode: result = wbsCode( n, role ); break;
2213 case NodeLevel: result = nodeLevel( n, role ); break;
2214
2215 // Performance
2216 case NodeBCWS: result = nodeBCWS( n, role ); break;
2217 case NodeBCWP: result = nodeBCWP( n, role ); break;
2218 case NodeACWP: result = nodeACWP( n, role ); break;
2219 case NodePerformanceIndex: result = nodePerformanceIndex( n, role ); break;
2220 case NodeCritical: result = nodeIsCritical( n, role ); break;
2221 case NodeCriticalPath: result = nodeInCriticalPath( n, role ); break;
2222
2223 case WPOwnerName: result = wpOwnerName( n, role ); break;
2224 case WPTransmitionStatus: result = wpTransmitionStatus( n, role ); break;
2225 case WPTransmitionTime: result = wpTransmitionTime( n, role ); break;
2226
2227 default:
2228 //kDebug(planDbg())<<"Invalid property number: "<<property;;
2229 return result;
2230 }
2231 return result;
2232}
2233
2234int NodeModel::propertyCount() const
2235{
2236 return columnMap().keyCount();
2237}
2238
2239KUndo2Command *NodeModel::setData( Node *node, int property, const QVariant & value, int role )
2240{
2241 switch ( property ) {
2242 case NodeModel::NodeName: return setName( node, value, role );
2243 case NodeModel::NodeType: return setType( node, value, role );
2244 case NodeModel::NodeResponsible: return setLeader( node, value, role );
2245 case NodeModel::NodeAllocation: return setAllocation( node, value, role );
2246 case NodeModel::NodeEstimateType: return setEstimateType( node, value, role );
2247 case NodeModel::NodeEstimateCalendar: return setEstimateCalendar( node, value, role );
2248 case NodeModel::NodeEstimate: return setEstimate( node, value, role );
2249 case NodeModel::NodeOptimisticRatio: return setOptimisticRatio( node, value, role );
2250 case NodeModel::NodePessimisticRatio: return setPessimisticRatio( node, value, role );
2251 case NodeModel::NodeRisk: return setRiskType( node, value, role );
2252 case NodeModel::NodeConstraint: return setConstraint( node, value, role );
2253 case NodeModel::NodeConstraintStart: return setConstraintStartTime( node, value, role );
2254 case NodeModel::NodeConstraintEnd: return setConstraintEndTime( node, value, role );
2255 case NodeModel::NodeRunningAccount: return setRunningAccount( node, value, role );
2256 case NodeModel::NodeStartupAccount: return setStartupAccount( node, value, role );
2257 case NodeModel::NodeStartupCost: return setStartupCost( node, value, role );
2258 case NodeModel::NodeShutdownAccount: return setShutdownAccount( node, value, role );
2259 case NodeModel::NodeShutdownCost: return setShutdownCost( node, value, role );
2260 case NodeModel::NodeDescription: return setDescription( node, value, role );
2261 case NodeModel::NodeCompleted: return setCompletion( node, value, role );
2262 case NodeModel::NodeActualEffort: return setActualEffort( node, value, role );
2263 case NodeModel::NodeRemainingEffort: return setRemainingEffort( node, value, role );
2264 case NodeModel::NodeActualStart: return setStartedTime( node, value, role );
2265 case NodeModel::NodeActualFinish: return setFinishedTime( node, value, role );
2266 default:
2267 qWarning("data: invalid display value column %d", property);
2268 return 0;
2269 }
2270 return 0;
2271}
2272
2273QVariant NodeModel::headerData( int section, int role )
2274{
2275 if ( role == Qt::DisplayRole ) {
2276 switch ( section ) {
2277 case NodeName: return i18nc( "@title:column", "Name" );
2278 case NodeType: return i18nc( "@title:column", "Type" );
2279 case NodeResponsible: return i18nc( "@title:column", "Responsible" );
2280 case NodeAllocation: return i18nc( "@title:column", "Allocation" );
2281 case NodeEstimateType: return i18nc( "@title:column", "Estimate Type" );
2282 case NodeEstimateCalendar: return i18nc( "@title:column", "Calendar" );
2283 case NodeEstimate: return i18nc( "@title:column", "Estimate" );
2284 case NodeOptimisticRatio: return i18nc( "@title:column", "Optimistic" ); // Ratio
2285 case NodePessimisticRatio: return i18nc( "@title:column", "Pessimistic" ); // Ratio
2286 case NodeRisk: return i18nc( "@title:column", "Risk" );
2287 case NodeConstraint: return i18nc( "@title:column", "Constraint" );
2288 case NodeConstraintStart: return i18nc( "@title:column", "Constraint Start" );
2289 case NodeConstraintEnd: return i18nc( "@title:column", "Constraint End" );
2290 case NodeRunningAccount: return i18nc( "@title:column", "Running Account" );
2291 case NodeStartupAccount: return i18nc( "@title:column", "Startup Account" );
2292 case NodeStartupCost: return i18nc( "@title:column", "Startup Cost" );
2293 case NodeShutdownAccount: return i18nc( "@title:column", "Shutdown Account" );
2294 case NodeShutdownCost: return i18nc( "@title:column", "Shutdown Cost" );
2295 case NodeDescription: return i18nc( "@title:column", "Description" );
2296
2297 // Based on edited values
2298 case NodeExpected: return i18nc( "@title:column", "Expected" );
2299 case NodeVarianceEstimate: return i18nc( "@title:column", "Variance (Est)" );
2300 case NodeOptimistic: return i18nc( "@title:column", "Optimistic" );
2301 case NodePessimistic: return i18nc( "@title:column", "Pessimistic" );
2302
2303 // After scheduling
2304 case NodeStartTime: return i18nc( "@title:column", "Start Time" );
2305 case NodeEndTime: return i18nc( "@title:column", "End Time" );
2306 case NodeEarlyStart: return i18nc( "@title:column", "Early Start" );
2307 case NodeEarlyFinish: return i18nc( "@title:column", "Early Finish" );
2308 case NodeLateStart: return i18nc( "@title:column", "Late Start" );
2309 case NodeLateFinish: return i18nc( "@title:column", "Late Finish" );
2310 case NodePositiveFloat: return i18nc( "@title:column", "Positive Float" );
2311 case NodeFreeFloat: return i18nc( "@title:column", "Free Float" );
2312 case NodeNegativeFloat: return i18nc( "@title:column", "Negative Float" );
2313 case NodeStartFloat: return i18nc( "@title:column", "Start Float" );
2314 case NodeFinishFloat: return i18nc( "@title:column", "Finish Float" );
2315 case NodeAssignments: return i18nc( "@title:column", "Assignments" );
2316
2317 // Based on scheduled values
2318 case NodeDuration: return i18nc( "@title:column", "Duration" );
2319 case NodeVarianceDuration: return i18nc( "@title:column", "Variance (Dur)" );
2320 case NodeOptimisticDuration: return i18nc( "@title:column", "Optimistic (Dur)" );
2321 case NodePessimisticDuration: return i18nc( "@title:column", "Pessimistic (Dur)" );
2322
2323 // Completion
2324 case NodeStatus: return i18nc( "@title:column", "Status" );
2325 // xgettext: no-c-format
2326 case NodeCompleted: return i18nc( "@title:column", "% Completed" );
2327 case NodePlannedEffort: return i18nc( "@title:column", "Planned Effort" );
2328 case NodeActualEffort: return i18nc( "@title:column", "Actual Effort" );
2329 case NodeRemainingEffort: return i18nc( "@title:column", "Remaining Effort" );
2330 case NodePlannedCost: return i18nc( "@title:column", "Planned Cost" );
2331 case NodeActualCost: return i18nc( "@title:column", "Actual Cost" );
2332 case NodeActualStart: return i18nc( "@title:column", "Actual Start" );
2333 case NodeStarted: return i18nc( "@title:column", "Started" );
2334 case NodeActualFinish: return i18nc( "@title:column", "Actual Finish" );
2335 case NodeFinished: return i18nc( "@title:column", "Finished" );
2336 case NodeStatusNote: return i18nc( "@title:column", "Status Note" );
2337
2338 // Scheduling errors
2339 case NodeSchedulingStatus: return i18nc( "@title:column", "Scheduling Status" );
2340 case NodeNotScheduled: return i18nc( "@title:column", "Not Scheduled" );
2341 case NodeAssignmentMissing: return i18nc( "@title:column", "Assignment Missing" );
2342 case NodeResourceOverbooked: return i18nc( "@title:column", "Resource Overbooked" );
2343 case NodeResourceUnavailable: return i18nc( "@title:column", "Resource Unavailable" );
2344 case NodeConstraintsError: return i18nc( "@title:column", "Constraints Error" );
2345 case NodeEffortNotMet: return i18nc( "@title:column", "Effort Not Met" );
2346 case NodeSchedulingError: return i18nc( "@title:column", "Scheduling Error" );
2347
2348 case NodeWBSCode: return i18nc( "@title:column", "WBS Code" );
2349 case NodeLevel: return i18nc( "@title:column Node level", "Level" );
2350
2351 // Performance
2352 case NodeBCWS: return i18nc( "@title:column Budgeted Cost of Work Scheduled", "BCWS" );
2353 case NodeBCWP: return i18nc( "@title:column Budgeted Cost of Work Performed", "BCWP" );
2354 case NodeACWP: return i18nc( "@title:column Actual Cost of Work Performed", "ACWP" );
2355 case NodePerformanceIndex: return i18nc( "@title:column Schedule Performance Index", "SPI" );
2356 case NodeCritical: return i18nc( "@title:column", "Critical" );
2357 case NodeCriticalPath: return i18nc( "@title:column", "Critical Path" );
2358
2359 // Work package handling
2360 case WPOwnerName: return i18nc( "@title:column", "Owner" );
2361 case WPTransmitionStatus: return i18nc( "@title:column", "Status" );
2362 case WPTransmitionTime: return i18nc( "@title:column", "Time" );
2363
2364 default: return QVariant();
2365 }
2366 }
2367 if ( role == Qt::ToolTipRole ) {
2368 switch ( section ) {
2369 case NodeName: return ToolTip::nodeName();
2370 case NodeType: return ToolTip::nodeType();
2371 case NodeResponsible: return ToolTip::nodeResponsible();
2372 case NodeAllocation: return ToolTip::allocation();
2373 case NodeEstimateType: return ToolTip::estimateType();
2374 case NodeEstimateCalendar: return ToolTip::estimateCalendar();
2375 case NodeEstimate: return ToolTip::estimate();
2376 case NodeOptimisticRatio: return ToolTip::optimisticRatio();
2377 case NodePessimisticRatio: return ToolTip::pessimisticRatio();
2378 case NodeRisk: return ToolTip::riskType();
2379 case NodeConstraint: return ToolTip::nodeConstraint();
2380 case NodeConstraintStart: return ToolTip::nodeConstraintStart();
2381 case NodeConstraintEnd: return ToolTip::nodeConstraintEnd();
2382 case NodeRunningAccount: return ToolTip::nodeRunningAccount();
2383 case NodeStartupAccount: return ToolTip::nodeStartupAccount();
2384 case NodeStartupCost: return ToolTip::nodeStartupCost();
2385 case NodeShutdownAccount: return ToolTip::nodeShutdownAccount();
2386 case NodeShutdownCost: return ToolTip::nodeShutdownCost();
2387 case NodeDescription: return ToolTip::nodeDescription();
2388
2389 // Based on edited values
2390 case NodeExpected: return ToolTip::estimateExpected();
2391 case NodeVarianceEstimate: return ToolTip::estimateVariance();
2392 case NodeOptimistic: return ToolTip::estimateOptimistic();
2393 case NodePessimistic: return ToolTip::estimatePessimistic();
2394
2395 // After scheduling
2396 case NodeStartTime: return ToolTip::nodeStartTime();
2397 case NodeEndTime: return ToolTip::nodeEndTime();
2398 case NodeEarlyStart: return ToolTip::nodeEarlyStart();
2399 case NodeEarlyFinish: return ToolTip::nodeEarlyFinish();
2400 case NodeLateStart: return ToolTip::nodeLateStart();
2401 case NodeLateFinish: return ToolTip::nodeLateFinish();
2402 case NodePositiveFloat: return ToolTip::nodePositiveFloat();
2403 case NodeFreeFloat: return ToolTip::nodeFreeFloat();
2404 case NodeNegativeFloat: return ToolTip::nodeNegativeFloat();
2405 case NodeStartFloat: return ToolTip::nodeStartFloat();
2406 case NodeFinishFloat: return ToolTip::nodeFinishFloat();
2407 case NodeAssignments: return ToolTip::nodeAssignment();
2408
2409 // Based on scheduled values
2410 case NodeDuration: return ToolTip::nodeDuration();
2411 case NodeVarianceDuration: return ToolTip::nodeVarianceDuration();
2412 case NodeOptimisticDuration: return ToolTip::nodeOptimisticDuration();
2413 case NodePessimisticDuration: return ToolTip::nodePessimisticDuration();
2414
2415 // Completion
2416 case NodeStatus: return ToolTip::nodeStatus();
2417 case NodeCompleted: return ToolTip::nodeCompletion();
2418 case NodePlannedEffort: return ToolTip::nodePlannedEffortTo();
2419 case NodeActualEffort: return ToolTip::nodeActualEffortTo();
2420 case NodeRemainingEffort: return ToolTip::nodeRemainingEffort();
2421 case NodePlannedCost: return ToolTip::nodePlannedCostTo();
2422 case NodeActualCost: return ToolTip::nodeActualCostTo();
2423 case NodeActualStart: return ToolTip::completionStartedTime();
2424 case NodeStarted: return ToolTip::completionStarted();
2425 case NodeActualFinish: return ToolTip::completionFinishedTime();
2426 case NodeFinished: return ToolTip::completionFinished();
2427 case NodeStatusNote: return ToolTip::completionStatusNote();
2428
2429 // Scheduling errors
2430 case NodeSchedulingStatus: return ToolTip::nodeSchedulingStatus();
2431 case NodeNotScheduled: return ToolTip::nodeNotScheduled();
2432 case NodeAssignmentMissing: return ToolTip::nodeAssignmentMissing();
2433 case NodeResourceOverbooked: return ToolTip::nodeResourceOverbooked();
2434 case NodeResourceUnavailable: return ToolTip::nodeResourceUnavailable();
2435 case NodeConstraintsError: return ToolTip::nodeConstraintsError();
2436 case NodeEffortNotMet: return ToolTip::nodeEffortNotMet();
2437 case NodeSchedulingError: return ToolTip::nodeSchedulingError();
2438
2439 case NodeWBSCode: return ToolTip::nodeWBS();
2440 case NodeLevel: return ToolTip::nodeLevel();
2441
2442 // Performance
2443 case NodeBCWS: return ToolTip::nodeBCWS();
2444 case NodeBCWP: return ToolTip::nodeBCWP();
2445 case NodeACWP: return ToolTip::nodeACWP();
2446 case NodePerformanceIndex: return ToolTip::nodePerformanceIndex();
2447
2448 // Work package handling FIXME
2449 case WPOwnerName: return i18nc( "@info:tooltip", "Work package owner" );
2450 case WPTransmitionStatus: return i18nc( "@info:tooltip", "Work package status" );
2451 case WPTransmitionTime: return i18nc( "@info:tooltip", "Work package send/receive time" );
2452
2453 default: return QVariant();
2454 }
2455 }
2456 if ( role == Qt::TextAlignmentRole ) {
2457 switch (section) {
2458 case NodeName:
2459 case NodeType:
2460 case NodeResponsible:
2461 case NodeAllocation:
2462 case NodeEstimateType:
2463 case NodeEstimateCalendar:
2464 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2465 case NodeEstimate:
2466 case NodeOptimisticRatio:
2467 case NodePessimisticRatio:
2468 return (int)(Qt::AlignRight|Qt::AlignVCenter); // number
2469 case NodeRisk:
2470 case NodeConstraint:
2471 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2472 case NodeConstraintStart:
2473 case NodeConstraintEnd:
2474 case NodeRunningAccount:
2475 case NodeStartupAccount:
2476 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2477 case NodeStartupCost:
2478 return (int)(Qt::AlignRight|Qt::AlignVCenter); // number
2479 case NodeShutdownAccount:
2480 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2481 case NodeShutdownCost:
2482 return (int)(Qt::AlignRight|Qt::AlignVCenter); // number
2483 case NodeDescription:
2484 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2485
2486 // Based on edited values
2487 case NodeExpected:
2488 case NodeVarianceEstimate:
2489 case NodeOptimistic:
2490 case NodePessimistic:
2491 return (int)(Qt::AlignRight|Qt::AlignVCenter); // number
2492
2493 // After scheduling
2494 case NodeStartTime:
2495 case NodeEndTime:
2496 case NodeEarlyStart:
2497 case NodeEarlyFinish:
2498 case NodeLateStart:
2499 case NodeLateFinish:
2500 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2501 case NodePositiveFloat:
2502 case NodeFreeFloat:
2503 case NodeNegativeFloat:
2504 case NodeStartFloat:
2505 case NodeFinishFloat:
2506 return (int)(Qt::AlignRight|Qt::AlignVCenter); // number
2507 case NodeAssignments:
2508 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2509
2510 // Based on scheduled values
2511 case NodeDuration:
2512 case NodeVarianceDuration:
2513 case NodeOptimisticDuration:
2514 case NodePessimisticDuration:
2515 return (int)(Qt::AlignRight|Qt::AlignVCenter); // number
2516
2517 // Completion
2518 case NodeStatus:
2519 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2520 case NodeCompleted:
2521 return (int)(Qt::AlignCenter); // special, presented as a bar
2522 case NodePlannedEffort:
2523 case NodeActualEffort:
2524 case NodeRemainingEffort:
2525 case NodePlannedCost:
2526 case NodeActualCost:
2527 return (int)(Qt::AlignRight|Qt::AlignVCenter); // number
2528 case NodeActualStart:
2529 case NodeStarted:
2530 case NodeActualFinish:
2531 case NodeFinished:
2532 case NodeStatusNote:
2533 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2534
2535 // Scheduling errors
2536 case NodeSchedulingStatus:
2537 case NodeNotScheduled:
2538 case NodeAssignmentMissing:
2539 case NodeResourceOverbooked:
2540 case NodeResourceUnavailable:
2541 case NodeConstraintsError:
2542 case NodeEffortNotMet:
2543 case NodeSchedulingError:
2544 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2545
2546 case NodeWBSCode:
2547 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2548 case NodeLevel:
2549 return (int)(Qt::AlignRight|Qt::AlignVCenter); // number
2550
2551 // Performance
2552 case NodeBCWS:
2553 case NodeBCWP:
2554 case NodeACWP:
2555 case NodePerformanceIndex:
2556 return (int)(Qt::AlignRight|Qt::AlignVCenter); // number
2557 case NodeCritical:
2558 case NodeCriticalPath:
2559 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2560
2561 case WPOwnerName:
2562 case WPTransmitionStatus:
2563 case WPTransmitionTime:
2564 return (int)(Qt::AlignLeft|Qt::AlignVCenter);
2565 default:
2566 return QVariant();
2567 }
2568 }
2569 if ( role == Qt::WhatsThisRole ) {
2570 switch ( section ) {
2571 case NodeNegativeFloat: return WhatsThis::nodeNegativeFloat();
2572
2573 default: return QVariant();
2574 }
2575 }
2576 return QVariant();
2577}
2578
2579KUndo2Command *NodeModel::setName( Node *node, const QVariant &value, int role )
2580{
2581 switch ( role ) {
2582 case Qt::EditRole: {
2583 if ( value.toString() == node->name() ) {
2584 return 0;
2585 }
2586 KUndo2MagicString s = kundo2_i18n( "Modify name" );
2587 switch ( node->type() ) {
2588 case Node::Type_Task: s = kundo2_i18n( "Modify task name" ); break;
2589 case Node::Type_Milestone: s = kundo2_i18n( "Modify milestone name" ); break;
2590 case Node::Type_Summarytask: s = kundo2_i18n( "Modify summarytask name" ); break;
2591 case Node::Type_Project: s = kundo2_i18n( "Modify project name" ); break;
2592 }
2593 return new NodeModifyNameCmd( *node, value.toString(), s );
2594 }
2595 }
2596 return 0;
2597}
2598
2599KUndo2Command *NodeModel::setLeader( Node *node, const QVariant &value, int role )
2600{
2601 switch ( role ) {
2602 case Qt::EditRole: {
2603 if ( value.toString() != node->leader() ) {
2604 return new NodeModifyLeaderCmd( *node, value.toString(), kundo2_i18n( "Modify responsible" ) );
2605 }
2606 break;
2607 }
2608 default:
2609 break;
2610 }
2611 return 0;
2612}
2613
2614KUndo2Command *NodeModel::setAllocation( Node */*node*/, const QVariant &/*value*/, int /*role*/ )
2615{
2616 return 0;
2617}
2618
2619KUndo2Command *NodeModel::setDescription( Node *node, const QVariant &value, int role )
2620{
2621 switch ( role ) {
2622 case Qt::EditRole:
2623 if ( value.toString() == node->description() ) {
2624 return 0;
2625 }
2626 return new NodeModifyDescriptionCmd( *node, value.toString(), kundo2_i18n( "Modify task description" ) );
2627 }
2628 return 0;
2629}
2630
2631KUndo2Command *NodeModel::setType( Node *, const QVariant &, int )
2632{
2633 return 0;
2634}
2635
2636KUndo2Command *NodeModel::setConstraint( Node *node, const QVariant &value, int role )
2637{
2638 switch ( role ) {
2639 case Qt::EditRole: {
2640 Node::ConstraintType v;
2641 QStringList lst = node->constraintList( false );
2642 if ( lst.contains( value.toString() ) ) {
2643 v = Node::ConstraintType( lst.indexOf( value.toString() ) );
2644 } else {
2645 v = Node::ConstraintType( value.toInt() );
2646 }
2647 //kDebug(planDbg())<<v;
2648 if ( v != node->constraint() ) {
2649 return new NodeModifyConstraintCmd( *node, v, kundo2_i18n( "Modify constraint type" ) );
2650 }
2651 break;
2652 }
2653 default:
2654 break;
2655 }
2656 return 0;
2657}
2658
2659KUndo2Command *NodeModel::setConstraintStartTime( Node *node, const QVariant &value, int role )
2660{
2661 switch ( role ) {
2662 case Qt::EditRole: {
2663 QDateTime dt = value.toDateTime();
2664 dt.setTime( QTime( dt.time().hour(), dt.time().minute() ) ); // reset possible secs/msecs
2665 if ( dt != node->constraintStartTime() ) {
2666 return new NodeModifyConstraintStartTimeCmd( *node, dt, kundo2_i18n( "Modify constraint start time" ) );
2667 }
2668 break;
2669 }
2670 default:
2671 break;
2672 }
2673 return 0;
2674}
2675
2676KUndo2Command *NodeModel::setConstraintEndTime( Node *node, const QVariant &value, int role )
2677{
2678 switch ( role ) {
2679 case Qt::EditRole: {
2680 QDateTime dt = value.toDateTime();
2681 dt.setTime( QTime( dt.time().hour(), dt.time().minute() ) ); // reset possible secs/msecs
2682 if ( dt != node->constraintEndTime() ) {
2683 return new NodeModifyConstraintEndTimeCmd( *node, dt, kundo2_i18n( "Modify constraint end time" ) );
2684 }
2685 break;
2686 }
2687 default:
2688 break;
2689 }
2690 return 0;
2691}
2692
2693KUndo2Command *NodeModel::setEstimateType( Node *node, const QVariant &value, int role )
2694{
2695 if ( node->estimate() == 0 ) {
2696 return 0;
2697 }
2698 switch ( role ) {
2699 case Qt::EditRole: {
2700 Estimate::Type v;
2701 QStringList lst = node->estimate()->typeToStringList( false );
2702 if ( lst.contains( value.toString() ) ) {
2703 v = Estimate::Type( lst.indexOf( value.toString() ) );
2704 } else {
2705 v = Estimate::Type( value.toInt() );
2706 }
2707 if ( v != node->estimate()->type() ) {
2708 return new ModifyEstimateTypeCmd( *node, node->estimate()->type(), v, kundo2_i18n( "Modify estimate type" ) );
2709 }
2710 break;
2711 }
2712 default:
2713 break;
2714 }
2715 return 0;
2716}
2717
2718KUndo2Command *NodeModel::setEstimateCalendar( Node *node, const QVariant &value, int role )
2719{
2720 if ( node->estimate() == 0 ) {
2721 return 0;
2722 }
2723 switch ( role ) {
2724 case Qt::EditRole: {
2725 Calendar *c = 0;
2726 Calendar *old = node->estimate()->calendar();
2727 if ( value.toInt() > 0 ) {
2728 QStringList lst = estimateCalendar( node, Role::EnumList ).toStringList();
2729 if ( value.toInt() < lst.count() ) {
2730 c = m_project->calendarByName( lst.at( value.toInt() ) );
2731 }
2732 }
2733 if ( c != old ) {
2734 return new ModifyEstimateCalendarCmd( *node, old, c, kundo2_i18n( "Modify estimate calendar" ) );
2735 }
2736 break;
2737 }
2738 default:
2739 break;
2740 }
2741 return 0;
2742}
2743
2744KUndo2Command *NodeModel::setEstimate( Node *node, const QVariant &value, int role )
2745{
2746 if ( node->estimate() == 0 ) {
2747 return 0;
2748 }
2749 switch ( role ) {
2750 case Qt::EditRole: {
2751 double d;
2752 Duration::Unit unit;
2753 if ( value.toList().count() == 2 ) {
2754 d = value.toList()[0].toDouble();
2755 unit = static_cast<Duration::Unit>( value.toList()[1].toInt() );
2756 } else if ( value.canConvert<QString>() ) {
2757 bool ok = Duration::valueFromString( value.toString(), d, unit );
2758 if ( ! ok ) {
2759 return 0;
2760 }
2761 } else {
2762 return 0;
2763 }
2764 //kDebug(planDbg())<<d<<","<<unit<<" ->"<<value.toList()[1].toInt();
2765 MacroCommand *cmd = 0;
2766 if ( d != node->estimate()->expectedEstimate() ) {
2767 if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Modify estimate" ) );
2768 cmd->addCommand( new ModifyEstimateCmd( *node, node->estimate()->expectedEstimate(), d ) );
2769 }
2770 if ( unit != node->estimate()->unit() ) {
2771 if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Modify estimate" ) );
2772 cmd->addCommand( new ModifyEstimateUnitCmd( *node, node->estimate()->unit(), unit ) );
2773 }
2774 if ( cmd ) {
2775 return cmd;
2776 }
2777 break;
2778 }
2779 default:
2780 break;
2781 }
2782 return 0;
2783}
2784
2785KUndo2Command *NodeModel::setOptimisticRatio( Node *node, const QVariant &value, int role )
2786{
2787 if ( node->estimate() == 0 ) {
2788 return 0;
2789 }
2790 switch ( role ) {
2791 case Qt::EditRole:
2792 if ( value.toInt() != node->estimate()->optimisticRatio() ) {
2793 return new EstimateModifyOptimisticRatioCmd( *node, node->estimate()->optimisticRatio(), value.toInt(), kundo2_i18n( "Modify optimistic estimate" ) );
2794 }
2795 break;
2796 default:
2797 break;
2798 }
2799 return 0;
2800}
2801
2802KUndo2Command *NodeModel::setPessimisticRatio( Node *node, const QVariant &value, int role )
2803{
2804 if ( node->estimate() == 0 ) {
2805 return 0;
2806 }
2807 switch ( role ) {
2808 case Qt::EditRole:
2809 if ( value.toInt() != node->estimate()->pessimisticRatio() ) {
2810 return new EstimateModifyPessimisticRatioCmd( *node, node->estimate()->pessimisticRatio(), value.toInt(), kundo2_i18n( "Modify pessimistic estimate" ) );
2811 }
2812 default:
2813 break;
2814 }
2815 return 0;
2816}
2817
2818KUndo2Command *NodeModel::setRiskType( Node *node, const QVariant &value, int role )
2819{
2820 if ( node->estimate() == 0 ) {
2821 return 0;
2822 }
2823 switch ( role ) {
2824 case Qt::EditRole: {
2825 int val = 0;
2826 QStringList lst = node->estimate()->risktypeToStringList( false );
2827 if ( lst.contains( value.toString() ) ) {
2828 val = lst.indexOf( value.toString() );
2829 } else {
2830 val = value.toInt();
2831 }
2832 if ( val != node->estimate()->risktype() ) {
2833 Estimate::Risktype v = Estimate::Risktype( val );
2834 return new EstimateModifyRiskCmd( *node, node->estimate()->risktype(), v, kundo2_i18n( "Modify risk type" ) );
2835 }
2836 break;
2837 }
2838 default:
2839 break;
2840 }
2841 return 0;
2842}
2843
2844KUndo2Command *NodeModel::setRunningAccount( Node *node, const QVariant &value, int role )
2845{
2846 switch ( role ) {
2847 case Qt::EditRole: {
2848 //kDebug(planDbg())<<node->name();
2849 QStringList lst = runningAccount( node, Role::EnumList ).toStringList();
2850 if ( value.toInt() < lst.count() ) {
2851 Account *a = m_project->accounts().findAccount( lst.at( value.toInt() ) );
2852 Account *old = node->runningAccount();
2853 if ( old != a ) {
2854 return new NodeModifyRunningAccountCmd( *node, old, a, kundo2_i18n( "Modify running account" ) );
2855 }
2856 }
2857 break;
2858 }
2859 default:
2860 break;
2861 }
2862 return 0;
2863}
2864
2865KUndo2Command *NodeModel::setStartupAccount( Node *node, const QVariant &value, int role )
2866{
2867 switch ( role ) {
2868 case Qt::EditRole: {
2869 //kDebug(planDbg())<<node->name();
2870 QStringList lst = startupAccount( node, Role::EnumList ).toStringList();
2871 if ( value.toInt() < lst.count() ) {
2872 Account *a = m_project->accounts().findAccount( lst.at( value.toInt() ) );
2873 Account *old = node->startupAccount();
2874 //kDebug(planDbg())<<(value.toInt())<<";"<<(lst.at( value.toInt()))<<":"<<a;
2875 if ( old != a ) {
2876 return new NodeModifyStartupAccountCmd( *node, old, a, kundo2_i18n( "Modify startup account" ) );
2877 }
2878 }
2879 break;
2880 }
2881 default:
2882 break;
2883 }
2884 return 0;
2885}
2886
2887KUndo2Command *NodeModel::setStartupCost( Node *node, const QVariant &value, int role )
2888{
2889 switch ( role ) {
2890 case Qt::EditRole: {
2891 double v = KGlobal::locale()->readMoney( value.toString() );
2892 if ( v != node->startupCost() ) {
2893 return new NodeModifyStartupCostCmd( *node, v, kundo2_i18n( "Modify startup cost" ) );
2894 }
2895 break;
2896 }
2897 default:
2898 break;
2899 }
2900 return 0;
2901}
2902
2903KUndo2Command *NodeModel::setShutdownAccount( Node *node, const QVariant &value, int role )
2904{
2905 switch ( role ) {
2906 case Qt::EditRole: {
2907 //kDebug(planDbg())<<node->name();
2908 QStringList lst = shutdownAccount( node, Role::EnumList ).toStringList();
2909 if ( value.toInt() < lst.count() ) {
2910 Account *a = m_project->accounts().findAccount( lst.at( value.toInt() ) );
2911 Account *old = node->shutdownAccount();
2912 if ( old != a ) {
2913 return new NodeModifyShutdownAccountCmd( *node, old, a, kundo2_i18n( "Modify shutdown account" ) );
2914 }
2915 }
2916 break;
2917 }
2918 default:
2919 break;
2920 }
2921 return 0;
2922}
2923
2924KUndo2Command *NodeModel::setShutdownCost( Node *node, const QVariant &value, int role )
2925{
2926 switch ( role ) {
2927 case Qt::EditRole: {
2928 double v = KGlobal::locale()->readMoney( value.toString() );
2929 if ( v != node->shutdownCost() ) {
2930 return new NodeModifyShutdownCostCmd( *node, v, kundo2_i18n( "Modify shutdown cost" ) );
2931 }
2932 break;
2933 }
2934 default:
2935 break;
2936 }
2937 return 0;
2938}
2939
2940KUndo2Command *NodeModel::setCompletion( Node */*node*/, const QVariant &/*value*/, int /*role*/ )
2941{
2942 return 0;
2943}
2944
2945KUndo2Command *NodeModel::setRemainingEffort( Node *node, const QVariant &value, int role )
2946{
2947 if ( role == Qt::EditRole && node->type() == Node::Type_Task ) {
2948 Task *t = static_cast<Task*>( node );
2949 double d( value.toList()[0].toDouble() );
2950 Duration::Unit unit = static_cast<Duration::Unit>( value.toList()[1].toInt() );
2951 Duration dur( d, unit );
2952 return new ModifyCompletionRemainingEffortCmd( t->completion(), QDate::currentDate(), dur, kundo2_i18n( "Modify remaining effort" ) );
2953 }
2954 return 0;
2955}
2956
2957KUndo2Command *NodeModel::setActualEffort( Node *node, const QVariant &value, int role )
2958{
2959 if ( role == Qt::EditRole && node->type() == Node::Type_Task ) {
2960 Task *t = static_cast<Task*>( node );
2961 double d( value.toList()[0].toDouble() );
2962 Duration::Unit unit = static_cast<Duration::Unit>( value.toList()[1].toInt() );
2963 Duration dur( d, unit );
2964 return new ModifyCompletionActualEffortCmd( t->completion(), QDate::currentDate(), dur, kundo2_i18n( "Modify actual effort" ) );
2965 }
2966 return 0;
2967}
2968
2969KUndo2Command *NodeModel::setStartedTime( Node *node, const QVariant &value, int role )
2970{
2971 switch ( role ) {
2972 case Qt::EditRole: {
2973 Task *t = qobject_cast<Task*>( node );
2974 if ( t == 0 ) {
2975 return 0;
2976 }
2977 MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify actual start time" ) );
2978 if ( ! t->completion().isStarted() ) {
2979 m->addCommand( new ModifyCompletionStartedCmd( t->completion(), true ) );
2980 }
2981 m->addCommand( new ModifyCompletionStartTimeCmd( t->completion(), value.toDateTime() ) );
2982 if ( t->type() == Node::Type_Milestone ) {
2983 m->addCommand( new ModifyCompletionFinishedCmd( t->completion(), true ) );
2984 m->addCommand( new ModifyCompletionFinishTimeCmd( t->completion(), value.toDateTime() ) );
2985 if ( t->completion().percentFinished() < 100 ) {
2986 Completion::Entry *e = new Completion::Entry( 100, Duration::zeroDuration, Duration::zeroDuration );
2987 m->addCommand( new AddCompletionEntryCmd( t->completion(), value.toDate(), e ) );
2988 }
2989 }
2990 return m;
2991 }
2992 default:
2993 break;
2994 }
2995 return 0;
2996}
2997
2998KUndo2Command *NodeModel::setFinishedTime( Node *node, const QVariant &value, int role )
2999{
3000 switch ( role ) {
3001 case Qt::EditRole: {
3002 Task *t = qobject_cast<Task*>( node );
3003 if ( t == 0 ) {
3004 return 0;
3005 }
3006 MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify actual finish time" ) );
3007 if ( ! t->completion().isFinished() ) {
3008 m->addCommand( new ModifyCompletionFinishedCmd( t->completion(), true ) );
3009 if ( t->completion().percentFinished() < 100 ) {
3010 Completion::Entry *e = new Completion::Entry( 100, Duration::zeroDuration, Duration::zeroDuration );
3011 m->addCommand( new AddCompletionEntryCmd( t->completion(), value.toDate(), e ) );
3012 }
3013 }
3014 m->addCommand( new ModifyCompletionFinishTimeCmd( t->completion(), value.toDateTime() ) );
3015 if ( t->type() == Node::Type_Milestone ) {
3016 m->addCommand( new ModifyCompletionStartedCmd( t->completion(), true ) );
3017 m->addCommand( new ModifyCompletionStartTimeCmd( t->completion(), value.toDateTime() ) );
3018 }
3019 return m;
3020 }
3021 default:
3022 break;
3023 }
3024 return 0;
3025}
3026
3027//----------------------------
3028NodeItemModel::NodeItemModel( QObject *parent )
3029 : ItemModelBase( parent ),
3030 m_node( 0 ),
3031 m_projectshown( false )
3032{
3033 setReadOnly( NodeModel::NodeDescription, true );
3034}
3035
3036NodeItemModel::~NodeItemModel()
3037{
3038}
3039
3040void NodeItemModel::setShowProject( bool on )
3041{
3042 m_projectshown = on;
3043 reset();
3044 emit projectShownChanged( on );
3045}
3046
3047void NodeItemModel::slotNodeToBeInserted( Node *parent, int row )
3048{
3049 //kDebug(planDbg())<<parent->name()<<"; "<<row;
3050 Q_ASSERT( m_node == 0 );
3051 m_node = parent;
3052 beginInsertRows( index( parent ), row, row );
3053}
3054
3055void NodeItemModel::slotNodeInserted( Node *node )
3056{
3057 //kDebug(planDbg())<<node->parentNode()->name()<<"-->"<<node->name();
3058 Q_ASSERT( node->parentNode() == m_node );
3059 endInsertRows();
3060 m_node = 0;
3061 emit nodeInserted( node );
3062}
3063
3064void NodeItemModel::slotNodeToBeRemoved( Node *node )
3065{
3066 //kDebug(planDbg())<<node->name();
3067 Q_ASSERT( m_node == 0 );
3068 m_node = node;
3069 int row = index( node ).row();
3070 beginRemoveRows( index( node->parentNode() ), row, row );
3071}
3072
3073void NodeItemModel::slotNodeRemoved( Node *node )
3074{
3075 //kDebug(planDbg())<<node->name();
3076 Q_ASSERT( node == m_node );
3077#ifdef NDEBUG
3078 Q_UNUSED(node)
3079#endif
3080 endRemoveRows();
3081 m_node = 0;
3082}
3083
3084void NodeItemModel::slotNodeToBeMoved( Node *node, int pos, Node *newParent, int newPos )
3085{
3086 //kDebug(planDbg())<<node->parentNode()->name()<<pos<<":"<<newParent->name()<<newPos;
3087 beginMoveRows( index( node->parentNode() ), pos, pos, index( newParent ), newPos );
3088}
3089
3090void NodeItemModel::slotNodeMoved( Node *node )
3091{
3092 Q_UNUSED( node );
3093 //kDebug(planDbg())<<node->parentNode()->name()<<node->parentNode()->indexOf( node );
3094 endMoveRows();
3095}
3096
3097void NodeItemModel::slotLayoutChanged()
3098{
3099 //kDebug(planDbg())<<node->name();
3100 emit layoutAboutToBeChanged();
3101 emit layoutChanged();
3102}
3103
3104void NodeItemModel::slotProjectCalulated(ScheduleManager *sm)
3105{
3106 kDebug(planDbg())<<m_manager<<sm;
3107 if ( sm && sm == m_manager ) {
3108 slotLayoutChanged();
3109 }
3110}
3111
3112void NodeItemModel::slotWbsDefinitionChanged()
3113{
3114 kDebug(planDbg());
3115 if ( m_project == 0 ) {
3116 return;
3117 }
3118 if ( m_projectshown ) {
3119 QModelIndex idx = createIndex( 0, NodeModel::NodeWBSCode, m_project );
3120 emit dataChanged( idx, idx );
3121 }
3122 foreach ( Node *n, m_project->allNodes() ) {
3123 int row = n->parentNode()->indexOf( n );
3124 QModelIndex idx = createIndex( row, NodeModel::NodeWBSCode, n );
3125 emit dataChanged( idx, idx );
3126 }
3127}
3128
3129
3130void NodeItemModel::setProject( Project *project )
3131{
3132 if ( m_project ) {
3133 disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) );
3134 disconnect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged()) );
3135 disconnect( m_project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)) );
3136 disconnect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) );
3137 disconnect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) );
3138
3139 disconnect( m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int)) );
3140 disconnect( m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*)) );
3141
3142 disconnect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) );
3143 disconnect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) );
3144 disconnect( m_project, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalulated(ScheduleManager*)));
3145 }
3146 m_project = project;
3147 kDebug(planDbg())<<this<<m_project<<"->"<<project;
3148 m_nodemodel.setProject( project );
3149 if ( project ) {
3150 connect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) );
3151 connect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged()) );
3152 connect( m_project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)) );
3153 connect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) );
3154 connect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) );
3155
3156 connect( m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int)) );
3157 connect( m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*)) );
3158
3159 connect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) );
3160 connect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) );
3161 connect( m_project, SIGNAL(projectCalculated(ScheduleManager*)), this, SLOT(slotProjectCalulated(ScheduleManager*)));
3162 }
3163 reset();
3164}
3165
3166void NodeItemModel::setScheduleManager( ScheduleManager *sm )
3167{
3168 if ( m_nodemodel.manager() ) {
3169 }
3170 m_nodemodel.setManager( sm );
3171 ItemModelBase::setScheduleManager( sm );
3172 if ( sm ) {
3173 }
3174 kDebug(planDbg())<<this<<sm;
3175 reset();
3176}
3177
3178Qt::ItemFlags NodeItemModel::flags( const QModelIndex &index ) const
3179{
3180 Qt::ItemFlags flags = QAbstractItemModel::flags( index );
3181 if ( !index.isValid() ) {
3182 if ( m_readWrite ) {
3183 flags |= Qt::ItemIsDropEnabled;
3184 }
3185 return flags;
3186 }
3187 if ( isColumnReadOnly( index.column() ) ) {
3188 //kDebug(planDbg())<<"Column is readonly:"<<index.column();
3189 return flags;
3190 }
3191 Node *n = node( index );
3192 if ( m_readWrite && n != 0 ) {
3193 bool baselined = n->isBaselined();
3194 flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
3195 switch ( index.column() ) {
3196 case NodeModel::NodeName: // name
3197 flags |= Qt::ItemIsEditable;
3198 break;
3199 case NodeModel::NodeType: break; // Node type
3200 case NodeModel::NodeResponsible: // Responsible
3201 flags |= Qt::ItemIsEditable;
3202 break;
3203 case NodeModel::NodeAllocation: // allocation
3204 if ( n->type() == Node::Type_Task ) {
3205 flags |= Qt::ItemIsEditable;
3206 }
3207 break;
3208 case NodeModel::NodeEstimateType: // estimateType
3209 {
3210 if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) {
3211 flags |= Qt::ItemIsEditable;
3212 }
3213 break;
3214 }
3215 case NodeModel::NodeEstimate: // estimate
3216 {
3217 if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) {
3218 flags |= Qt::ItemIsEditable;
3219 }
3220 break;
3221 }
3222 case NodeModel::NodeOptimisticRatio: // optimisticRatio
3223 case NodeModel::NodePessimisticRatio: // pessimisticRatio
3224 {
3225 if ( ! baselined && n->type() == Node::Type_Task ) {
3226 flags |= Qt::ItemIsEditable;
3227 }
3228 break;
3229 }
3230 case NodeModel::NodeEstimateCalendar:
3231 {
3232 if ( ! baselined && n->type() == Node::Type_Task )
3233 {
3234 flags |= Qt::ItemIsEditable;
3235 }
3236 break;
3237 }
3238 case NodeModel::NodeRisk: // risktype
3239 {
3240 if ( ! baselined && n->type() == Node::Type_Task ) {
3241 flags |= Qt::ItemIsEditable;
3242 }
3243 break;
3244 }
3245 case NodeModel::NodeConstraint: // constraint type
3246 if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) {
3247 flags |= Qt::ItemIsEditable;
3248 }
3249 break;
3250 case NodeModel::NodeConstraintStart: { // constraint start
3251 if ( ! baselined && n->type() == Node::Type_Project ) {
3252 flags |= Qt::ItemIsEditable;
3253 break;
3254 }
3255 if ( ! baselined && ! ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) {
3256 break;
3257 }
3258 flags |= Qt::ItemIsEditable;
3259 break;
3260 }
3261 case NodeModel::NodeConstraintEnd: { // constraint end
3262 if ( ! baselined && n->type() == Node::Type_Project ) {
3263 flags |= Qt::ItemIsEditable;
3264 break;
3265 }
3266 if ( ! baselined && ! ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) {
3267 break;
3268 }
3269 flags |= Qt::ItemIsEditable;
3270 break;
3271 }
3272 case NodeModel::NodeRunningAccount: // running account
3273 if ( ! baselined && n->type() == Node::Type_Task ) {
3274 flags |= Qt::ItemIsEditable;
3275 }
3276 break;
3277 case NodeModel::NodeStartupAccount: // startup account
3278 case NodeModel::NodeStartupCost: // startup cost
3279 case NodeModel::NodeShutdownAccount: // shutdown account
3280 case NodeModel::NodeShutdownCost: { // shutdown cost
3281 if ( ! baselined && ( n->type() == Node::Type_Task || n->type() == Node::Type_Milestone ) ) {
3282 flags |= Qt::ItemIsEditable;
3283 }
3284 break;
3285 }
3286 case NodeModel::NodeDescription: // description
3287 flags |= Qt::ItemIsEditable;
3288 break;
3289 default:
3290 break;
3291 }
3292 Task *t = static_cast<Task*>( n );
3293 if ( manager() && t->isScheduled( id() ) ) {
3294 if ( ! t->completion().isStarted() ) {
3295 switch ( index.column() ) {
3296 case NodeModel::NodeActualStart:
3297 flags |= Qt::ItemIsEditable;
3298 break;
3299 case NodeModel::NodeActualFinish:
3300 if ( t->type() == Node::Type_Milestone ) {
3301 flags |= Qt::ItemIsEditable;
3302 }
3303 break;
3304 case NodeModel::NodeCompleted:
3305 if ( t->state() & Node::State_ReadyToStart ) {
3306 flags |= Qt::ItemIsEditable;
3307 }
3308 break;
3309
3310 default: break;
3311 }
3312 } else if ( ! t->completion().isFinished() ) {
3313 switch ( index.column() ) {
3314 case NodeModel::NodeActualFinish:
3315 case NodeModel::NodeCompleted:
3316 case NodeModel::NodeRemainingEffort:
3317 flags |= Qt::ItemIsEditable;
3318 break;
3319 case NodeModel::NodeActualEffort:
3320 if ( t->completion().entrymode() == Completion::EnterEffortPerTask || t->completion().entrymode() == Completion::EnterEffortPerResource ) {
3321 flags |= Qt::ItemIsEditable;
3322 }
3323 break;
3324 default: break;
3325 }
3326 }
3327 }
3328 }
3329 return flags;
3330}
3331
3332
3333QModelIndex NodeItemModel::parent( const QModelIndex &index ) const
3334{
3335 if ( ! index.isValid() ) {
3336 return QModelIndex();
3337 }
3338 Node *n = node( index );
3339 if ( n == 0 || n == m_project ) {
3340 return QModelIndex();
3341 }
3342 Node *p = n->parentNode();
3343 if ( p == m_project ) {
3344 return m_projectshown ? createIndex( 0, 0, p ) : QModelIndex();
3345 }
3346 int row = p->parentNode()->indexOf( p );
3347 if ( row == -1 ) {
3348 return QModelIndex();
3349 }
3350 return createIndex( row, 0, p );
3351}
3352
3353QModelIndex NodeItemModel::index( int row, int column, const QModelIndex &parent ) const
3354{
3355 if ( parent.isValid() ) {
3356 Q_ASSERT( parent.model() == this );
3357 }
3358 //kDebug(planDbg())<<parent<<row<<column;
3359 if ( m_project == 0 || column < 0 || column >= columnCount() || row < 0 ) {
3360 //kDebug(planDbg())<<m_project<<parent<<"No index for"<<row<<","<<column;
3361 return QModelIndex();
3362 }
3363 if ( m_projectshown && ! parent.isValid() ) {
3364 return createIndex( row, column, m_project );
3365 }
3366 Node *p = node( parent );
3367 if ( row >= p->numChildren() ) {
3368 kError()<<p->name()<<" row too high"<<row<<","<<column;
3369 return QModelIndex();
3370 }
3371 // now get the internal pointer for the index
3372 Node *n = p->childNode( row );
3373 QModelIndex idx = createIndex(row, column, n);
3374 //kDebug(planDbg())<<idx;
3375 return idx;
3376}
3377
3378QModelIndex NodeItemModel::index( const Node *node, int column ) const
3379{
3380 if ( m_project == 0 || node == 0 ) {
3381 return QModelIndex();
3382 }
3383 Node *par = node->parentNode();
3384 if ( par ) {
3385 //kDebug(planDbg())<<par<<"-->"<<node;
3386 return createIndex( par->indexOf( node ), column, const_cast<Node*>(node) );
3387 }
3388 if ( m_projectshown && node == m_project ) {
3389 return createIndex( 0, column, m_project );
3390 }
3391 //kDebug(planDbg())<<node;
3392 return QModelIndex();
3393}
3394
3395bool NodeItemModel::setType( Node *, const QVariant &, int )
3396{
3397 return false;
3398}
3399
3400bool NodeItemModel::setAllocation( Node *node, const QVariant &value, int role )
3401{
3402 Task *task = qobject_cast<Task*>( node );
3403 if ( task == 0 ) {
3404 return false;
3405 }
3406 switch ( role ) {
3407 case Qt::EditRole:
3408 {
3409 MacroCommand *cmd = 0;
3410 QStringList res = m_project->resourceNameList();
3411 QStringList req = node->requestNameList();
3412 QStringList alloc;
3413 foreach ( const QString &s, value.toString().split( QRegExp(" *, *"), QString::SkipEmptyParts ) ) {
3414 alloc << s.trimmed();
3415 }
3416 // first add all new resources (to "default" group)
3417 ResourceGroup *pargr = m_project->groupByName( i18n( "Resources" ) );
3418 foreach ( const QString &s, alloc ) {
3419 Resource *r = m_project->resourceByName( s.trimmed() );
3420 if ( r != 0 ) {
3421 continue;
3422 }
3423 if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Add resource" ) );
3424 if ( pargr == 0 ) {
3425 pargr = new ResourceGroup();
3426 pargr->setName( i18n( "Resources" ) );
3427 cmd->addCommand( new AddResourceGroupCmd( m_project, pargr ) );
3428 //kDebug(planDbg())<<"add group:"<<pargr->name();
3429 }
3430 r = new Resource();
3431 r->setName( s.trimmed() );
3432 cmd->addCommand( new AddResourceCmd( pargr, r ) );
3433 //kDebug(planDbg())<<"add resource:"<<r->name();
3434 emit executeCommand( cmd );
3435 cmd = 0;
3436 }
3437
3438 KUndo2MagicString c = kundo2_i18n( "Modify resource allocations" );
3439 // Handle deleted requests
3440 foreach ( const QString &s, req ) {
3441 // if a request is not in alloc, it must have been be removed by the user
3442 if ( alloc.indexOf( s ) == -1 ) {
3443 // remove removed resource request
3444 ResourceRequest *r = node->resourceRequest( s );
3445 if ( r ) {
3446 if ( cmd == 0 ) cmd = new MacroCommand( c );
3447 //kDebug(planDbg())<<"delete request:"<<r->resource()->name()<<" group:"<<r->parent()->group()->name();
3448 cmd->addCommand( new RemoveResourceRequestCmd( r->parent(), r ) );
3449 }
3450 }
3451 }
3452 // Handle new requests
3453 QMap<ResourceGroup*, ResourceGroupRequest*> groupmap;
3454 foreach ( const QString &s, alloc ) {
3455 // if an allocation is not in req, it must be added
3456 if ( req.indexOf( s ) == -1 ) {
3457 ResourceGroup *pargr = 0;
3458 Resource *r = m_project->resourceByName( s );
3459 if ( r == 0 ) {
3460 // Handle request to non exixting resource
3461 pargr = m_project->groupByName( i18n( "Resources" ) );
3462 if ( pargr == 0 ) {
3463 pargr = new ResourceGroup();
3464 pargr->setName( i18n( "Resources" ) );
3465 cmd->addCommand( new AddResourceGroupCmd( m_project, pargr ) );
3466 //kDebug(planDbg())<<"add group:"<<pargr->name();
3467 }
3468 r = new Resource();
3469 r->setName( s );
3470 cmd->addCommand( new AddResourceCmd( pargr, r ) );
3471 //kDebug(planDbg())<<"add resource:"<<r->name();
3472 emit executeCommand( cmd );
3473 cmd = 0;
3474 } else {
3475 pargr = r->parentGroup();
3476 //kDebug(planDbg())<<"add '"<<r->name()<<"' to group:"<<pargr;
3477 }
3478 // add request
3479 ResourceGroupRequest *g = node->resourceGroupRequest( pargr );
3480 if ( g == 0 ) {
3481 g = groupmap.value( pargr );
3482 }
3483 if ( g == 0 ) {
3484 // create a group request
3485 if ( cmd == 0 ) cmd = new MacroCommand( c );
3486 g = new ResourceGroupRequest( pargr );
3487 cmd->addCommand( new AddResourceGroupRequestCmd( *task, g ) );
3488 groupmap.insert( pargr, g );
3489 //kDebug(planDbg())<<"add group request:"<<g;
3490 }
3491 if ( cmd == 0 ) cmd = new MacroCommand( c );
3492 cmd->addCommand( new AddResourceRequestCmd( g, new ResourceRequest( r, r->units() ) ) );
3493 //kDebug(planDbg())<<"add request:"<<r->name()<<" group:"<<g;
3494 }
3495 }
3496 if ( cmd ) {
3497 emit executeCommand( cmd );
3498 return true;
3499 }
3500 }
3501 }
3502 return false;
3503}
3504
3505bool NodeItemModel::setCompletion( Node *node, const QVariant &value, int role )
3506{
3507 kDebug(planDbg())<<node->name()<<value<<role;
3508 if ( role != Qt::EditRole ) {
3509 return 0;
3510 }
3511 if ( node->type() == Node::Type_Task ) {
3512 Completion &c = static_cast<Task*>( node )->completion();
3513 QDateTime dt = QDateTime::currentDateTime();
3514 QDate date = dt.date();
3515 MacroCommand *m = new MacroCommand( kundo2_i18n( "Modify completion" ) );
3516 if ( ! c.isStarted() ) {
3517 m->addCommand( new ModifyCompletionStartTimeCmd( c, dt ) );
3518 m->addCommand( new ModifyCompletionStartedCmd( c, true ) );
3519 }
3520 m->addCommand( new ModifyCompletionPercentFinishedCmd( c, date, value.toInt() ) );
3521 if ( value.toInt() == 100 ) {
3522 m->addCommand( new ModifyCompletionFinishTimeCmd( c, dt ) );
3523 m->addCommand( new ModifyCompletionFinishedCmd( c, true ) );
3524 }
3525 emit executeCommand( m ); // also adds a new entry if necessary
3526 if ( c.entrymode() == Completion::EnterCompleted ) {
3527 Duration planned = static_cast<Task*>( node )->plannedEffort( m_nodemodel.id() );
3528 Duration actual = ( planned * value.toInt() ) / 100;
3529 kDebug(planDbg())<<planned.toString()<<value.toInt()<<actual.toString();
3530 NamedCommand *cmd = new ModifyCompletionActualEffortCmd( c, date, actual );
3531 cmd->execute();
3532 m->addCommand( cmd );
3533 cmd = new ModifyCompletionRemainingEffortCmd( c, date, planned - actual );
3534 cmd->execute();
3535 m->addCommand( cmd );
3536 }
3537 return true;
3538 }
3539 if ( node->type() == Node::Type_Milestone ) {
3540 Completion &c = static_cast<Task*>( node )->completion();
3541 if ( value.toInt() > 0 ) {
3542 QDateTime dt = QDateTime::currentDateTime();
3543 QDate date = dt.date();
3544 MacroCommand *m = new MacroCommand( kundo2_i18n( "Set finished" ) );
3545 m->addCommand( new ModifyCompletionStartTimeCmd( c, dt ) );
3546 m->addCommand( new ModifyCompletionStartedCmd( c, true ) );
3547 m->addCommand( new ModifyCompletionFinishTimeCmd( c, dt ) );
3548 m->addCommand( new ModifyCompletionFinishedCmd( c, true ) );
3549 m->addCommand( new ModifyCompletionPercentFinishedCmd( c, date, 100 ) );
3550 emit executeCommand( m ); // also adds a new entry if necessary
3551 return true;
3552 }
3553 return false;
3554 }
3555 return false;
3556}
3557
3558QVariant NodeItemModel::data( const QModelIndex &index, int role ) const
3559{
3560 if ( role == Qt::TextAlignmentRole ) {
3561 return headerData( index.column(), Qt::Horizontal, role );
3562 }
3563 Node *n = node( index );
3564 if ( role == Role::Object ) {
3565 return n ? QVariant::fromValue( static_cast<QObject*>( n ) ) : QVariant();
3566 }
3567 QVariant result;
3568 if ( n != 0 ) {
3569 result = m_nodemodel.data( n, index.column(), role );
3570 //kDebug(planDbg())<<n->name()<<": "<<index.column()<<", "<<role<<result;
3571 }
3572 if ( role == Qt::EditRole ) {
3573 switch ( index.column() ) {
3574 case NodeModel::NodeActualStart:
3575 case NodeModel::NodeActualFinish:
3576 if ( ! result.isValid() ) {
3577 return QDateTime::currentDateTime();
3578 }
3579 break;
3580 }
3581 }
3582 return result;
3583}
3584
3585bool NodeItemModel::setData( const QModelIndex &index, const QVariant &value, int role )
3586{
3587 if ( ! index.isValid() ) {
3588 return ItemModelBase::setData( index, value, role );
3589 }
3590 if ( ( flags(index) &Qt::ItemIsEditable ) == 0 || role != Qt::EditRole ) {
3591 kWarning()<<index<<value<<role;
3592 return false;
3593 }
3594 Node *n = node( index );
3595 if ( n ) {
3596 switch ( index.column() ) {
3597 case NodeModel::NodeCompleted: return setCompletion( n, value, role );
3598 case NodeModel::NodeAllocation: return setAllocation( n, value, role );
3599 default: {
3600 KUndo2Command *c = m_nodemodel.setData( n, index.column(), value, role );
3601 if ( c ) {
3602 emit executeCommand( c );
3603 return true;
3604 }
3605 break;
3606 }
3607 }
3608 }
3609 return false;
3610}
3611
3612QVariant NodeItemModel::headerData( int section, Qt::Orientation orientation, int role ) const
3613{
3614 if ( orientation == Qt::Horizontal ) {
3615 if ( role == Qt::DisplayRole || role == Qt::TextAlignmentRole ) {
3616 return m_nodemodel.headerData( section, role );
3617 }
3618 }
3619 if ( role == Qt::ToolTipRole ) {
3620 return NodeModel::headerData( section, role );
3621 } else if ( role == Qt::WhatsThisRole ) {
3622 return NodeModel::headerData( section, role );
3623 }
3624 return ItemModelBase::headerData(section, orientation, role);
3625}
3626
3627QAbstractItemDelegate *NodeItemModel::createDelegate( int column, QWidget *parent ) const
3628{
3629 switch ( column ) {
3630 //case NodeModel::NodeAllocation: return new ??Delegate( parent );
3631 case NodeModel::NodeEstimateType: return new EnumDelegate( parent );
3632 case NodeModel::NodeEstimateCalendar: return new EnumDelegate( parent );
3633 case NodeModel::NodeEstimate: return new DurationSpinBoxDelegate( parent );
3634 case NodeModel::NodeOptimisticRatio: return new SpinBoxDelegate( parent );
3635 case NodeModel::NodePessimisticRatio: return new SpinBoxDelegate( parent );
3636 case NodeModel::NodeRisk: return new EnumDelegate( parent );
3637 case NodeModel::NodeConstraint: return new EnumDelegate( parent );
3638 case NodeModel::NodeConstraintStart: return new DateTimeCalendarDelegate( parent );
3639 case NodeModel::NodeConstraintEnd: return new DateTimeCalendarDelegate( parent );
3640 case NodeModel::NodeRunningAccount: return new EnumDelegate( parent );
3641 case NodeModel::NodeStartupAccount: return new EnumDelegate( parent );
3642 case NodeModel::NodeStartupCost: return new MoneyDelegate( parent );
3643 case NodeModel::NodeShutdownAccount: return new EnumDelegate( parent );
3644 case NodeModel::NodeShutdownCost: return new MoneyDelegate( parent );
3645
3646 case NodeModel::NodeCompleted: return new TaskCompleteDelegate( parent );
3647 case NodeModel::NodeRemainingEffort: return new DurationSpinBoxDelegate( parent );
3648 case NodeModel::NodeActualEffort: return new DurationSpinBoxDelegate( parent );
3649
3650 default: return 0;
3651 }
3652 return 0;
3653}
3654
3655int NodeItemModel::columnCount( const QModelIndex &/*parent*/ ) const
3656{
3657 return m_nodemodel.propertyCount();
3658}
3659
3660int NodeItemModel::rowCount( const QModelIndex &parent ) const
3661{
3662 if ( m_projectshown && ! parent.isValid() ) {
3663 return m_project == 0 ? 0 : 1;
3664 }
3665 Node *p = node( parent );
3666 return p == 0 ? 0 : p->numChildren();
3667}
3668
3669Qt::DropActions NodeItemModel::supportedDropActions() const
3670{
3671 return Qt::CopyAction | Qt::MoveAction;
3672}
3673
3674
3675QStringList NodeItemModel::mimeTypes() const
3676{
3677 return QStringList() << "application/x-vnd.kde.plan.nodeitemmodel.internal"
3678 << "application/x-vnd.kde.plan.resourceitemmodel.internal"
3679 << "application/x-vnd.kde.plan.project"
3680 << "text/uri-list";
3681}
3682
3683QMimeData *NodeItemModel::mimeData( const QModelIndexList & indexes ) const
3684{
3685 QMimeData *m = new QMimeData();
3686 QByteArray encodedData;
3687 QDataStream stream(&encodedData, QIODevice::WriteOnly);
3688 QList<int> rows;
3689 foreach (const QModelIndex &index, indexes) {
3690 if ( index.isValid() && !rows.contains( index.row() ) ) {
3691 //kDebug(planDbg())<<index.row();
3692 Node *n = node( index );
3693 if ( n ) {
3694 rows << index.row();
3695 stream << n->id();
3696 }
3697 }
3698 }
3699 m->setData("application/x-vnd.kde.plan.nodeitemmodel.internal", encodedData);
3700 return m;
3701}
3702
3703bool NodeItemModel::dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data )
3704{
3705 kDebug(planDbg());
3706 if ( m_projectshown && ! index.isValid() ) {
3707 return false;
3708 }
3709 Node *dn = node( index ); // returns project if ! index.isValid()
3710 if ( dn == 0 ) {
3711 kError()<<"no node (or project) to drop on!";
3712 return false; // hmmm
3713 }
3714 if ( data->hasFormat("application/x-vnd.kde.plan.resourceitemmodel.internal") ) {
3715 switch ( dropIndicatorPosition ) {
3716 case ItemModelBase::OnItem:
3717 if ( index.column() == NodeModel::NodeAllocation ) {
3718 kDebug(planDbg())<<"resource:"<<index<<(dn->type() == Node::Type_Task);
3719 return dn->type() == Node::Type_Task;
3720 } else if ( index.column() == NodeModel::NodeResponsible ) {
3721 kDebug(planDbg())<<"resource:"<<index<<true;
3722 return true;
3723 }
3724 break;
3725 default:
3726 break;
3727 }
3728 } else if ( data->hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal")
3729 || data->hasFormat( "application/x-vnd.kde.plan.project" )
3730 || data->hasUrls() )
3731 {
3732 switch ( dropIndicatorPosition ) {
3733 case ItemModelBase::AboveItem:
3734 case ItemModelBase::BelowItem:
3735 // dn == sibling, if not project
3736 if ( dn == m_project ) {
3737 return dropAllowed( dn, data );
3738 }
3739 return dropAllowed( dn->parentNode(), data );
3740 case ItemModelBase::OnItem:
3741 // dn == new parent
3742 return dropAllowed( dn, data );
3743 default:
3744 break;
3745 }
3746 } else {
3747 kDebug(planDbg())<<"Unknown mimetype";
3748 }
3749 return false;
3750}
3751
3752QList<Resource*> NodeItemModel::resourceList( QDataStream &stream )
3753{
3754 QList<Resource*> lst;
3755 while (!stream.atEnd()) {
3756 QString id;
3757 stream >> id;
3758 kDebug(planDbg())<<"id"<<id;
3759 Resource *r = m_project->findResource( id );
3760 if ( r ) {
3761 lst << r;
3762 }
3763 }
3764 kDebug(planDbg())<<lst;
3765 return lst;
3766}
3767
3768bool NodeItemModel::dropAllowed( Node *on, const QMimeData *data )
3769{
3770 if ( ! m_projectshown && on == m_project ) {
3771 return true;
3772 }
3773 if ( on->isBaselined() && on->type() != Node::Type_Summarytask ) {
3774 return false;
3775 }
3776 if ( data->hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal" ) ) {
3777 QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" );
3778 QDataStream stream(&encodedData, QIODevice::ReadOnly);
3779 QList<Node*> lst = nodeList( stream );
3780 foreach ( Node *n, lst ) {
3781 if ( n->type() == Node::Type_Project || on == n || on->isChildOf( n ) ) {
3782 return false;
3783 }
3784 }
3785 lst = removeChildNodes( lst );
3786 foreach ( Node *n, lst ) {
3787 if ( ! m_project->canMoveTask( n, on ) ) {
3788 return false;
3789 }
3790 }
3791 }
3792 return true;
3793}
3794
3795QList<Node*> NodeItemModel::nodeList( QDataStream &stream )
3796{
3797 QList<Node*> lst;
3798 while (!stream.atEnd()) {
3799 QString id;
3800 stream >> id;
3801 Node *node = m_project->findNode( id );
3802 if ( node ) {
3803 lst << node;
3804 }
3805 }
3806 return lst;
3807}
3808
3809QList<Node*> NodeItemModel::removeChildNodes( const QList<Node*> &nodes )
3810{
3811 QList<Node*> lst;
3812 foreach ( Node *node, nodes ) {
3813 bool ins = true;
3814 foreach ( Node *n, lst ) {
3815 if ( node->isChildOf( n ) ) {
3816 //kDebug(planDbg())<<node->name()<<" is child of"<<n->name();
3817 ins = false;
3818 break;
3819 }
3820 }
3821 if ( ins ) {
3822 //kDebug(planDbg())<<" insert"<<node->name();
3823 lst << node;
3824 }
3825 }
3826 QList<Node*> nl = lst;
3827 QList<Node*> nlst = lst;
3828 foreach ( Node *node, nl ) {
3829 foreach ( Node *n, nlst ) {
3830 if ( n->isChildOf( node ) ) {
3831 //kDebug(planDbg())<<n->name()<<" is child of"<<node->name();
3832 int i = nodes.indexOf( n );
3833 lst.removeAt( i );
3834 }
3835 }
3836 }
3837 return lst;
3838}
3839
3840bool NodeItemModel::dropResourceMimeData( const QMimeData *data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex &parent )
3841{
3842 QByteArray encodedData = data->data( "application/x-vnd.kde.plan.resourceitemmodel.internal" );
3843 QDataStream stream(&encodedData, QIODevice::ReadOnly);
3844 Node *n = node( parent );
3845 kDebug(planDbg())<<n<<parent;
3846 if ( n == 0 ) {
3847 return true;
3848 }
3849 kDebug(planDbg())<<n->name();
3850 if ( parent.column() == NodeModel::NodeResponsible ) {
3851 QString s;
3852 foreach ( Resource *r, resourceList( stream ) ) {
3853 s += r->name();
3854 }
3855 if ( ! s.isEmpty() ) {
3856 if ( action == Qt::CopyAction && ! n->leader().isEmpty() ) {
3857 s += ',' + n->leader();
3858 }
3859 KUndo2Command *cmd = m_nodemodel.setLeader( n, s, Qt::EditRole );
3860 if ( cmd ) {
3861 emit executeCommand( cmd );
3862 }
3863 kDebug(planDbg())<<s;
3864 }
3865 return true;
3866 }
3867 if ( n->type() == Node::Type_Task ) {
3868 QList<Resource*> lst = resourceList( stream );
3869 if ( action == Qt::CopyAction ) {
3870 lst += static_cast<Task*>( n )->requestedResources();
3871 }
3872 KUndo2Command *cmd = createAllocationCommand( static_cast<Task&>( *n ), lst );
3873 if ( cmd ) {
3874 emit executeCommand( cmd );
3875 }
3876 return true;
3877 }
3878 return true;
3879}
3880
3881bool NodeItemModel::dropProjectMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent )
3882{
3883 Node *n = node( parent );
3884 kDebug(planDbg())<<n<<parent;
3885 if ( n == 0 ) {
3886 n = m_project;
3887 }
3888 kDebug(planDbg())<<n->name()<<action<<row<<parent;
3889
3890 KoXmlDocument doc;
3891 doc.setContent( data->data( "application/x-vnd.kde.plan.project" ) );
3892 KoXmlElement element = doc.documentElement().namedItem( "project" ).toElement();
3893 Project project;
3894 XMLLoaderObject status;
3895 status.setVersion( doc.documentElement().attribute( "version", PLAN_FILE_SYNTAX_VERSION ) );
3896 status.setProject( &project );
3897 if ( ! project.load( element, status ) ) {
3898 kDebug(planDbg())<<"Failed to load project";
3899 return false;
3900 }
3901 project.generateUniqueNodeIds();
3902 KUndo2Command *cmd = new InsertProjectCmd( project, n, n->childNode( row - 1 ), kundo2_i18nc("1=project or task name", "Insert %1", project.name() ) );
3903 emit executeCommand( cmd );
3904 return true;
3905}
3906
3907bool NodeItemModel::dropUrlMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
3908{
3909 if ( data->hasUrls() ) {
3910 QList<QUrl> urls = data->urls();
3911 kDebug(planDbg())<<urls;
3912 foreach ( const QUrl &url, urls ) {
3913 KMimeType::Ptr mime = KMimeType::findByUrl( url );
3914 kDebug(planDbg())<<url<<mime->name();
3915 if ( mime->is( "application/x-vnd.kde.plan" ) ) {
3916 importProjectFile( url, action, row, column, parent );
3917 }
3918 }
3919 return true;
3920 }
3921 return false;
3922}
3923
3924bool NodeItemModel::importProjectFile( const KUrl &url, Qt::DropAction /*action*/, int row, int /*column*/, const QModelIndex &parent )
3925{
3926 if ( ! url.isLocalFile() ) {
3927 kDebug(planDbg())<<"TODO: download if url not local";
3928 return false;
3929 }
3930 KoStore *store = KoStore::createStore( url.path(), KoStore::Read, "", KoStore::Auto );
3931 if ( store->bad() ) {
3932 // d->lastErrorMessage = i18n( "Not a valid Calligra file: %1", file );
3933 kDebug(planDbg())<<"bad store"<<url.prettyUrl();
3934 delete store;
3935 // QApplication::restoreOverrideCursor();
3936 return false;
3937 }
3938 if ( ! store->open( "root" ) ) { // maindoc.xml
3939 kDebug(planDbg())<<"No root"<<url.prettyUrl();
3940 delete store;
3941 return false;
3942 }
3943 KoXmlDocument doc;
3944 doc.setContent( store->device() );
3945 KoXmlElement element = doc.documentElement().namedItem( "project" ).toElement();
3946 Project project;
3947 XMLLoaderObject status;
3948 status.setVersion( doc.documentElement().attribute( "version", PLAN_FILE_SYNTAX_VERSION ) );
3949 status.setProject( &project );
3950 if ( ! project.load( element, status ) ) {
3951 kDebug(planDbg())<<"Failed to load project from:"<<url;
3952 return false;
3953 }
3954 project.generateUniqueNodeIds();
3955 Node *n = node( parent );
3956 kDebug(planDbg())<<n<<parent;
3957 if ( n == 0 ) {
3958 n = m_project;
3959 }
3960 KUndo2Command *cmd = new InsertProjectCmd( project, n, n->childNode( row - 1 ), kundo2_i18n( "Insert %1", url.fileName() ) );
3961 emit executeCommand( cmd );
3962 return true;
3963}
3964
3965KUndo2Command *NodeItemModel::createAllocationCommand( Task &task, const QList<Resource*> &lst )
3966{
3967 MacroCommand *cmd = new MacroCommand( kundo2_i18n( "Modify resource allocations" ) );
3968 QMap<ResourceGroup*, ResourceGroupRequest*> groups;
3969 foreach ( Resource *r, lst ) {
3970 if ( ! groups.contains( r->parentGroup() ) && task.resourceGroupRequest( r->parentGroup() ) == 0 ) {
3971 ResourceGroupRequest *gr = new ResourceGroupRequest( r->parentGroup() );
3972 groups[ r->parentGroup() ] = gr;
3973 cmd->addCommand( new AddResourceGroupRequestCmd( task, gr ) );
3974 }
3975 }
3976 QList<Resource*> resources = task.requestedResources();
3977 foreach ( Resource *r, lst ) {
3978 if ( resources.contains( r ) ) {
3979 continue;
3980 }
3981 ResourceGroupRequest *gr = groups.value( r->parentGroup() );
3982 if ( gr == 0 ) {
3983 gr = task.resourceGroupRequest( r->parentGroup() );
3984 }
3985 if ( gr == 0 ) {
3986 kError()<<"No group request found, cannot add resource request:"<<r->name();
3987 continue;
3988 }
3989 cmd->addCommand( new AddResourceRequestCmd( gr, new ResourceRequest( r, 100 ) ) );
3990 }
3991 foreach ( Resource *r, resources ) {
3992 if ( ! lst.contains( r ) ) {
3993 ResourceGroupRequest *gr = task.resourceGroupRequest( r->parentGroup() );
3994 ResourceRequest *rr = task.requests().find( r );
3995 if ( gr && rr ) {
3996 cmd->addCommand( new RemoveResourceRequestCmd( gr, rr ) );
3997 }
3998 }
3999 }
4000 if ( cmd->isEmpty() ) {
4001 delete cmd;
4002 return 0;
4003 }
4004 return cmd;
4005}
4006
4007bool NodeItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
4008{
4009 kDebug(planDbg())<<action;
4010 if (action == Qt::IgnoreAction) {
4011 return true;
4012 }
4013 if ( data->hasFormat( "application/x-vnd.kde.plan.resourceitemmodel.internal" ) ) {
4014 return dropResourceMimeData( data, action, row, column, parent );
4015 }
4016 if ( data->hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal" ) ) {
4017 if ( action == Qt::MoveAction ) {
4018 //kDebug(planDbg())<<"MoveAction";
4019
4020 QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" );
4021 QDataStream stream(&encodedData, QIODevice::ReadOnly);
4022 Node *par = 0;
4023 if ( parent.isValid() ) {
4024 par = node( parent );
4025 } else {
4026 par = m_project;
4027 }
4028 QList<Node*> lst = nodeList( stream );
4029 QList<Node*> nodes = removeChildNodes( lst ); // children goes with their parent
4030 foreach ( Node *n, nodes ) {
4031 if ( ! m_project->canMoveTask( n, par ) ) {
4032 //kDebug(planDbg())<<"Can't move task:"<<n->name();
4033 return false;
4034 }
4035 }
4036 int offset = 0;
4037 MacroCommand *cmd = 0;
4038 foreach ( Node *n, nodes ) {
4039 if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Move tasks" ) );
4040 // append nodes if dropped *on* another node, insert if dropped *after*
4041 int pos = row == -1 ? -1 : row + offset;
4042 if ( pos >= 0 && n->parentNode() == par && par->indexOf( n ) < pos ) {
4043 --pos;
4044 }
4045 cmd->addCommand( new NodeMoveCmd( m_project, n, par, pos ) );
4046 offset++;
4047 }
4048 if ( cmd ) {
4049 emit executeCommand( cmd );
4050 }
4051 //kDebug(planDbg())<<row<<","<<column<<" parent="<<parent.row()<<","<<parent.column()<<":"<<par->name();
4052 return true;
4053 }
4054 }
4055 if ( data->hasFormat( "application/x-vnd.kde.plan.project" ) ) {
4056 kDebug(planDbg());
4057 return dropProjectMimeData( data, action, row, column, parent );
4058
4059 }
4060 if ( data->hasUrls() ) {
4061 return dropUrlMimeData( data, action, row, column, parent );
4062 }
4063 return false;
4064}
4065
4066Node *NodeItemModel::node( const QModelIndex &index ) const
4067{
4068 Node *n = m_project;
4069 if ( index.isValid() ) {
4070 //kDebug(planDbg())<<index.internalPointer()<<":"<<index.row()<<","<<index.column();
4071 n = static_cast<Node*>( index.internalPointer() );
4072 Q_ASSERT( n );
4073 }
4074 return n;
4075}
4076
4077void NodeItemModel::slotNodeChanged( Node *node )
4078{
4079 if ( node == 0 || ( ! m_projectshown && node->type() == Node::Type_Project ) ) {
4080 return;
4081 }
4082 if ( node->type() == Node::Type_Project ) {
4083 emit dataChanged( createIndex( 0, 0, node ), createIndex( 0, columnCount()-1, node ) );
4084 return;
4085 }
4086 int row = node->parentNode()->findChildNode( node );
4087 Q_ASSERT( row >= 0 );
4088 emit dataChanged( createIndex( row, 0, node ), createIndex( row, columnCount()-1, node ) );
4089}
4090
4091QModelIndex NodeItemModel::insertTask( Node *node, Node *after )
4092{
4093 MacroCommand *cmd = new MacroCommand( kundo2_i18n( "Add task" ) );
4094 cmd->addCommand( new TaskAddCmd( m_project, node, after ) );
4095 if ( m_project && node->type() == Node::Type_Task ) {
4096 QMap<ResourceGroup*, ResourceGroupRequest*> groups;
4097 foreach ( Resource *r, m_project->autoAllocateResources() ) {
4098 if ( ! groups.contains( r->parentGroup() ) ) {
4099 ResourceGroupRequest *gr = new ResourceGroupRequest( r->parentGroup() );
4100 cmd->addCommand( new AddResourceGroupRequestCmd( static_cast<Task&>(*node), gr ) );
4101 groups[ r->parentGroup() ] = gr;
4102 }
4103 ResourceRequest *rr = new ResourceRequest( r, 100 );
4104 cmd->addCommand( new AddResourceRequestCmd( groups[ r->parentGroup() ], rr ) );
4105 }
4106 }
4107 emit executeCommand( cmd );
4108 int row = -1;
4109 if ( node->parentNode() ) {
4110 row = node->parentNode()->indexOf( node );
4111 }
4112 if ( row != -1 ) {
4113 //kDebug(planDbg())<<"Inserted: "<<node->name()<<"; "<<row;
4114 return createIndex( row, 0, node );
4115 }
4116 //kDebug(planDbg())<<"Can't find "<<node->name();
4117 return QModelIndex();
4118}
4119
4120QModelIndex NodeItemModel::insertSubtask( Node *node, Node *parent )
4121{
4122 emit executeCommand( new SubtaskAddCmd( m_project, node, parent, kundo2_i18n( "Add sub-task" ) ) );
4123 int row = -1;
4124 if ( node->parentNode() ) {
4125 row = node->parentNode()->indexOf( node );
4126 }
4127 if ( row != -1 ) {
4128 //kDebug(planDbg())<<node->parentNode()<<" inserted: "<<node->name()<<"; "<<row;
4129 return createIndex( row, 0, node );
4130 }
4131 //kDebug(planDbg())<<"Can't find "<<node->name();
4132 return QModelIndex();
4133}
4134
4135int NodeItemModel::sortRole( int column ) const
4136{
4137 switch ( column ) {
4138 case NodeModel::NodeStartTime:
4139 case NodeModel::NodeEndTime:
4140 case NodeModel::NodeActualStart:
4141 case NodeModel::NodeActualFinish:
4142 case NodeModel::NodeEarlyStart:
4143 case NodeModel::NodeEarlyFinish:
4144 case NodeModel::NodeLateStart:
4145 case NodeModel::NodeLateFinish:
4146 case NodeModel::NodeConstraintStart:
4147 case NodeModel::NodeConstraintEnd:
4148 return Qt::EditRole;
4149 default:
4150 break;
4151 }
4152 return Qt::DisplayRole;
4153}
4154
4155//------------------------------------------------
4156GanttItemModel::GanttItemModel( QObject *parent )
4157 : NodeItemModel( parent ),
4158 m_showSpecial( false )
4159{
4160}
4161
4162GanttItemModel::~GanttItemModel()
4163{
4164 QList<void*> lst = parentmap.values();
4165 while ( ! lst.isEmpty() )
4166 delete (int*)(lst.takeFirst());
4167}
4168
4169int GanttItemModel::rowCount( const QModelIndex &parent ) const
4170{
4171 if ( m_showSpecial ) {
4172 if ( parentmap.values().contains( parent.internalPointer() ) ) {
4173 return 0;
4174 }
4175 Node *n = node( parent );
4176 if ( n && n->type() == Node::Type_Task ) {
4177 return 5; // the task + early start + late finish ++
4178 }
4179 }
4180 return NodeItemModel::rowCount( parent );
4181}
4182
4183QModelIndex GanttItemModel::index( int row, int column, const QModelIndex &parent ) const
4184{
4185 if ( m_showSpecial && parent.isValid() ) {
4186 Node *p = node( parent );
4187 if ( p->type() == Node::Type_Task ) {
4188 void *v = 0;
4189 foreach ( void *i, parentmap.values( p ) ) {
4190 if ( *( (int*)( i ) ) == row ) {
4191 v = i;
4192 break;
4193 }
4194 }
4195 if ( v == 0 ) {
4196 v = new int( row );
4197 const_cast<GanttItemModel*>( this )->parentmap.insertMulti( p, v );
4198 }
4199 return createIndex( row, column, v );
4200 }
4201 }
4202 return NodeItemModel::index( row, column, parent );
4203}
4204
4205QModelIndex GanttItemModel::parent( const QModelIndex &idx ) const
4206{
4207 if ( m_showSpecial ) {
4208 QList<Node*> lst = parentmap.keys( idx.internalPointer() );
4209 if ( ! lst.isEmpty() ) {
4210 Q_ASSERT( lst.count() == 1 );
4211 return index( lst.first() );
4212 }
4213 }
4214 return NodeItemModel::parent( idx );
4215}
4216
4217QVariant GanttItemModel::data( const QModelIndex &index, int role ) const
4218{
4219 if ( ! index.isValid() ) {
4220 return QVariant();
4221 }
4222 if ( role == Qt::TextAlignmentRole ) {
4223 return headerData( index.column(), Qt::Horizontal, role );
4224 }
4225 QModelIndex idx = index;
4226 QList<Node*> lst;
4227 if ( m_showSpecial ) {
4228 lst = parentmap.keys( idx.internalPointer() );
4229 }
4230 if ( ! lst.isEmpty() ) {
4231 Q_ASSERT( lst.count() == 1 );
4232 int row = *((int*)(idx.internalPointer()));
4233 Node *n = lst.first();
4234 if ( role == SpecialItemTypeRole ) {
4235 return row; // 0=task, 1=early start, 2=late finish...
4236 }
4237 switch ( row ) {
4238 case 0: // the task
4239 if ( idx.column() == NodeModel::NodeType && role == KDGantt::ItemTypeRole ) {
4240 switch ( n->type() ) {
4241 case Node::Type_Task: return KDGantt::TypeTask;
4242 default: break;
4243 }
4244 }
4245 break;
4246 case 1: { // early start
4247 if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KDGantt::ItemTypeRole ) {
4248 return QVariant();
4249 }
4250 switch ( idx.column() ) {
4251 case NodeModel::NodeName: return "Early Start";
4252 case NodeModel::NodeType: return KDGantt::TypeEvent;
4253 case NodeModel::NodeStartTime:
4254 case NodeModel::NodeEndTime: return n->earlyStart( id() );
4255 default: break;
4256 }
4257 }
4258 case 2: { // late finish
4259 if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KDGantt::ItemTypeRole ) {
4260 return QVariant();
4261 }
4262 switch ( idx.column() ) {
4263 case NodeModel::NodeName: return "Late Finish";
4264 case NodeModel::NodeType: return KDGantt::TypeEvent;
4265 case NodeModel::NodeStartTime:
4266 case NodeModel::NodeEndTime: return n->lateFinish( id() );
4267 default: break;
4268 }
4269 }
4270 case 3: { // late start
4271 if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KDGantt::ItemTypeRole ) {
4272 return QVariant();
4273 }
4274 switch ( idx.column() ) {
4275 case NodeModel::NodeName: return "Late Start";
4276 case NodeModel::NodeType: return KDGantt::TypeEvent;
4277 case NodeModel::NodeStartTime:
4278 case NodeModel::NodeEndTime: return n->lateStart( id() );
4279 default: break;
4280 }
4281 }
4282 case 4: { // early finish
4283 if ( role != Qt::DisplayRole && role != Qt::EditRole && role != KDGantt::ItemTypeRole ) {
4284 return QVariant();
4285 }
4286 switch ( idx.column() ) {
4287 case NodeModel::NodeName: return "Early Finish";
4288 case NodeModel::NodeType: return KDGantt::TypeEvent;
4289 case NodeModel::NodeStartTime:
4290 case NodeModel::NodeEndTime: return n->earlyFinish( id() );
4291 default: break;
4292 }
4293 }
4294 default: return QVariant();
4295 }
4296 idx = createIndex( idx.row(), idx.column(), n );
4297 } else {
4298 if ( role == SpecialItemTypeRole ) {
4299 return 0; // task of some type
4300 }
4301 if ( idx.column() == NodeModel::NodeType && role == KDGantt::ItemTypeRole ) {
4302 QVariant result = NodeItemModel::data( idx, Qt::EditRole );
4303 switch ( result.toInt() ) {
4304 case Node::Type_Project: return KDGantt::TypeSummary;
4305 case Node::Type_Summarytask: return KDGantt::TypeSummary;
4306 case Node::Type_Milestone: return KDGantt::TypeEvent;
4307 default: return m_showSpecial ? KDGantt::TypeMulti : KDGantt::TypeTask;
4308 }
4309 }
4310 }
4311 return NodeItemModel::data( idx, role );
4312}
4313
4314//----------------------------
4315MilestoneItemModel::MilestoneItemModel( QObject *parent )
4316 : ItemModelBase( parent )
4317{
4318}
4319
4320MilestoneItemModel::~MilestoneItemModel()
4321{
4322}
4323
4324QList<Node*> MilestoneItemModel::mileStones() const
4325{
4326 QList<Node*> lst;
4327 foreach( Node* n, m_nodemap ) {
4328 if ( n->type() == Node::Type_Milestone ) {
4329 lst << n;
4330 }
4331 }
4332 return lst;
4333}
4334
4335void MilestoneItemModel::slotNodeToBeInserted( Node *parent, int row )
4336{
4337 Q_UNUSED(parent);
4338 Q_UNUSED(row);
4339}
4340
4341void MilestoneItemModel::slotNodeInserted( Node *node )
4342{
4343 Q_UNUSED(node);
4344 resetModel();
4345}
4346
4347void MilestoneItemModel::slotNodeToBeRemoved( Node *node )
4348{
4349 Q_UNUSED(node);
4350 //kDebug(planDbg())<<node->name();
4351/* int row = m_nodemap.values().indexOf( node );
4352 if ( row != -1 ) {
4353 Q_ASSERT( m_nodemap.contains( node->wbsCode() ) );
4354 Q_ASSERT( m_nodemap.keys().indexOf( node->wbsCode() ) == row );
4355 beginRemoveRows( QModelIndex(), row, row );
4356 m_nodemap.remove( node->wbsCode() );
4357 endRemoveRows();
4358 }*/
4359}
4360
4361void MilestoneItemModel::slotNodeRemoved( Node *node )
4362{
4363 Q_UNUSED(node);
4364 resetModel();
4365 //endRemoveRows();
4366}
4367
4368void MilestoneItemModel::slotLayoutChanged()
4369{
4370 //kDebug(planDbg())<<node->name();
4371 emit layoutAboutToBeChanged();
4372 emit layoutChanged();
4373}
4374
4375void MilestoneItemModel::slotNodeToBeMoved( Node *node, int pos, Node *newParent, int newPos )
4376{
4377 Q_UNUSED( node );
4378 Q_UNUSED( pos );
4379 Q_UNUSED( newParent );
4380 Q_UNUSED( newPos );
4381}
4382
4383void MilestoneItemModel::slotNodeMoved( Node *node )
4384{
4385 Q_UNUSED( node );
4386 resetModel();
4387}
4388
4389void MilestoneItemModel::setProject( Project *project )
4390{
4391 if ( m_project ) {
4392 disconnect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) );
4393 disconnect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged()) );
4394 disconnect( m_project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)) );
4395 disconnect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) );
4396 disconnect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) );
4397
4398 disconnect(m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int)));
4399 disconnect(m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*)));
4400
4401 disconnect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) );
4402 disconnect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) );
4403 }
4404 m_project = project;
4405 //kDebug(planDbg())<<m_project<<"->"<<project;
4406 m_nodemodel.setProject( project );
4407 if ( project ) {
4408 connect( m_project, SIGNAL(localeChanged()), this, SLOT(slotLayoutChanged()) );
4409 connect( m_project, SIGNAL(wbsDefinitionChanged()), this, SLOT(slotWbsDefinitionChanged()) );
4410 connect( m_project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)) );
4411 connect( m_project, SIGNAL(nodeToBeAdded(Node*,int)), this, SLOT(slotNodeToBeInserted(Node*,int)) );
4412 connect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) );
4413
4414 connect(m_project, SIGNAL(nodeToBeMoved(Node*,int,Node*,int)), this, SLOT(slotNodeToBeMoved(Node*,int,Node*,int)));
4415 connect(m_project, SIGNAL(nodeMoved(Node*)), this, SLOT(slotNodeMoved(Node*)));
4416
4417 connect( m_project, SIGNAL(nodeAdded(Node*)), this, SLOT(slotNodeInserted(Node*)) );
4418 connect( m_project, SIGNAL(nodeRemoved(Node*)), this, SLOT(slotNodeRemoved(Node*)) );
4419 }
4420 resetModel();
4421}
4422
4423void MilestoneItemModel::setScheduleManager( ScheduleManager *sm )
4424{
4425 if ( m_nodemodel.manager() ) {
4426 }
4427 m_nodemodel.setManager( sm );
4428 ItemModelBase::setScheduleManager( sm );
4429 if ( sm ) {
4430 }
4431 //kDebug(planDbg())<<sm;
4432 resetModel();
4433}
4434
4435bool MilestoneItemModel::resetData()
4436{
4437 int cnt = m_nodemap.count();
4438 m_nodemap.clear();
4439 if ( m_project != 0 ) {
4440 foreach ( Node *n, m_project->allNodes() ) {
4441 m_nodemap.insert( n->wbsCode(), n );
4442 }
4443 }
4444 return cnt != m_nodemap.count();
4445}
4446
4447void MilestoneItemModel::resetModel()
4448{
4449 resetData();
4450 reset();
4451}
4452
4453Qt::ItemFlags MilestoneItemModel::flags( const QModelIndex &index ) const
4454{
4455 Qt::ItemFlags flags = QAbstractItemModel::flags( index );
4456 if ( !index.isValid() ) {
4457 if ( m_readWrite ) {
4458 flags |= Qt::ItemIsDropEnabled;
4459 }
4460 return flags;
4461 }
4462 if ( m_readWrite ) {
4463 flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
4464 switch ( index.column() ) {
4465 case NodeModel::NodeName: // name
4466 flags |= Qt::ItemIsEditable;
4467 break;
4468 case NodeModel::NodeType: break; // Node type
4469 case NodeModel::NodeResponsible: // Responsible
4470 flags |= Qt::ItemIsEditable;
4471 break;
4472 case NodeModel::NodeConstraint: // constraint type
4473 flags |= Qt::ItemIsEditable;
4474 break;
4475 case NodeModel::NodeConstraintStart: { // constraint start
4476 Node *n = node( index );
4477 if ( n == 0 )
4478 break;
4479 int c = n->constraint();
4480 if ( c == Node::MustStartOn || c == Node::StartNotEarlier || c == Node::FixedInterval ) {
4481 flags |= Qt::ItemIsEditable;
4482 }
4483 break;
4484 }
4485 case NodeModel::NodeConstraintEnd: { // constraint end
4486 Node *n = node( index );
4487 if ( n == 0 )
4488 break;
4489 int c = n->constraint();
4490 if ( c == Node::MustFinishOn || c == Node::FinishNotLater || c == Node::FixedInterval ) {
4491 flags |= Qt::ItemIsEditable;
4492 }
4493 break;
4494 }
4495 case NodeModel::NodeStartupAccount: // startup account
4496 case NodeModel::NodeStartupCost: // startup cost
4497 case NodeModel::NodeShutdownAccount: // shutdown account
4498 case NodeModel::NodeShutdownCost: { // shutdown cost
4499 Node *n = node( index );
4500 if ( n && (n->type() == Node::Type_Task || n->type() == Node::Type_Milestone) ) {
4501 flags |= Qt::ItemIsEditable;
4502 }
4503 break;
4504 }
4505 case NodeModel::NodeDescription: // description
4506 break;
4507 default:
4508 flags &= ~Qt::ItemIsEditable;
4509 }
4510 }
4511 return flags;
4512}
4513
4514QModelIndex MilestoneItemModel::parent( const QModelIndex &index ) const
4515{
4516 Q_UNUSED(index);
4517 return QModelIndex();
4518}
4519
4520QModelIndex MilestoneItemModel::index( int row, int column, const QModelIndex &parent ) const
4521{
4522 //kDebug(planDbg())<<parent<<row<<", "<<m_nodemap.count();
4523 if ( m_project == 0 || row < 0 || column < 0 ) {
4524 //kDebug(planDbg())<<"No project"<<m_project<<" or illegal row, column"<<row<<column;
4525 return QModelIndex();
4526 }
4527 if ( parent.isValid() || row >= m_nodemap.count() ) {
4528 //kDebug(planDbg())<<"No index for"<<parent<<row<<","<<column;
4529 return QModelIndex();
4530 }
4531 return createIndex( row, column, m_nodemap.values().at( row ) );
4532}
4533
4534QModelIndex MilestoneItemModel::index( const Node *node ) const
4535{
4536 if ( m_project == 0 || node == 0 ) {
4537 return QModelIndex();
4538 }
4539 return createIndex( m_nodemap.values().indexOf( const_cast<Node*>( node ) ), 0, const_cast<Node*>(node) );
4540}
4541
4542
4543QVariant MilestoneItemModel::data( const QModelIndex &index, int role ) const
4544{
4545 QVariant result;
4546 if ( role == Qt::TextAlignmentRole ) {
4547 return headerData( index.column(), Qt::Horizontal, role );
4548 }
4549 Node *n = node( index );
4550 if ( n != 0 ) {
4551 if ( index.column() == NodeModel::NodeType && role == KDGantt::ItemTypeRole ) {
4552 result = m_nodemodel.data( n, index.column(), Qt::EditRole );
4553 switch ( result.toInt() ) {
4554 case Node::Type_Summarytask: return KDGantt::TypeSummary;
4555 case Node::Type_Milestone: return KDGantt::TypeEvent;
4556 default: return KDGantt::TypeTask;
4557 }
4558 return result;
4559 }
4560 }
4561 result = m_nodemodel.data( n, index.column(), role );
4562 return result;
4563}
4564
4565bool MilestoneItemModel::setData( const QModelIndex &index, const QVariant &/*value*/, int role )
4566{
4567 if ( ( flags(index) &Qt::ItemIsEditable ) == 0 || role != Qt::EditRole ) {
4568 return false;
4569 }
4570// Node *n = node( index );
4571 switch (index.column()) {
4572 default:
4573 qWarning("data: invalid display value column %d", index.column());
4574 return false;
4575 }
4576 return false;
4577}
4578
4579QVariant MilestoneItemModel::headerData( int section, Qt::Orientation orientation, int role ) const
4580{
4581 if ( orientation == Qt::Horizontal ) {
4582 if ( role == Qt::DisplayRole || role == Qt::TextAlignmentRole) {
4583 return m_nodemodel.headerData( section, role );
4584 }
4585 }
4586 if ( role == Qt::ToolTipRole ) {
4587 return NodeModel::headerData( section, role );
4588 }
4589 return ItemModelBase::headerData(section, orientation, role);
4590}
4591
4592QAbstractItemDelegate *MilestoneItemModel::createDelegate( int column, QWidget *parent ) const
4593{
4594 switch ( column ) {
4595 case NodeModel::NodeEstimateType: return new EnumDelegate( parent );
4596 case NodeModel::NodeEstimateCalendar: return new EnumDelegate( parent );
4597 case NodeModel::NodeEstimate: return new DurationSpinBoxDelegate( parent );
4598 case NodeModel::NodeOptimisticRatio: return new SpinBoxDelegate( parent );
4599 case NodeModel::NodePessimisticRatio: return new SpinBoxDelegate( parent );
4600 case NodeModel::NodeRisk: return new EnumDelegate( parent );
4601 case NodeModel::NodeConstraint: return new EnumDelegate( parent );
4602 case NodeModel::NodeRunningAccount: return new EnumDelegate( parent );
4603 case NodeModel::NodeStartupAccount: return new EnumDelegate( parent );
4604 case NodeModel::NodeStartupCost: return new MoneyDelegate( parent );
4605 case NodeModel::NodeShutdownAccount: return new EnumDelegate( parent );
4606 case NodeModel::NodeShutdownCost: return new MoneyDelegate( parent );
4607
4608 case NodeModel::NodeCompleted: return new TaskCompleteDelegate( parent );
4609 case NodeModel::NodeRemainingEffort: return new DurationSpinBoxDelegate( parent );
4610 case NodeModel::NodeActualEffort: return new DurationSpinBoxDelegate( parent );
4611
4612 default: return 0;
4613 }
4614 return 0;
4615}
4616
4617int MilestoneItemModel::columnCount( const QModelIndex &/*parent*/ ) const
4618{
4619 return m_nodemodel.propertyCount();
4620}
4621
4622int MilestoneItemModel::rowCount( const QModelIndex &parent ) const
4623{
4624 //kDebug(planDbg())<<parent;
4625 if ( parent.isValid() ) {
4626 return 0;
4627 }
4628 //kDebug(planDbg())<<m_nodemap.count();
4629 return m_nodemap.count();
4630}
4631
4632Qt::DropActions MilestoneItemModel::supportedDropActions() const
4633{
4634 return Qt::CopyAction | Qt::MoveAction;
4635}
4636
4637
4638QStringList MilestoneItemModel::mimeTypes() const
4639{
4640 return QStringList();
4641}
4642
4643QMimeData *MilestoneItemModel::mimeData( const QModelIndexList & indexes ) const
4644{
4645 QMimeData *m = new QMimeData();
4646 QByteArray encodedData;
4647 QDataStream stream(&encodedData, QIODevice::WriteOnly);
4648 QList<int> rows;
4649 foreach (const QModelIndex &index, indexes) {
4650 if ( index.isValid() && !rows.contains( index.row() ) ) {
4651 //kDebug(planDbg())<<index.row();
4652 Node *n = node( index );
4653 if ( n ) {
4654 rows << index.row();
4655 stream << n->id();
4656 }
4657 }
4658 }
4659 m->setData("application/x-vnd.kde.plan.nodeitemmodel.internal", encodedData);
4660 return m;
4661}
4662
4663bool MilestoneItemModel::dropAllowed( const QModelIndex &index, int dropIndicatorPosition, const QMimeData *data )
4664{
4665 //kDebug(planDbg());
4666 Node *dn = node( index );
4667 if ( dn == 0 ) {
4668 kError()<<"no node to drop on!";
4669 return false; // hmmm
4670 }
4671 switch ( dropIndicatorPosition ) {
4672 case ItemModelBase::AboveItem:
4673 case ItemModelBase::BelowItem:
4674 // dn == sibling
4675 return dropAllowed( dn->parentNode(), data );
4676 case ItemModelBase::OnItem:
4677 // dn == new parent
4678 return dropAllowed( dn, data );
4679 default:
4680 break;
4681 }
4682 return false;
4683}
4684
4685bool MilestoneItemModel::dropAllowed( Node *on, const QMimeData *data )
4686{
4687 if ( !data->hasFormat("application/x-vnd.kde.plan.nodeitemmodel.internal") ) {
4688 return false;
4689 }
4690 if ( on == m_project ) {
4691 return true;
4692 }
4693 QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" );
4694 QDataStream stream(&encodedData, QIODevice::ReadOnly);
4695 QList<Node*> lst = nodeList( stream );
4696 foreach ( Node *n, lst ) {
4697 if ( on == n || on->isChildOf( n ) ) {
4698 return false;
4699 }
4700 }
4701 lst = removeChildNodes( lst );
4702 foreach ( Node *n, lst ) {
4703 if ( ! m_project->canMoveTask( n, on ) ) {
4704 return false;
4705 }
4706 }
4707 return true;
4708}
4709
4710QList<Node*> MilestoneItemModel::nodeList( QDataStream &stream )
4711{
4712 QList<Node*> lst;
4713 while (!stream.atEnd()) {
4714 QString id;
4715 stream >> id;
4716 Node *node = m_project->findNode( id );
4717 if ( node ) {
4718 lst << node;
4719 }
4720 }
4721 return lst;
4722}
4723
4724QList<Node*> MilestoneItemModel::removeChildNodes( const QList<Node*> &nodes )
4725{
4726 QList<Node*> lst;
4727 foreach ( Node *node, nodes ) {
4728 bool ins = true;
4729 foreach ( Node *n, lst ) {
4730 if ( node->isChildOf( n ) ) {
4731 //kDebug(planDbg())<<node->name()<<" is child of"<<n->name();
4732 ins = false;
4733 break;
4734 }
4735 }
4736 if ( ins ) {
4737 //kDebug(planDbg())<<" insert"<<node->name();
4738 lst << node;
4739 }
4740 }
4741 QList<Node*> nl = lst;
4742 QList<Node*> nlst = lst;
4743 foreach ( Node *node, nl ) {
4744 foreach ( Node *n, nlst ) {
4745 if ( n->isChildOf( node ) ) {
4746 //kDebug(planDbg())<<n->name()<<" is child of"<<node->name();
4747 int i = nodes.indexOf( n );
4748 lst.removeAt( i );
4749 }
4750 }
4751 }
4752 return lst;
4753}
4754
4755bool MilestoneItemModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent )
4756{
4757 //kDebug(planDbg())<<action;
4758 if (action == Qt::IgnoreAction) {
4759 return true;
4760 }
4761 if ( !data->hasFormat( "application/x-vnd.kde.plan.nodeitemmodel.internal" ) ) {
4762 return false;
4763 }
4764 if ( action == Qt::MoveAction ) {
4765 //kDebug(planDbg())<<"MoveAction";
4766
4767 QByteArray encodedData = data->data( "application/x-vnd.kde.plan.nodeitemmodel.internal" );
4768 QDataStream stream(&encodedData, QIODevice::ReadOnly);
4769 Node *par = 0;
4770 if ( parent.isValid() ) {
4771 par = node( parent );
4772 } else {
4773 par = m_project;
4774 }
4775 QList<Node*> lst = nodeList( stream );
4776 QList<Node*> nodes = removeChildNodes( lst ); // children goes with their parent
4777 foreach ( Node *n, nodes ) {
4778 if ( ! m_project->canMoveTask( n, par ) ) {
4779 //kDebug(planDbg())<<"Can't move task:"<<n->name();
4780 return false;
4781 }
4782 }
4783 int offset = 0;
4784 MacroCommand *cmd = 0;
4785 foreach ( Node *n, nodes ) {
4786 if ( cmd == 0 ) cmd = new MacroCommand( kundo2_i18n( "Move tasks" ) );
4787 // append nodes if dropped *on* another node, insert if dropped *after*
4788 int pos = row == -1 ? -1 : row + offset;
4789 cmd->addCommand( new NodeMoveCmd( m_project, n, par, pos ) );
4790 offset++;
4791 }
4792 if ( cmd ) {
4793 emit executeCommand( cmd );
4794 }
4795 //kDebug(planDbg())<<row<<","<<column<<" parent="<<parent.row()<<","<<parent.column()<<":"<<par->name();
4796 return true;
4797 }
4798 return false;
4799}
4800
4801Node *MilestoneItemModel::node( const QModelIndex &index ) const
4802{
4803 Node *n = 0;
4804 if ( index.isValid() ) {
4805 //kDebug(planDbg())<<index;
4806 n = static_cast<Node*>( index.internalPointer() );
4807 }
4808 return n;
4809}
4810
4811void MilestoneItemModel::slotNodeChanged( Node *node )
4812{
4813 //kDebug(planDbg())<<node->name();
4814 if ( node == 0 ) {
4815 return;
4816 }
4817// if ( ! m_nodemap.contains( node->wbsCode() ) || m_nodemap.value( node->wbsCode() ) != node ) {
4818 emit layoutAboutToBeChanged();
4819 if ( resetData() ) {
4820 reset();
4821 } else {
4822 emit layoutChanged();
4823 }
4824 return;
4825/* }
4826 int row = m_nodemap.values().indexOf( node );
4827 kDebug(planDbg())<<node->name()<<": "<<node->typeToString()<<row;
4828 emit dataChanged( createIndex( row, 0, node ), createIndex( row, columnCount()-1, node ) );*/
4829}
4830
4831void MilestoneItemModel::slotWbsDefinitionChanged()
4832{
4833 //kDebug(planDbg());
4834 if ( m_project == 0 ) {
4835 return;
4836 }
4837 if ( ! m_nodemap.isEmpty() ) {
4838 emit layoutAboutToBeChanged();
4839 resetData();
4840 emit layoutChanged();
4841 }
4842}
4843
4844//--------------
4845NodeSortFilterProxyModel::NodeSortFilterProxyModel( ItemModelBase* model, QObject *parent, bool filterUnscheduled )
4846 : QSortFilterProxyModel( parent ),
4847 m_filterUnscheduled( filterUnscheduled )
4848{
4849 setSourceModel( model );
4850 setDynamicSortFilter( true );
4851}
4852
4853ItemModelBase *NodeSortFilterProxyModel::itemModel() const
4854{
4855 return static_cast<ItemModelBase *>( sourceModel() );
4856}
4857
4858void NodeSortFilterProxyModel::setFilterUnscheduled( bool on ) {
4859 m_filterUnscheduled = on;
4860 invalidateFilter();
4861}
4862
4863bool NodeSortFilterProxyModel::filterAcceptsRow ( int row, const QModelIndex & parent ) const
4864{
4865 //kDebug(planDbg())<<sourceModel()<<row<<parent;
4866 if ( itemModel()->project() == 0 ) {
4867 //kDebug(planDbg())<<itemModel()->project();
4868 return false;
4869 }
4870 if ( m_filterUnscheduled ) {
4871 QString s = sourceModel()->data( sourceModel()->index( row, NodeModel::NodeNotScheduled, parent ), Qt::EditRole ).toString();
4872 if ( s == "true" ) {
4873 //kDebug(planDbg())<<"Filtered unscheduled:"<<sourceModel()->index( row, 0, parent );
4874 return false;
4875 }
4876 }
4877 bool accepted = QSortFilterProxyModel::filterAcceptsRow( row, parent );
4878 //kDebug(planDbg())<<this<<sourceModel()->index( row, 0, parent )<<"accepted ="<<accepted<<filterRegExp()<<filterRegExp().isEmpty()<<filterRegExp().capturedTexts();
4879 return accepted;
4880}
4881
4882//------------------
4883TaskModuleModel::TaskModuleModel( QObject *parent )
4884 : QAbstractItemModel( parent )
4885{
4886}
4887
4888void TaskModuleModel::addTaskModule( Project *project )
4889{
4890 beginInsertRows( QModelIndex(), m_modules.count(), m_modules.count() );
4891 m_modules << project;
4892 endInsertRows();
4893}
4894
4895Qt::ItemFlags TaskModuleModel::flags( const QModelIndex &idx ) const
4896{
4897 Qt::ItemFlags f = QAbstractItemModel::flags( idx ) | Qt::ItemIsDropEnabled;
4898 if ( idx.isValid() ) {
4899 f |= Qt::ItemIsDragEnabled;
4900 }
4901 return f;
4902}
4903
4904int TaskModuleModel::columnCount (const QModelIndex &/*idx*/ ) const
4905{
4906 return 1;
4907}
4908
4909int TaskModuleModel::rowCount( const QModelIndex &idx ) const
4910{
4911 return idx.isValid() ? 0 : m_modules.count();
4912}
4913
4914QVariant TaskModuleModel::data( const QModelIndex& idx, int role ) const
4915{
4916 switch ( role ) {
4917 case Qt::DisplayRole: return m_modules.value( idx.row() )->name();
4918 case Qt::ToolTipRole: return m_modules.value( idx.row() )->description();
4919 case Qt::WhatsThisRole: return m_modules.value( idx.row() )->description();
4920 default: break;
4921 }
4922 return QVariant();
4923}
4924
4925QVariant TaskModuleModel::headerData( int /*section*/, Qt::Orientation orientation , int role ) const
4926{
4927 if ( orientation == Qt::Horizontal ) {
4928 switch ( role ) {
4929 case Qt::DisplayRole: return i18nc( "@title:column", "Name" );
4930 default: break;
4931 }
4932 }
4933 return QVariant();
4934}
4935
4936QModelIndex TaskModuleModel::parent( const QModelIndex& /*idx*/ ) const
4937{
4938 return QModelIndex();
4939}
4940
4941QModelIndex TaskModuleModel::index( int row, int column, const QModelIndex &parent ) const
4942{
4943 if ( parent.isValid() ) {
4944 return QModelIndex();
4945 }
4946 return createIndex( row, column, m_modules.value( row ) );
4947}
4948
4949QStringList TaskModuleModel::mimeTypes() const
4950{
4951 return QStringList() << "application/x-vnd.kde.plan" << "text/uri-list";
4952}
4953
4954bool TaskModuleModel::dropMimeData( const QMimeData *data, Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex &/*parent*/ )
4955{
4956 if ( data->hasUrls() ) {
4957 QList<QUrl> urls = data->urls();
4958 kDebug(planDbg())<<urls;
4959 foreach ( const QUrl &url, urls ) {
4960 KMimeType::Ptr mime = KMimeType::findByUrl( url );
4961 kDebug(planDbg())<<url<<mime->name();
4962 if ( mime->is( "application/x-vnd.kde.plan" ) || mime->is( "application/xml" ) ) {
4963 importProject( url );
4964 }
4965 }
4966 return true;
4967 }
4968 return false;
4969}
4970
4971bool TaskModuleModel::importProject( const KUrl &url, bool emitsignal )
4972{
4973 if ( ! url.isLocalFile() ) {
4974 kDebug(planDbg())<<"TODO: download if url not local";
4975 return false;
4976 }
4977 KoStore *store = KoStore::createStore( url.path(), KoStore::Read, "", KoStore::Auto );
4978 if ( store->bad() ) {
4979 // d->lastErrorMessage = i18n( "Not a valid Calligra file: %1", file );
4980 kDebug(planDbg())<<"bad store"<<url.prettyUrl();
4981 delete store;
4982 // QApplication::restoreOverrideCursor();
4983 return false;
4984 }
4985 if ( ! store->open( "root" ) ) { // maindoc.xml
4986 kDebug(planDbg())<<"No root"<<url.prettyUrl();
4987 delete store;
4988 return false;
4989 }
4990 KoXmlDocument doc;
4991 doc.setContent( store->device() );
4992 KoXmlElement element = doc.documentElement().namedItem( "project" ).toElement();
4993 Project *project = new Project();
4994 XMLLoaderObject status;
4995 status.setVersion( doc.documentElement().attribute( "version", PLAN_FILE_SYNTAX_VERSION ) );
4996 status.setProject( project );
4997 if ( project->load( element, status ) ) {
4998 stripProject( project );
4999 addTaskModule( project );
5000 if ( emitsignal ) {
5001 emit saveTaskModule( url, project );
5002 }
5003 } else {
5004 kDebug(planDbg())<<"Failed to load project from:"<<url;
5005 delete project;
5006 return false;
5007 }
5008 return true;
5009}
5010
5011QMimeData* TaskModuleModel::mimeData( const QModelIndexList &lst ) const
5012{
5013 QMimeData *mime = new QMimeData();
5014 if ( lst.count() == 1 ) {
5015 QModelIndex idx = lst.at( 0 );
5016 if ( idx.isValid() ) {
5017 Project *project = m_modules.value( idx.row() );
5018 QDomDocument document( "plan" );
5019 document.appendChild( document.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" ) );
5020 QDomElement doc = document.createElement( "plan" );
5021 doc.setAttribute( "editor", "Plan" );
5022 doc.setAttribute( "mime", "application/x-vnd.kde.plan" );
5023 doc.setAttribute( "version", PLAN_FILE_SYNTAX_VERSION );
5024 document.appendChild( doc );
5025 project->save( doc );
5026 mime->setData( "application/x-vnd.kde.plan.project", document.toByteArray() );
5027 }
5028 }
5029 return mime;
5030}
5031
5032void TaskModuleModel::stripProject( Project *project ) const
5033{
5034 foreach ( ScheduleManager *sm, project->scheduleManagers() ) {
5035 DeleteScheduleManagerCmd c( *project, sm );
5036 }
5037}
5038
5039void TaskModuleModel::loadTaskModules( const QStringList &files )
5040{
5041 kDebug(planDbg())<<files;
5042 foreach ( const QString &file, files ) {
5043 importProject( KUrl( file ), false );
5044 }
5045}
5046
5047
5048} //namespace KPlato
5049
5050#include "kptnodeitemmodel.moc"
5051