1 | /* This file is part of the KDE project |
2 | Copyright (C) 2007, 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 "kptrelationmodel.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 "kptrelation.h" |
29 | #include "kptdebug.h" |
30 | |
31 | #include <QAbstractItemModel> |
32 | #include <QModelIndex> |
33 | #include <QWidget> |
34 | |
35 | #include <kaction.h> |
36 | #include <kglobal.h> |
37 | #include <klocale.h> |
38 | #include <ktoggleaction.h> |
39 | #include <kactionmenu.h> |
40 | #include <kstandardaction.h> |
41 | #include <kstandardshortcut.h> |
42 | #include <kaccelgen.h> |
43 | #include <kactioncollection.h> |
44 | |
45 | #include <kdganttglobal.h> |
46 | |
47 | |
48 | namespace KPlato |
49 | { |
50 | |
51 | QVariant RelationModel::parentName( const Relation *r, int role ) const |
52 | { |
53 | //kDebug(planDbg())<<r<<", "<<role<<endl; |
54 | switch ( role ) { |
55 | case Qt::DisplayRole: |
56 | case Qt::ToolTipRole: |
57 | case Qt::EditRole: |
58 | return r->parent()->name(); |
59 | case Qt::TextAlignmentRole: |
60 | case Qt::StatusTipRole: |
61 | case Qt::WhatsThisRole: |
62 | return QVariant(); |
63 | } |
64 | return QVariant(); |
65 | } |
66 | |
67 | QVariant RelationModel::childName( const Relation *r, int role ) const |
68 | { |
69 | //kDebug(planDbg())<<r<<", "<<role<<endl; |
70 | switch ( role ) { |
71 | case Qt::DisplayRole: |
72 | case Qt::ToolTipRole: |
73 | case Qt::EditRole: |
74 | return r->child()->name(); |
75 | case Qt::TextAlignmentRole: |
76 | case Qt::StatusTipRole: |
77 | case Qt::WhatsThisRole: |
78 | return QVariant(); |
79 | } |
80 | return QVariant(); |
81 | } |
82 | |
83 | QVariant RelationModel::type( const Relation *r, int role ) const |
84 | { |
85 | //kDebug(planDbg())<<r<<", "<<role<<endl; |
86 | switch ( role ) { |
87 | case Qt::DisplayRole: |
88 | case Qt::ToolTipRole: |
89 | return r->typeToString( true ); |
90 | case Role::EnumList: |
91 | return r->typeList( true ); |
92 | case Qt::EditRole: |
93 | case Role::EnumListValue: |
94 | return (int)r->type(); |
95 | case Qt::TextAlignmentRole: |
96 | return Qt::AlignCenter; |
97 | case Qt::StatusTipRole: |
98 | case Qt::WhatsThisRole: |
99 | return QVariant(); |
100 | } |
101 | return QVariant(); |
102 | } |
103 | |
104 | QVariant RelationModel::lag( const Relation *r, int role ) const |
105 | { |
106 | switch ( role ) { |
107 | case Qt::DisplayRole: |
108 | case Qt::ToolTipRole: { |
109 | Duration::Unit unit = Duration::Unit_h; |
110 | return QVariant(KGlobal::locale()->formatNumber( r->lag().toDouble( unit ), 1 ) + Duration::unitToString( unit, true )); |
111 | } |
112 | case Qt::EditRole: |
113 | return r->lag().toDouble( Duration::Unit_h ); |
114 | case Role::DurationUnit: |
115 | return static_cast<int>( Duration::Unit_h ); |
116 | case Qt::StatusTipRole: |
117 | case Qt::WhatsThisRole: |
118 | return QVariant(); |
119 | } |
120 | return QVariant(); |
121 | } |
122 | |
123 | QVariant RelationModel::data( const Relation *r, int property, int role ) const |
124 | { |
125 | QVariant result; |
126 | switch ( property ) { |
127 | case 0: result = parentName( r, role ); break; |
128 | case 1: result = childName( r, role ); break; |
129 | case 2: result = type( r, role ); break; |
130 | case 3: result = lag( r, role ); break; |
131 | default: |
132 | //kDebug(planDbg())<<"Invalid property number: "<<property<<endl;; |
133 | return result; |
134 | } |
135 | return result; |
136 | } |
137 | |
138 | int RelationModel::propertyCount() |
139 | { |
140 | return 4; |
141 | } |
142 | |
143 | QVariant RelationModel::( int section, int role ) |
144 | { |
145 | if ( role == Qt::DisplayRole ) { |
146 | switch ( section ) { |
147 | case 0: return i18n( "Parent" ); |
148 | case 1: return i18n( "Child" ); |
149 | case 2: return i18n( "Type" ); |
150 | case 3: return i18n( "Lag" ); |
151 | default: return QVariant(); |
152 | } |
153 | } |
154 | if ( role == Qt::ToolTipRole ) { |
155 | switch ( section ) { |
156 | case 0: return ToolTip::relationParent(); |
157 | case 1: return ToolTip::relationChild(); |
158 | case 2: return ToolTip::relationType(); |
159 | case 3: return ToolTip::relationLag(); |
160 | default: return QVariant(); |
161 | } |
162 | } |
163 | return QVariant(); |
164 | } |
165 | |
166 | //---------------------------- |
167 | RelationItemModel::RelationItemModel( QObject *parent ) |
168 | : ItemModelBase( parent ), |
169 | m_node( 0 ), |
170 | m_removedRelation( 0 ) |
171 | { |
172 | } |
173 | |
174 | RelationItemModel::~RelationItemModel() |
175 | { |
176 | } |
177 | |
178 | void RelationItemModel::slotRelationToBeAdded( Relation *relation, int, int ) |
179 | { |
180 | kDebug(planDbg()); |
181 | if ( m_node == 0 || m_node != relation->child() ) { |
182 | return; |
183 | } |
184 | // relations always appended |
185 | int row = rowCount(); |
186 | beginInsertRows( QModelIndex(), row, row ); |
187 | } |
188 | |
189 | void RelationItemModel::slotRelationAdded( Relation *relation ) |
190 | { |
191 | kDebug(planDbg()); |
192 | if ( m_node == 0 || m_node != relation->child() ) { |
193 | return; |
194 | } |
195 | endInsertRows(); |
196 | } |
197 | |
198 | void RelationItemModel::slotRelationToBeRemoved( Relation *relation ) |
199 | { |
200 | if ( m_node == 0 || ! m_node->dependParentNodes().contains( relation ) ) { |
201 | return; |
202 | } |
203 | m_removedRelation = relation; |
204 | int row = m_node->dependParentNodes().indexOf( relation ); |
205 | kDebug(planDbg())<<row; |
206 | beginRemoveRows( QModelIndex(), row, row ); |
207 | } |
208 | |
209 | void RelationItemModel::slotRelationRemoved( Relation *relation ) |
210 | { |
211 | kDebug(planDbg()); |
212 | if ( m_removedRelation != relation ) { |
213 | return; |
214 | } |
215 | m_removedRelation = 0; |
216 | endRemoveRows(); |
217 | } |
218 | |
219 | void RelationItemModel::slotRelationModified( Relation *relation ) |
220 | { |
221 | kDebug(planDbg()); |
222 | if ( m_node == 0 || ! m_node->dependParentNodes().contains( relation ) ) { |
223 | return; |
224 | } |
225 | int row = m_node->dependParentNodes().indexOf( relation ); |
226 | emit dataChanged( createIndex( row, 0 ), createIndex( row, columnCount()-1 ) ); |
227 | } |
228 | |
229 | void RelationItemModel::slotNodeToBeRemoved( Node *node ) |
230 | { |
231 | if ( node != m_node ) { |
232 | return; |
233 | } |
234 | setNode( 0 ); |
235 | } |
236 | |
237 | void RelationItemModel::slotNodeRemoved( Node *node ) |
238 | { |
239 | Q_UNUSED(node); |
240 | } |
241 | |
242 | void RelationItemModel::slotLayoutChanged() |
243 | { |
244 | //kDebug(planDbg())<<node->name()<<endl; |
245 | emit layoutAboutToBeChanged(); |
246 | emit layoutChanged(); |
247 | } |
248 | |
249 | void RelationItemModel::setProject( Project *project ) |
250 | { |
251 | if ( m_project ) { |
252 | disconnect( m_project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)) ); |
253 | disconnect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) ); |
254 | |
255 | disconnect( m_project, SIGNAL(relationToBeAdded(Relation*,int,int)), this, SLOT(slotRelationToBeAdded(Relation*,int,int)) ); |
256 | disconnect( m_project, SIGNAL(relationAdded(Relation*)), this, SLOT(slotRelationAdded(Relation*)) ); |
257 | |
258 | disconnect( m_project, SIGNAL(relationToBeRemoved(Relation*)), this, SLOT(slotRelationToBeRemoved(Relation*)) ); |
259 | disconnect( m_project, SIGNAL(relationRemoved(Relation*)), this, SLOT(slotRelationRemoved(Relation*)) ); |
260 | |
261 | disconnect( m_project, SIGNAL(relationModified(Relation*)), this, SLOT(slotRelationModified(Relation*)) ); |
262 | } |
263 | m_project = project; |
264 | if ( project ) { |
265 | connect( m_project, SIGNAL(nodeChanged(Node*)), this, SLOT(slotNodeChanged(Node*)) ); |
266 | connect( m_project, SIGNAL(nodeToBeRemoved(Node*)), this, SLOT(slotNodeToBeRemoved(Node*)) ); |
267 | |
268 | connect( m_project, SIGNAL(relationToBeAdded(Relation*,int,int)), this, SLOT(slotRelationToBeAdded(Relation*,int,int)) ); |
269 | connect( m_project, SIGNAL(relationAdded(Relation*)), this, SLOT(slotRelationAdded(Relation*)) ); |
270 | |
271 | connect( m_project, SIGNAL(relationToBeRemoved(Relation*)), this, SLOT(slotRelationToBeRemoved(Relation*)) ); |
272 | connect( m_project, SIGNAL(relationRemoved(Relation*)), this, SLOT(slotRelationRemoved(Relation*)) ); |
273 | |
274 | connect( m_project, SIGNAL(relationModified(Relation*)), this, SLOT(slotRelationModified(Relation*)) ); |
275 | } |
276 | reset(); |
277 | } |
278 | |
279 | void RelationItemModel::setNode( Node *node ) |
280 | { |
281 | m_node = node; |
282 | reset(); |
283 | } |
284 | |
285 | Qt::ItemFlags RelationItemModel::flags( const QModelIndex &index ) const |
286 | { |
287 | Qt::ItemFlags flags = QAbstractItemModel::flags( index ); |
288 | if ( !index.isValid() ) { |
289 | if ( m_readWrite ) { |
290 | flags |= Qt::ItemIsDropEnabled; |
291 | } |
292 | return flags; |
293 | } |
294 | if ( m_readWrite ) { |
295 | flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; |
296 | switch ( index.column() ) { |
297 | case 2: // type |
298 | flags |= Qt::ItemIsEditable; |
299 | break; |
300 | case 3: // lag |
301 | flags |= Qt::ItemIsEditable; |
302 | break; |
303 | default: |
304 | flags &= ~Qt::ItemIsEditable; |
305 | break; |
306 | } |
307 | } |
308 | return flags; |
309 | } |
310 | |
311 | |
312 | QModelIndex RelationItemModel::parent( const QModelIndex &/*index*/ ) const |
313 | { |
314 | return QModelIndex(); // flat model |
315 | } |
316 | |
317 | QModelIndex RelationItemModel::index( int row, int column, const QModelIndex &parent ) const |
318 | { |
319 | if ( m_project == 0 ) { |
320 | return QModelIndex(); |
321 | } |
322 | if ( parent.isValid() ) { |
323 | return QModelIndex(); // flat model |
324 | } |
325 | return createIndex( row, column ); |
326 | } |
327 | |
328 | bool RelationItemModel::setType( Relation *r, const QVariant &value, int role ) |
329 | { |
330 | switch ( role ) { |
331 | case Qt::EditRole: |
332 | Relation::Type v = Relation::Type( value.toInt() ); |
333 | //kDebug(planDbg())<<v<<r->type(); |
334 | if ( v == r->type() ) { |
335 | return false; |
336 | } |
337 | emit executeCommand( new ModifyRelationTypeCmd( r, v, kundo2_i18n("Modify relation type" ) ) ); |
338 | return true; |
339 | } |
340 | return false; |
341 | } |
342 | |
343 | bool RelationItemModel::setLag( Relation *r, const QVariant &value, int role ) |
344 | { |
345 | switch ( role ) { |
346 | case Qt::EditRole: { |
347 | Duration::Unit unit = static_cast<Duration::Unit>( value.toList()[1].toInt() ); |
348 | Duration d( value.toList()[0].toDouble(), unit ); |
349 | kDebug(planDbg())<<value.toList()[0].toDouble()<<"," <<unit<<" ->" <<d.toString(); |
350 | if ( d == r->lag() ) { |
351 | return false; |
352 | } |
353 | emit executeCommand( new ModifyRelationLagCmd( r, d, kundo2_i18n( "Modify relation time lag" ) ) ); |
354 | return true; |
355 | } |
356 | default: |
357 | break; |
358 | } |
359 | return false; |
360 | } |
361 | |
362 | QVariant RelationItemModel::data( const QModelIndex &index, int role ) const |
363 | { |
364 | if ( role == Qt::TextAlignmentRole ) { |
365 | return headerData( index.column(), Qt::Horizontal, role ); |
366 | } |
367 | |
368 | QVariant result; |
369 | Relation *r = relation( index ); |
370 | if ( r != 0 ) { |
371 | result = m_relationmodel.data( r, index.column(), role ); |
372 | } |
373 | if ( result.isValid() ) { |
374 | if ( role == Qt::DisplayRole && result.type() == QVariant::String && result.toString().isEmpty()) { |
375 | // HACK to show focus in empty cells |
376 | result = ' '; |
377 | } |
378 | return result; |
379 | } |
380 | return result; |
381 | } |
382 | |
383 | bool RelationItemModel::setData( const QModelIndex &index, const QVariant &value, int role ) |
384 | { |
385 | if ( ! index.isValid() ) { |
386 | return ItemModelBase::setData( index, value, role ); |
387 | } |
388 | if ( ( flags(index) & Qt::ItemIsEditable ) == 0 || role != Qt::EditRole ) { |
389 | return false; |
390 | } |
391 | Relation *r = relation( index ); |
392 | switch (index.column()) { |
393 | case 0: return false; |
394 | case 1: return false; |
395 | case 2: return setType( r, value, role ); |
396 | case 3: return setLag( r, value, role ); |
397 | default: |
398 | qWarning("data: invalid display value column %d" , index.column()); |
399 | return false; |
400 | } |
401 | return false; |
402 | } |
403 | |
404 | QVariant RelationItemModel::( int section, Qt::Orientation orientation, int role ) const |
405 | { |
406 | if ( orientation == Qt::Horizontal ) { |
407 | if ( role == Qt::DisplayRole ) { |
408 | return m_relationmodel.headerData( section, role ); |
409 | } else if ( role == Qt::TextAlignmentRole ) { |
410 | switch (section) { |
411 | case 2: return Qt::AlignCenter; |
412 | case 3: return Qt::AlignRight; |
413 | default: return QVariant(); |
414 | } |
415 | } |
416 | } |
417 | if ( role == Qt::ToolTipRole ) { |
418 | return RelationModel::headerData( section, role ); |
419 | } |
420 | return ItemModelBase::headerData(section, orientation, role); |
421 | } |
422 | |
423 | QAbstractItemDelegate *RelationItemModel::createDelegate( int column, QWidget *parent ) const |
424 | { |
425 | switch ( column ) { |
426 | case 2: return new EnumDelegate( parent ); |
427 | case 3: return new DurationSpinBoxDelegate( parent ); |
428 | default: return 0; |
429 | } |
430 | return 0; |
431 | } |
432 | |
433 | int RelationItemModel::columnCount( const QModelIndex &/*parent*/ ) const |
434 | { |
435 | return m_relationmodel.propertyCount(); |
436 | } |
437 | |
438 | int RelationItemModel::rowCount( const QModelIndex &parent ) const |
439 | { |
440 | if ( m_project == 0 || m_node == 0 || parent.isValid() ) { |
441 | return 0; |
442 | } |
443 | return m_node->numDependParentNodes(); |
444 | } |
445 | |
446 | Relation *RelationItemModel::relation( const QModelIndex &index ) const |
447 | { |
448 | if ( ! index.isValid() || m_node == 0 ) { |
449 | return 0; |
450 | } |
451 | return m_node->dependParentNodes().value( index.row() ); |
452 | } |
453 | |
454 | void RelationItemModel::slotNodeChanged( Node *node ) |
455 | { |
456 | Q_UNUSED(node); |
457 | reset(); |
458 | } |
459 | |
460 | |
461 | } //namespace KPlato |
462 | |
463 | #include "kptrelationmodel.moc" |
464 | |