1 /*************************-**************************************************
2 * Copyright (C) 2007 by Arrigo Zanette *
4 ***************************************************************************/
10 #include "backupper.h"
11 #include "sakwidget.h"
12 #include "saksubwidget.h"
13 #include "sakmessageitem.h"
14 #include "pixmapviewer.h"
16 #include "backupper.h"
20 //BEGIN Hits >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
22 //BEGIN MyDateItemDelegate
25 MyDateItemDelegate::MyDateItemDelegate(QObject
*parent
)
26 : QItemDelegate(parent
)
30 QWidget
*MyDateItemDelegate::createEditor(QWidget
*parent
,
31 const QStyleOptionViewItem
&/* option */,
32 const QModelIndex
& index
) const
34 QDateTimeEdit
*editor
= new QDateTimeEdit(parent
);
35 editor
->setCalendarPopup(true);
36 editor
->setDisplayFormat(DATETIMEFORMAT
);
37 editor
->setDateTime(QDateTime::fromString(index
.data().toString(), DATETIMEFORMAT
));
41 void MyDateItemDelegate::setEditorData(QWidget
*editor
,
42 const QModelIndex
&index
) const
44 const QDateTime
& value
= index
.model()->data(index
, Qt::DisplayRole
).toDateTime();
46 QDateTimeEdit
*e
= static_cast<QDateTimeEdit
*>(editor
);
47 e
->setDateTime(value
);
50 void MyDateItemDelegate::setModelData(QWidget
*editor
, QAbstractItemModel
*model
,
51 const QModelIndex
&index
) const
53 QDateTimeEdit
*e
= static_cast<QDateTimeEdit
*>(editor
);
55 const QDateTime
& value
= e
->dateTime();
57 model
->setData(index
, value
.toString(DATETIMEFORMAT
), Qt::EditRole
);
60 void MyDateItemDelegate::updateEditorGeometry(QWidget
*editor
,
61 const QStyleOptionViewItem
&option
, const QModelIndex
&/* index */) const
63 editor
->setGeometry(option
.rect
);
66 //END MyDateItemDelegate
68 //BEGIN TaskItemDelegate
70 TaskItemDelegate::TaskItemDelegate(Sak
* sak
, QObject
*parent
)
71 : QItemDelegate(parent
), m_sak(sak
)
75 QWidget
*TaskItemDelegate::createEditor(QWidget
*parent
,
76 const QStyleOptionViewItem
&/* option */,
77 const QModelIndex
& index
) const
79 QComboBox
*editor
= new QComboBox(parent
);
82 QString current
= index
.data().toString();
83 foreach(const Task
& t
, *m_sak
->tasks()) {
84 editor
->addItem(t
.icon
, t
.title
);
85 if (t
.title
== current
)
89 editor
->setCurrentIndex(j
);
93 void TaskItemDelegate::setEditorData(QWidget
*editor
,
94 const QModelIndex
&index
) const
96 const QString
& value ( index
.data().toString() );
98 QComboBox
*e
= static_cast<QComboBox
*>(editor
);
99 for(int i
=0; i
<e
->count(); i
++) {
100 if (e
->itemText(i
) == value
) {
101 e
->setCurrentIndex(i
);
107 void TaskItemDelegate::setModelData(QWidget
*editor
, QAbstractItemModel
*model
,
108 const QModelIndex
&index
) const
110 QComboBox
*e
= static_cast<QComboBox
*>(editor
);
111 model
->setData(index
, e
->currentText(), Qt::EditRole
);
112 model
->setData(index
, e
->itemIcon(e
->currentIndex()), Qt::DecorationRole
);
115 void TaskItemDelegate::updateEditorGeometry(QWidget
*editor
,
116 const QStyleOptionViewItem
&option
, const QModelIndex
&/* index */) const
118 editor
->setGeometry(option
.rect
);
121 //END TaskItemDelegate
124 //BEGIN SubTaskItemDelegate
126 SubTaskItemDelegate::SubTaskItemDelegate(Sak
* s
, QObject
*parent
)
127 : QItemDelegate(parent
), m_sak(s
)
131 QWidget
*SubTaskItemDelegate::createEditor(QWidget
*parent
,
132 const QStyleOptionViewItem
&/* option */,
133 const QModelIndex
& index
) const
135 QComboBox
*editor
= new QComboBox(parent
);
136 editor
->setEditable(true);
139 QString taskTitle
= index
.model()->index(index
.row(), index
.column()-1, index
.parent()).data().toString();
141 QHash
<QString
, Task
>::iterator titr
= m_sak
->tasks()->find(taskTitle
);
142 if (titr
== m_sak
->tasks()->end()) {
145 const Task
& task(titr
.value());
147 QString current
= index
.data().toString();
148 QHash
< QString
, Task::SubTask
>::const_iterator itr
= task
.subTasks
.begin(), end
= task
.subTasks
.end();
149 for(int i
=0; itr
!= end
; itr
++, i
++) {
150 editor
->addItem(itr
->title
);
151 if (itr
->title
== current
)
155 editor
->setCurrentIndex(j
);
159 void SubTaskItemDelegate::setEditorData(QWidget
*editor
,
160 const QModelIndex
&index
) const
162 const QString
& value ( index
.data().toString() );
164 QComboBox
*e
= static_cast<QComboBox
*>(editor
);
165 for(int i
=0; i
<e
->count(); i
++) {
166 if (e
->itemText(i
) == value
) {
167 e
->setCurrentIndex(i
);
173 void SubTaskItemDelegate::setModelData(QWidget
*editor
, QAbstractItemModel
*model
,
174 const QModelIndex
&index
) const
176 QComboBox
*e
= static_cast<QComboBox
*>(editor
);
177 model
->setData(index
, e
->currentText(), Qt::EditRole
);
178 model
->setData(index
, e
->itemIcon(e
->currentIndex()), Qt::DecorationRole
);
181 void SubTaskItemDelegate::updateEditorGeometry(QWidget
*editor
,
182 const QStyleOptionViewItem
&option
, const QModelIndex
&/* index */) const
184 editor
->setGeometry(option
.rect
);
187 //END TaskItemDelegate
191 void Sak::addDefaultHit()
193 QTreeWidgetItem
* i
= new QTreeWidgetItem
;
194 Task::Hit
p(QDateTime::currentDateTime(), 0);
195 i
->setText(0, p
.timestamp
.toString(DATETIMEFORMAT
));
196 i
->setText(1, m_editedTasks
.begin().key());
197 i
->setIcon(1, m_editedTasks
.begin().value().icon
);
198 i
->setSizeHint(0, QSize(32, 32));
199 i
->setText(3, QString("%1").arg(p
.duration
));
200 i
->setFlags(i
->flags() | Qt::ItemIsEditable
);
201 hitsList
->addTopLevelItem( i
);
203 m_editedTasks
[i
->text(1)].hits
[i
->text(2)] << p
;
204 i
->setData(1, Qt::UserRole
, qVariantFromValue(HitElement(&m_editedTasks
[i
->text(1)], i
->text(2), p
.timestamp
, p
.duration
)));
207 void Sak::exportHits()
209 QString fileName
= QFileDialog::getSaveFileName();
210 QFile
file(fileName
);
211 if (!file
.open(QIODevice::Truncate
|QIODevice::ReadWrite
)) {
212 QMessageBox::warning(0, QString("Error saving"), QString("Error opening file %1").arg(fileName
));
215 QTextStream
stream(&file
);
216 for (int i
=0; i
<hitsList
->topLevelItemCount(); i
++) {
217 QTreeWidgetItem
* w
= hitsList
->topLevelItem ( i
);
218 QString
name(w
->text(1));
219 QDateTime
timestamp(QDateTime::fromString(w
->text(0), DATETIMEFORMAT
));
220 QHash
<QString
, Task
>::iterator titr
= m_tasks
.find(name
);
221 stream
<< w
->text(1) << ";" << w
->text(0) << ";" << w
->text(2) << ";" << w
->text(3) << ";\n";
228 QList
<HitElement
> Sak::createHitsList(const QDateTime
& from
, const QDateTime
& to
)
230 QMap
<QDateTime
, HitElement
> hits
;
231 foreach(const Task
& t
, m_editedTasks
) {
232 QHash
<QString
, QList
< Task::Hit
> > ::const_iterator hitr
= t
.hits
.begin(), hend
= t
.hits
.end();
233 while(hitr
!= hend
) {
234 const QList
< Task::Hit
> & l(hitr
.value());
235 for (int i
=0; i
<l
.count(); i
++) {
236 const QDateTime
& d
= l
[i
].timestamp
;
237 if ( (!from
.isValid() || d
>= from
) && ( !to
.isValid() || d
<= to
) ) {
238 hits
.insertMulti(d
, HitElement((Task
*)&t
, hitr
.key(), d
, l
[i
].duration
));
244 return hits
.values();
248 QMap
<double,QPair
<Task
*, QString
> > Sak::createSummaryList(const QList
<HitElement
>& hits
)
250 QHash
<QPair
<Task
*, QString
>, double> summaryMap
;
251 foreach(const HitElement
& hit
, hits
) {
252 summaryMap
[QPair
<Task
*, QString
>(hit
.task
, hit
.subtask
)] += Task::hours(hit
.duration
);
253 summaryMap
[QPair
<Task
*, QString
>(hit
.task
, "")] += Task::hours(hit
.duration
);
255 QMap
<double, QPair
<Task
*, QString
> > summaryOrderedMap
;
256 QHash
<QPair
<Task
*, QString
>, double>::const_iterator itr
= summaryMap
.begin();
257 while(itr
!= summaryMap
.end()) {
258 summaryOrderedMap
.insertMulti(itr
.value(), itr
.key());
261 return summaryOrderedMap
;
266 void Sak::saveHitChanges()
269 if ( QMessageBox::question ( 0, "Hit list changed", "Hit list has changed: do you want to save changes?", QMessageBox::Save
| QMessageBox::Discard
, QMessageBox::Discard
) == QMessageBox::Save
) {
270 m_tasks
= m_editedTasks
;
271 } else m_editedTasks
= m_tasks
; // undo changes
273 selectedStartDate(QDate());
278 bool Sak::hitsListEventFilter(QEvent
* e
)
280 if (e
->type() == QEvent::ContextMenu
) {
281 QContextMenuEvent
* me
= dynamic_cast<QContextMenuEvent
*>(e
);
282 if (!me
) return false;
283 m_addHitMenu
->popup(me
->globalPos());
285 } else if (e
->type() == QEvent::KeyRelease
) {
286 QKeyEvent
* ke
= dynamic_cast<QKeyEvent
*>(e
);
287 if (!ke
) return false;
288 if ( !hitsList
->hasFocus() || (ke
->key() != Qt::Key_Delete
&& ke
->key() != Qt::Key_Backspace
) ) return false;
289 QList
<QTreeWidgetItem
*> selected
= hitsList
->selectedItems();
290 if (selected
.isEmpty()) return false;
291 foreach(QTreeWidgetItem
* ii
, selected
) {
292 hitsListItemChanged(hitsList
->takeTopLevelItem(hitsList
->indexOfTopLevelItem (ii
)), -1);
295 } else if (e
->type() == QEvent::Hide
) {
297 }/* else if (e->type() == QEvent::Show) {
298 m_editedTasks = m_tasks;
299 selectedStartDate(QDate());
305 void Sak::selectedStartDate(const QDate
& _date
)
308 if (!date
.isValid()) {
309 date
= cal1
->selectedDate();
312 if (sender() != cal1
) {
313 cal1
->setSelectedDate(date
);
315 if (sender() != cal3
) {
316 cal3
->setSelectedDate(date
);
318 if (cal2
->selectedDate() < cal1
->selectedDate()) {
319 cal2
->setSelectedDate(date
.addDays(1));
320 cal4
->setSelectedDate(date
.addDays(1));
322 cal2
->setMinimumDate(date
);
323 cal4
->setMinimumDate(date
);
324 populateHitsList(createHitsList(QDateTime(cal1
->selectedDate()), QDateTime(cal2
->selectedDate())));
326 hitsTimeline
->setPeriod(QDateTime(cal1
->selectedDate()), QDateTime(cal2
->selectedDate()));
329 void Sak::selectedEndDate(const QDate
& _date
)
333 date
= cal1
->selectedDate();
335 if (sender() != cal2
) {
336 cal2
->setSelectedDate(date
);
338 if (sender() != cal4
) {
339 cal4
->setSelectedDate(date
);
341 if (cal1
->selectedDate() > date
) {
342 cal2
->setSelectedDate(cal1
->selectedDate().addDays(1));
343 cal4
->setSelectedDate(cal1
->selectedDate().addDays(1));
345 populateHitsList(createHitsList(QDateTime(cal1
->selectedDate()), QDateTime(cal2
->selectedDate())));
346 hitsTimeline
->setPeriod(QDateTime(cal1
->selectedDate()), QDateTime(cal2
->selectedDate()));
350 void Sak::hitsListItemChanged(QTreeWidgetItem
* i
, int column
)
352 hitsList
->blockSignals(true);
354 // save change in structure m_editedTasks
356 const HitElement
& origHit
= i
->data(1, Qt::UserRole
).value
<HitElement
>();
357 // find hit in m_editedTasks
358 Q_ASSERT(origHit
.task
);
359 Task
& t(*origHit
.task
);
360 Q_ASSERT(m_editedTasks
.contains(t
.title
));
361 Task
& et(m_editedTasks
[t
.title
]);
363 QList
< Task::Hit
>& origList(et
.hits
[origHit
.subtask
]);
365 int hitPosition
= origList
.indexOf(Task::Hit(origHit
.timestamp
, origHit
.duration
));
366 if (hitPosition
==-1) {
367 qWarning() << "CANNOT FIND IN TASK LIST "<< t
.title
<< origHit
.subtask
<< origHit
.timestamp
<< origHit
.duration
;
370 if (!m_editedTasks
.contains(i
->text(1))) {
371 i
->setText(1, t
.title
);
372 qDebug() << "Task " << i
->text(1) << " does not exists -> undo change";
373 } else if (column
== -1) {
374 qDebug() << "remove hit from task " << t
.title
;
375 origList
.takeAt(hitPosition
);
377 qDebug() << "remove hit from task " << t
.title
;
378 origList
.takeAt(hitPosition
);
379 Task
& nt(m_editedTasks
[i
->text(1)]);
380 Task::Hit
p(QDateTime::fromString(i
->text(0), DATETIMEFORMAT
), i
->text(3).toUInt());
381 i
->setData(1, Qt::UserRole
, qVariantFromValue(HitElement(&nt
, i
->text(2), p
.timestamp
, p
.duration
)));
382 qDebug() << "insert hit into task " << i
->text(1) << p
.timestamp
;
383 nt
.hits
[i
->text(2)] << p
;
389 else if (m_editedTasks
.contains(i
->text(column
))) {
390 i
->setIcon(column
, m_editedTasks
[i
->text(column
)].icon
);
392 i
->setIcon(column
, QIcon());
395 hitsList
->blockSignals(false);
398 void Sak::hitsSelectedInList(QTreeWidgetItem
* current
, QTreeWidgetItem
* /*prev*/)
401 // clear current selection
402 QList
<QGraphicsItem
*> sitems
= hitsTimeline
->scene()->selectedItems();
403 for(int j
=0; j
<sitems
.count(); j
++) {
404 HitItem
* tmp
= dynamic_cast<HitItem
*>(sitems
[j
]);
406 tmp
->setZValue(tmp
->timestamp().toTime_t());
407 tmp
->setSelected(false);
412 QPointF
center (QDateTime::fromString(current
->text(0), DATETIMEFORMAT
).toTime_t() / 60.0, 0);
413 int duration
= current
->text(3).toUInt();
414 QList
<QGraphicsItem
*> items
= hitsTimeline
->scene()->items();
415 for(int i
=0; i
<items
.count(); i
++) {
416 HitItem
* hitem
= dynamic_cast<HitItem
*>(items
[i
]);
417 if (hitem
&& hitem
->timestamp() == QDateTime::fromString(current
->text(0), DATETIMEFORMAT
) && hitem
->task()->title
== current
->text(1) && hitem
->subtask() == current
->text(2) && hitem
->duration() == duration
) {
418 hitem
->setZValue(1e20
);
419 hitem
->setSelected(true);
423 hitsTimeline
->centerOn(center
);
427 void Sak::hitsSelectedInTimeline(HitItem
* hitem
)
429 const Task
* t
= hitem
->task();
430 QList
<QTreeWidgetItem
*> items
= hitsList
->findItems(hitem
->timestamp().toString(DATETIMEFORMAT
), Qt::MatchExactly
, 0);
431 qDebug() << "look for " << hitem
->timestamp().toString(DATETIMEFORMAT
);
433 QString
tmp(QString ("%1").arg(hitem
->duration()));
434 qDebug() << "duration " << tmp
;
435 foreach(QTreeWidgetItem
* item
, items
) {
436 if (item
->text(1) == t
->title
&& item
->text(2) == hitem
->subtask() && item
->text(3) == tmp
) {
437 hitsList
->clearSelection();
438 item
->setSelected(true);
439 if (hitem
->timestamp() != hitem
->newTimestamp() || hitem
->duration() != hitem
->newDuration()) {
440 item
->setText(0, hitem
->newTimestamp().toString(DATETIMEFORMAT
));
441 item
->setText(3, QString("%1").arg(hitem
->newDuration()));
442 hitem
->commitChanges();
444 hitsList
->scrollToItem(item
);
451 void Sak::populateHitsList(const QList
<HitElement
>& hits
, QTreeWidget
* theHitsList
)
453 if (theHitsList
== 0)
454 theHitsList
= hitsList
;
455 Q_ASSERT(theHitsList
);
457 theHitsList
->clear();
460 double totOverestimation
;
461 HitElement::overestimations(hits
, o
, totOverestimation
);
462 QList
<QTreeWidgetItem
*> widgets
;
464 foreach(const HitElement
& hit
, hits
) {
465 QTreeWidgetItem
* w
= new QTreeWidgetItem
;
466 w
->setText(0, hit
.timestamp
.toString(DATETIMEFORMAT
));
467 w
->setText(1, hit
.task
->title
);
468 w
->setSizeHint(0, QSize(24, 24));
469 w
->setData(1, Qt::UserRole
, qVariantFromValue(hit
));
470 w
->setText(2, hit
.subtask
);
471 w
->setText(3, QString("%1").arg(hit
.duration
));
472 if (hit
.task
->title
== "<away>") {
473 for(int i
=0; i
<4; i
++) {
474 w
->setForeground(i
,Qt::gray
);
477 for(int i
=0; i
<4; i
++) {
478 w
->setBackground(i
,hit
.task
->bgColor
);
479 w
->setForeground(i
,hit
.task
->fgColor
);
481 #if MARK_OVERESTIMATIONS
483 w
->setBackground(0,Qt::red
);
484 w
->setBackground(1,Qt::red
);
485 w
->setBackground(2,Qt::red
);
486 w
->setBackground(3,Qt::red
);
487 w
->setBackground(4,Qt::red
);
488 w
->setText(4,QString("%1").arg(o
[i
]));
490 w
->setText(4,QString("%1").arg(o
[i
]));
493 w
->setIcon(1, hit
.task
->icon
);
495 w
->setFlags(w
->flags() | Qt::ItemIsEditable
);
496 else w
->setDisabled(true);
500 theHitsList
->addTopLevelItems(widgets
);
505 theHitsList
= summaryList
;
506 theHitsList
->clear();
507 const QMap
<double, QPair
<Task
*, QString
> >& map(createSummaryList(hits
));
508 QMap
<double, QPair
<Task
*, QString
> >::const_iterator itr
= map
.begin();
509 QHash
<Task
*, QTreeWidgetItem
*> topLevels
;
510 for(; itr
!= map
.end(); itr
++) { // first be sure to insert top levels
511 QTreeWidgetItem
* topLevel
;
512 if (!topLevels
.contains(itr
.value().first
)) {
513 QTreeWidgetItem
* w
= new QTreeWidgetItem(QTreeWidgetItem::UserType
);
514 w
->setText(0, itr
.value().first
->title
);
515 w
->setIcon(0, itr
.value().first
->icon
);
516 topLevels
[itr
.value().first
] = w
;
518 topLevel
= topLevels
[itr
.value().first
];
519 if (itr
.value().second
== "")
520 topLevel
->setText(1, QString("%1").arg(topLevel
->text(1).toInt() + itr
.key(), 4, 'f', 2, ' '));
521 if (!itr
.value().second
.isEmpty()) {
522 QTreeWidgetItem
* w
= new QTreeWidgetItem(QTreeWidgetItem::UserType
);
523 w
->setText(0, itr
.value().second
);
524 w
->setText(1, QString("%1").arg(itr
.key(), 4, 'f', 2, ' '));
525 topLevel
->addChild(w
);
529 theHitsList
->addTopLevelItems(topLevels
.values());
532 populateHitsTimeline(hits
, hitsTimeline
);
535 void Sak::populateHitsTimeline(const QList
<HitElement
>& hits
, Timeline
* timeline
)
537 if (!timeline
) return;
538 QGraphicsScene
* scene
= timeline
->scene();
540 QList
<QGraphicsItem
*> items
= scene
->items();
541 foreach(QGraphicsItem
* item
, items
) {
542 if (dynamic_cast<HitItem
*>(item
)) {
543 scene
->removeItem(item
);
547 foreach(HitElement e
, hits
) {
548 HitItem
* item
= new HitItem(e
.task
, e
.timestamp
, e
.duration
, e
.subtask
);
549 connect(item
, SIGNAL(changed()), timeline
, SLOT(selectionChanged()));
550 scene
->addItem(item
);
556 void Sak::interactiveMergeHits()
558 if (!m_incremental
->foundPieces
.count()) return;
560 mergeDialog
.setWindowTitle("Merge sparse hits");
561 mergeDialog
.setModal(true);
562 QTreeWidget
* theHitsList
= newHitsList();
563 QMap
<QDateTime
, HitElement
> hits
;
564 QMap
<QDateTime
, Incremental::Hit
>::iterator itr
= m_incremental
->foundPieces
.begin();
565 while(itr
!= m_incremental
->foundPieces
.end()) {
566 QHash
<QString
, Task
>::iterator titr
= m_tasks
.find(itr
.value().task
);
567 if (titr
== m_tasks
.end()) {
568 qDebug() << "Discard piece for unknown task " << itr
.value().task
;
570 hits
.insertMulti(itr
.key(), HitElement(&titr
.value(), itr
.value().subtask
, itr
.key(), itr
.value().duration
));
574 if (hits
.count() == 0) return;
576 qDebug() << "hits: " << hits
.count() << hits
.begin().key() << (--hits
.end()).key();
577 QList
<HitElement
> okHits (createHitsList(hits
.begin().key(), (--hits
.end()).key()));
578 QMap
<QDateTime
, HitElement
> tmpHits
;
579 for(int i
=0; i
<okHits
.count(); i
++) {
580 HitElement
& cmp(okHits
[i
]);
581 QMap
<QDateTime
, HitElement
>::iterator itr
= hits
.find(cmp
.timestamp
);
583 while(itr
!= hits
.end() && itr
.key() == cmp
.timestamp
) {
584 const HitElement
& cur ( itr
.value() );
585 if (cmp
.task
->title
== cur
.task
->title
&& cmp
.subtask
== cur
.subtask
&& cmp
.duration
== cur
.duration
) {
586 itr
= hits
.erase(itr
);
591 okHits
[i
].editable
=false;
592 tmpHits
.insertMulti(okHits
[i
].timestamp
, okHits
[i
]);
595 if (!hits
.count()) return;
596 else hits
.unite(tmpHits
);
598 populateHitsList(hits
.values(), theHitsList
);
599 mergeDialog
.setMinimumWidth(750);
600 mergeDialog
.setMinimumHeight(600);
601 QVBoxLayout
mainLayout(&mergeDialog
);
602 mainLayout
.addWidget(theHitsList
);
603 QPushButton
* ok
= new QPushButton("Do merge!");
604 QPushButton
* cancel
= new QPushButton("Cancel");
605 QHBoxLayout
* buttons
= new QHBoxLayout
;
606 buttons
->addWidget(ok
);
607 buttons
->addWidget(cancel
);
608 mainLayout
.addLayout(buttons
);
609 connect(ok
, SIGNAL(clicked()), &mergeDialog
, SLOT(accept()));
610 connect(cancel
, SIGNAL(clicked()), &mergeDialog
, SLOT(reject()));
612 if ( mergeDialog
.exec() ) {
613 for (int i
=0; i
<theHitsList
->topLevelItemCount(); i
++) {
614 QTreeWidgetItem
* w
= theHitsList
->topLevelItem ( i
);
615 if (!w
->isDisabled()) {
616 QString
name(w
->text(1));
617 QDateTime
timestamp(QDateTime::fromString(w
->text(0), DATETIMEFORMAT
));
618 int duration (w
->text(3).toUInt());
619 QHash
<QString
, Task
>::iterator titr
= m_tasks
.find(name
);
620 Q_ASSERT(titr
!= m_tasks
.end());
621 (*titr
).hits
[w
->text(2)] << Task::Hit(timestamp
, duration
);
625 m_incremental
->clearMergedPieces();