File indexing completed on 2024-04-28 08:49:24

0001 /* This file is part of the KDE project
0002 
0003    Copyright (C) 2006 Dario Massarin <nekkar@libero.it>
0004    Copyright (C) 2009 Lukas Appelhans <l.appelhans@gmx.de>
0005    Copyright (C) 2010 Matthias Fuchs <mat69@gmx.net>
0006 
0007    This program is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 */
0012 
0013 #include "core/transfertreemodel.h"
0014 
0015 #include "core/kget.h"
0016 #include "core/transfergrouphandler.h"
0017 #include "core/transferhandler.h"
0018 #include "core/transfertreeselectionmodel.h"
0019 #include "dbus/dbustransferwrapper.h"
0020 #include "kget_debug.h"
0021 #include "settings.h"
0022 #include "transferadaptor.h"
0023 #include "transfergroupscheduler.h"
0024 
0025 #include <algorithm>
0026 
0027 #include <QDebug>
0028 
0029 #include <KIO/Global>
0030 #include <KLocalizedString>
0031 
0032 ItemMimeData::ItemMimeData()
0033     : QMimeData()
0034 {
0035 }
0036 
0037 ItemMimeData::~ItemMimeData()
0038 {
0039 }
0040 
0041 void ItemMimeData::appendTransfer(const QPointer<TransferHandler> &transfer)
0042 {
0043     m_transfers.append(transfer);
0044 }
0045 
0046 QList<QPointer<TransferHandler>> ItemMimeData::transfers() const
0047 {
0048     return m_transfers;
0049 }
0050 
0051 ModelItem::ModelItem(Handler *handler)
0052     : QStandardItem()
0053     , m_handler(handler)
0054 {
0055 }
0056 
0057 ModelItem::~ModelItem()
0058 {
0059 }
0060 
0061 void ModelItem::emitDataChanged()
0062 {
0063     QStandardItem::emitDataChanged();
0064 }
0065 
0066 Handler *ModelItem::handler()
0067 {
0068     return m_handler;
0069 }
0070 
0071 bool ModelItem::isGroup()
0072 {
0073     return false;
0074 }
0075 
0076 GroupModelItem *ModelItem::asGroup()
0077 {
0078     return dynamic_cast<GroupModelItem *>(this);
0079 }
0080 
0081 TransferModelItem *ModelItem::asTransfer()
0082 {
0083     return dynamic_cast<TransferModelItem *>(this);
0084 }
0085 
0086 TransferModelItem::TransferModelItem(TransferHandler *handler)
0087     : ModelItem(handler)
0088     , m_transferHandler(handler)
0089 {
0090 }
0091 
0092 TransferModelItem::~TransferModelItem()
0093 {
0094 }
0095 
0096 QVariant TransferModelItem::data(int role) const
0097 {
0098     if (role == Qt::DisplayRole)
0099         return m_transferHandler->data(column());
0100     else if (role == Qt::DecorationRole) {
0101         switch (column()) {
0102         case 0: {
0103             // store the icon for speed improvements, KIconLoader should make sure, that
0104             // the icon data gets shared
0105             if (m_mimeType.isNull()) {
0106                 m_mimeType = QIcon::fromTheme(KIO::iconNameForUrl(m_transferHandler->dest()));
0107             }
0108 
0109             return m_mimeType;
0110         }
0111         case 1:
0112             return QIcon::fromTheme(m_transferHandler->statusIconName());
0113         }
0114     }
0115     if (role == Qt::TextAlignmentRole) {
0116         switch (column()) {
0117         case 0: // name
0118             return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
0119         default:
0120             return Qt::AlignCenter;
0121         }
0122     }
0123     // KextendableItemDelegate::ShowExtensionIndicatorRole
0124     // tells the KExtendableItemDelegate which column contains the extender icon
0125     if (role == Qt::UserRole + 200) {
0126         if (column() == 0)
0127             return true;
0128         else
0129             return false;
0130     }
0131     return QVariant();
0132 }
0133 
0134 TransferHandler *TransferModelItem::transferHandler()
0135 {
0136     return m_transferHandler;
0137 }
0138 
0139 GroupModelItem::GroupModelItem(TransferGroupHandler *handler)
0140     : ModelItem(handler)
0141     , m_groupHandler(handler)
0142 {
0143 }
0144 
0145 GroupModelItem::~GroupModelItem()
0146 {
0147 }
0148 
0149 QVariant GroupModelItem::data(int role) const
0150 {
0151     if (role == Qt::DisplayRole) {
0152         return m_groupHandler->data(column());
0153     }
0154     if (role == Qt::TextAlignmentRole) {
0155         switch (column()) {
0156         case 0: // name
0157             return Qt::AlignVCenter;
0158         case 2: // size
0159         case 3: // speed
0160         case 4: // progress
0161             return Qt::AlignCenter;
0162         default:
0163             return QVariant(Qt::AlignLeft | Qt::AlignBottom);
0164         }
0165     }
0166     if (role == Qt::DecorationRole && column() == 0)
0167         return m_groupHandler->pixmap();
0168     return QVariant();
0169 }
0170 
0171 TransferGroupHandler *GroupModelItem::groupHandler()
0172 {
0173     // qDebug() << m_groupHandler->name();
0174     return m_groupHandler;
0175 }
0176 
0177 bool GroupModelItem::isGroup()
0178 {
0179     return true;
0180 }
0181 
0182 TransferTreeModel::TransferTreeModel(Scheduler *scheduler)
0183     : QStandardItemModel()
0184     , m_scheduler(scheduler)
0185     , m_timerId(-1)
0186 {
0187     m_transferGroups.clear();
0188     m_transfers.clear();
0189 }
0190 
0191 TransferTreeModel::~TransferTreeModel()
0192 {
0193 }
0194 
0195 void TransferTreeModel::addGroup(TransferGroup *group)
0196 {
0197     QList<QStandardItem *> items;
0198     for (int i = 0; i != group->handler()->columnCount(); i++)
0199         items << new GroupModelItem(group->handler());
0200 
0201     appendRow(items);
0202 
0203     m_transferGroups.append(static_cast<GroupModelItem *>(items.first()));
0204 
0205     Q_EMIT groupAddedEvent(group->handler());
0206 
0207     KGet::m_scheduler->addQueue(group);
0208 }
0209 
0210 void TransferTreeModel::delGroup(TransferGroup *group)
0211 {
0212     if (m_transferGroups.count() <= 1) // If there is only one group left, we should not remove it
0213         return;
0214     GroupModelItem *item = itemFromTransferGroupHandler(group->handler());
0215     if (!item) {
0216         return;
0217     }
0218 
0219     QList<Transfer *> transfers;
0220     JobQueue::iterator it;
0221     JobQueue::iterator itEnd = group->end();
0222     for (it = group->begin(); it != itEnd; ++it) {
0223         transfers << static_cast<Transfer *>(*it);
0224     }
0225     delTransfers(transfers);
0226 
0227     m_transferGroups.removeAll(item);
0228     removeRow(item->row());
0229 
0230     m_changedGroups.removeAll(group->handler());
0231 
0232     Q_EMIT groupRemovedEvent(group->handler());
0233 
0234     KGet::m_scheduler->delQueue(group);
0235 }
0236 
0237 void TransferTreeModel::addTransfers(const QList<Transfer *> &transfers, TransferGroup *group)
0238 {
0239     ModelItem *parentItem = itemFromTransferGroupHandler(group->handler());
0240     beginInsertRows(parentItem->index(), parentItem->rowCount(), parentItem->rowCount() + transfers.count() - 1);
0241 
0242     // HACK blocks all signals from the model when adding multiple items,
0243     // that way rowsInserted gets only emitted once, and not constantly when doing appendRow
0244     // change this once there is a better way to append many transfers at once
0245     blockSignals(true);
0246 
0247     // now create and add the new items
0248     QList<TransferHandler *> handlers;
0249     group->append(transfers);
0250     foreach (Transfer *transfer, transfers) {
0251         TransferHandler *handler = transfer->handler();
0252         handlers << handler;
0253 
0254         QList<QStandardItem *> items;
0255         for (int i = 0; i != handler->columnCount(); ++i) {
0256             items << new TransferModelItem(handler);
0257         }
0258 
0259         parentItem->appendRow(items);
0260 
0261         m_transfers.append(static_cast<TransferModelItem *>(items.first()));
0262 
0263         auto *wrapper = new DBusTransferWrapper(handler);
0264         new TransferAdaptor(wrapper);
0265         QDBusConnection::sessionBus().registerObject(handler->dBusObjectPath(), wrapper);
0266     }
0267 
0268     // notify the rest of the changes
0269     blockSignals(false);
0270     endInsertRows();
0271     Q_EMIT transfersAddedEvent(handlers);
0272 }
0273 
0274 void TransferTreeModel::delTransfers(const QList<Transfer *> &t)
0275 {
0276     QList<Transfer *> transfers = t;
0277     QList<TransferHandler *> handlers;
0278 
0279     // find all valid items and sort them according to their groups
0280     QHash<TransferGroup *, QList<TransferModelItem *>> groups;
0281     QHash<TransferGroup *, QList<Transfer *>> groupsTransfer;
0282     {
0283         QList<Transfer *>::iterator it;
0284         QList<Transfer *>::iterator itEnd = transfers.end();
0285         for (it = transfers.begin(); it != itEnd;) {
0286             TransferModelItem *item = itemFromTransferHandler((*it)->handler());
0287             if (item) {
0288                 handlers << (*it)->handler();
0289                 groups[(*it)->group()] << item;
0290                 groupsTransfer[(*it)->group()] << *it;
0291                 ++it;
0292             } else {
0293                 it = transfers.erase(it);
0294             }
0295         }
0296     }
0297 
0298     Q_EMIT transfersAboutToBeRemovedEvent(handlers);
0299 
0300     // remove the items from the model
0301     {
0302         QHash<TransferGroup *, QList<TransferModelItem *>>::iterator it;
0303         QHash<TransferGroup *, QList<TransferModelItem *>>::iterator itEnd = groups.end();
0304         for (it = groups.begin(); it != itEnd; ++it) {
0305             const int numItems = (*it).count();
0306             QStandardItem *parentItem = (*it).first()->parent();
0307             QModelIndex parentIndex = parentItem->index();
0308             if (numItems == parentItem->rowCount()) {
0309                 for (int i = 0; i < numItems; ++i) {
0310                     m_transfers.removeAll((*it)[i]);
0311                 }
0312                 removeRows(0, numItems, parentIndex);
0313                 continue;
0314             }
0315 
0316             int rowStart = (*it).first()->row();
0317             int numRows = 1;
0318             m_transfers.removeAll((*it).first());
0319             for (int i = 1; i < numItems; ++i) {
0320                 // previous item is neighbour
0321                 if (rowStart + numRows == (*it)[i]->row()) {
0322                     ++numRows;
0323                     // no neighbour, so start again
0324                 } else {
0325                     removeRows(rowStart, numRows, parentIndex);
0326                     rowStart = (*it)[i]->row();
0327                     numRows = 1;
0328                 }
0329                 m_transfers.removeAll((*it)[i]);
0330             }
0331             // remove last items
0332             removeRows(rowStart, numRows, parentIndex);
0333         }
0334     }
0335 
0336     foreach (Transfer *transfer, transfers) {
0337         QDBusConnection::sessionBus().unregisterObject(transfer->handler()->dBusObjectPath());
0338         m_changedTransfers.removeAll(transfer->handler());
0339     }
0340 
0341     {
0342         QHash<TransferGroup *, QList<Transfer *>>::iterator it;
0343         QHash<TransferGroup *, QList<Transfer *>>::iterator itEnd = groupsTransfer.end();
0344         for (it = groupsTransfer.begin(); it != itEnd; ++it) {
0345             it.key()->remove(it.value());
0346         }
0347     }
0348 
0349     Q_EMIT transfersRemovedEvent(handlers);
0350 }
0351 
0352 TransferModelItem *TransferTreeModel::itemFromTransferHandler(TransferHandler *handler)
0353 {
0354     foreach (TransferModelItem *item, m_transfers) {
0355         if (handler == item->transferHandler())
0356             return item;
0357     }
0358     return nullptr;
0359 }
0360 
0361 GroupModelItem *TransferTreeModel::itemFromTransferGroupHandler(TransferGroupHandler *handler)
0362 {
0363     foreach (GroupModelItem *item, m_transferGroups) {
0364         if (handler == item->groupHandler())
0365             return item;
0366     }
0367     return nullptr;
0368 }
0369 
0370 ModelItem *TransferTreeModel::itemFromHandler(Handler *handler)
0371 {
0372     auto *transfer = qobject_cast<TransferHandler *>(handler);
0373     if (transfer) {
0374         return itemFromTransferHandler(transfer);
0375     }
0376     return itemFromTransferGroupHandler(qobject_cast<TransferGroupHandler *>(handler));
0377 }
0378 
0379 ModelItem *TransferTreeModel::itemFromIndex(const QModelIndex &index) const
0380 {
0381     QStandardItem *item = QStandardItemModel::itemFromIndex(index);
0382     if (item)
0383         return dynamic_cast<ModelItem *>(item);
0384     return nullptr;
0385 }
0386 
0387 void TransferTreeModel::moveTransfer(Transfer *transfer, TransferGroup *destGroup, Transfer *after)
0388 {
0389     if ((after) && (destGroup != after->group()))
0390         return;
0391 
0392     int position = transfer->group()->indexOf(transfer);
0393 
0394     TransferGroup *oldGroup = transfer->group();
0395 
0396     bool sameGroup = false;
0397 
0398     if (destGroup == transfer->group()) {
0399         sameGroup = true;
0400         if (after)
0401             destGroup->move(transfer, after);
0402         else
0403             destGroup->move(transfer, nullptr);
0404     } else {
0405         transfer->group()->remove(transfer);
0406 
0407         if (after)
0408             destGroup->insert(transfer, after);
0409         else
0410             destGroup->prepend(transfer);
0411 
0412         transfer->m_jobQueue = destGroup;
0413     }
0414     QList<QStandardItem *> items = itemFromHandler(oldGroup->handler())->takeRow(position);
0415     itemFromHandler(destGroup->handler())->insertRow(destGroup->indexOf(transfer), items);
0416 
0417     if (!sameGroup)
0418         Q_EMIT transferMovedEvent(transfer->handler(), destGroup->handler());
0419 
0420     KGet::selectionModel()->clearSelection();
0421 }
0422 
0423 void TransferTreeModel::moveTransfer(TransferHandler *transfer, TransferGroupHandler *destGroup, TransferHandler *after)
0424 {
0425     Transfer *afterTransfer = nullptr;
0426     if (after) {
0427         afterTransfer = after->m_transfer;
0428     }
0429     moveTransfer(transfer->m_transfer, destGroup->m_group, afterTransfer);
0430 }
0431 
0432 QList<TransferGroup *> TransferTreeModel::transferGroups()
0433 {
0434     QList<TransferGroup *> transferGroups;
0435     foreach (GroupModelItem *item, m_transferGroups) {
0436         transferGroups << item->groupHandler()->m_group;
0437     }
0438 
0439     return transferGroups;
0440 }
0441 
0442 TransferGroup *TransferTreeModel::findGroup(const QString &groupName)
0443 {
0444     foreach (GroupModelItem *group, m_transferGroups) {
0445         if (group->groupHandler()->name() == groupName)
0446             return group->groupHandler()->m_group;
0447     }
0448     return nullptr;
0449 }
0450 
0451 Transfer *TransferTreeModel::findTransfer(const QUrl &src)
0452 {
0453     /*foreach (TransferGroup * group, transferGroups())
0454     {
0455         Transfer * t = group->findTransfer(src);
0456         if (t)
0457             return t;
0458     }*/
0459     foreach (TransferModelItem *transfer, m_transfers) {
0460         if (transfer->transferHandler()->source() == src)
0461             return transfer->transferHandler()->m_transfer;
0462     }
0463     return nullptr;
0464 }
0465 
0466 Transfer *TransferTreeModel::findTransferByDestination(const QUrl &dest)
0467 {
0468     /*foreach (TransferGroup * group, transferGroups())
0469     {
0470         Transfer * t = group->findTransferByDestination(dest);
0471         if (t)
0472             return t;
0473     }*/
0474     foreach (TransferModelItem *transfer, m_transfers) {
0475         if (transfer->transferHandler()->dest() == dest)
0476             return transfer->transferHandler()->m_transfer;
0477     }
0478     return nullptr;
0479 }
0480 
0481 Transfer *TransferTreeModel::findTransferByDBusObjectPath(const QString &dbusObjectPath)
0482 {
0483     foreach (TransferModelItem *transfer, m_transfers) {
0484         if (transfer->transferHandler()->dBusObjectPath() == dbusObjectPath)
0485             return transfer->transferHandler()->m_transfer;
0486     }
0487     return nullptr;
0488 }
0489 
0490 void TransferTreeModel::postDataChangedEvent(TransferHandler *transfer)
0491 {
0492     if (m_timerId == -1)
0493         m_timerId = startTimer(500);
0494 
0495     m_changedTransfers.append(transfer);
0496 }
0497 
0498 void TransferTreeModel::postDataChangedEvent(TransferGroupHandler *group)
0499 {
0500     if (m_timerId == -1)
0501         m_timerId = startTimer(500);
0502 
0503     m_changedGroups.append(group);
0504 }
0505 
0506 Qt::ItemFlags TransferTreeModel::flags(const QModelIndex &index) const
0507 {
0508     //     qCDebug(KGET_DEBUG) << "TransferTreeModel::flags()";
0509     if (!index.isValid())
0510         return Qt::ItemIsEnabled;
0511 
0512     Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
0513 
0514     if (!index.parent().isValid()) {
0515         if (index.column() == 0)
0516             flags |= Qt::ItemIsDropEnabled;
0517     } else
0518         flags |= Qt::ItemIsDragEnabled;
0519 
0520     // flags |= Qt::ItemIsDropEnabled;
0521 
0522     // We can edit all the groups but the default one
0523     if (index.row() > 0) {
0524         flags |= Qt::ItemIsEditable;
0525     }
0526 
0527     return flags;
0528 }
0529 
0530 QVariant TransferTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
0531 {
0532     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
0533         return columnName(section);
0534     }
0535 
0536     return QVariant();
0537 }
0538 
0539 Qt::DropActions TransferTreeModel::supportedDropActions() const
0540 {
0541     return Qt::CopyAction | Qt::MoveAction;
0542 }
0543 
0544 QStringList TransferTreeModel::mimeTypes() const
0545 {
0546     QStringList types;
0547     types << "kget/transfer_pointer";
0548     return types;
0549 }
0550 
0551 QMimeData *TransferTreeModel::mimeData(const QModelIndexList &indexes) const
0552 {
0553     auto *mimeData = new ItemMimeData();
0554 
0555     QModelIndexList sortedIndexes = indexes;
0556     std::sort(sortedIndexes.begin(), sortedIndexes.end(), [](const QModelIndex &a, const QModelIndex &b) {
0557         return b < a;
0558     });
0559     foreach (const QModelIndex &index, sortedIndexes) {
0560         if (index.isValid() && index.column() == 0 && index.parent().isValid()) {
0561             ModelItem *item = itemFromIndex(index);
0562             if (!item->isGroup()) {
0563                 mimeData->appendTransfer(QPointer<TransferHandler>(item->asTransfer()->transferHandler()));
0564             }
0565         }
0566     }
0567 
0568     mimeData->setData("kget/transfer_pointer", QByteArray());
0569     return mimeData;
0570 }
0571 
0572 bool TransferTreeModel::dropMimeData(const QMimeData *mdata, Qt::DropAction action, int row, int column, const QModelIndex &parent)
0573 {
0574     if (action == Qt::IgnoreAction)
0575         return true;
0576 
0577     const auto *itemData = qobject_cast<const ItemMimeData *>(mdata);
0578     if (!itemData) {
0579         qCWarning(KGET_DEBUG) << "Unsupported mime data dropped.";
0580         return false;
0581     }
0582 
0583     TransferGroup *destGroup = findGroup(data(parent, Qt::DisplayRole).toString());
0584     if (!destGroup) {
0585         qCWarning(KGET_DEBUG) << "No group could be found where the transfers should be inserted to.";
0586         return false;
0587     }
0588 
0589     if (parent.isValid())
0590         qCDebug(KGET_DEBUG) << "TransferTreeModel::dropMimeData"
0591                             << " " << row << " " << column;
0592 
0593     QList<QPointer<TransferHandler>> transfers = itemData->transfers();
0594     qCDebug(KGET_DEBUG) << "TransferTreeModel::dropMimeData:" << transfers.count() << "transfers.";
0595 
0596     const bool droppedInsideGroup = parent.isValid();
0597     Transfer *after = nullptr;
0598     for (int i = 0; i < transfers.count(); ++i) {
0599         bool b = destGroup->size() > row && row - 1 >= 0;
0600         if (b)
0601             qCDebug(KGET_DEBUG) << "TRANSFER AFTER:" << destGroup->operator[](row - 1)->source();
0602         else
0603             qCDebug(KGET_DEBUG) << "TRANSFER AFTER NOT EXISTING";
0604 
0605         if (!after) {
0606             bool rowValid = (row - 1 >= 0) && (destGroup->size() >= row);
0607             if (droppedInsideGroup && rowValid) {
0608                 after = destGroup->operator[](row - 1); // insert at the correct position
0609             }
0610         }
0611 
0612         if (transfers[i].isNull()) {
0613             qWarning() << "The moved transfer has been deleted inbetween.";
0614         } else {
0615             moveTransfer(transfers[i].data()->m_transfer, destGroup, after);
0616         }
0617     }
0618     return true;
0619 }
0620 
0621 QString TransferTreeModel::columnName(int column)
0622 {
0623     switch (column) {
0624     case 0:
0625         return i18nc("name of download", "Name");
0626     case 1:
0627         return i18nc("status of download", "Status");
0628     case 2:
0629         return i18nc("size of download", "Size");
0630     case 3:
0631         return i18nc("progress of download", "Progress");
0632     case 4:
0633         return i18nc("speed of download", "Speed");
0634     case 5:
0635         return i18nc("remaining time of download", "Remaining Time");
0636     }
0637     return QString();
0638 }
0639 
0640 int TransferTreeModel::column(Transfer::TransferChange flag)
0641 {
0642     switch (flag) {
0643     case Transfer::Tc_FileName:
0644         return 0;
0645     case Transfer::Tc_Status:
0646         return 1;
0647     case Transfer::Tc_TotalSize:
0648         return 2;
0649     case Transfer::Tc_Percent:
0650         return 3;
0651     case Transfer::Tc_DownloadSpeed:
0652         return 4;
0653     case Transfer::Tc_RemainingTime:
0654         return 5;
0655     default:
0656         return -1;
0657     }
0658     return -1;
0659 }
0660 
0661 int TransferTreeModel::column(TransferGroup::GroupChange flag)
0662 {
0663     switch (flag) {
0664     case TransferGroup::Gc_GroupName:
0665         return 0;
0666     case TransferGroup::Gc_Status:
0667         return 1;
0668     case TransferGroup::Gc_TotalSize:
0669         return 2;
0670     case TransferGroup::Gc_Percent:
0671         return 3;
0672     case TransferGroup::Gc_DownloadSpeed:
0673         return 4;
0674     default:
0675         return -1;
0676     }
0677     return -1;
0678 }
0679 
0680 void TransferTreeModel::timerEvent(QTimerEvent *event)
0681 {
0682     Q_UNUSED(event)
0683     //     qCDebug(KGET_DEBUG) << "TransferTreeModel::timerEvent";
0684 
0685     QMap<TransferHandler *, Transfer::ChangesFlags> updatedTransfers;
0686     QMap<TransferGroupHandler *, TransferGroup::ChangesFlags> updatedGroups;
0687 
0688     foreach (TransferHandler *transfer, m_changedTransfers) {
0689         if (!updatedTransfers.contains(transfer)) {
0690             TransferGroupHandler *group = transfer->group();
0691             ModelItem *item = itemFromHandler(group);
0692             Transfer::ChangesFlags changesFlags = transfer->changesFlags();
0693 
0694             Q_EMIT transfer->transferChangedEvent(transfer, changesFlags);
0695 
0696             int row = group->indexOf(transfer);
0697 
0698             //             qCDebug(KGET_DEBUG) << "CHILD = " << item->child(row, column(Transfer::Tc_FileName));
0699 
0700             // Now, check that model child items already exist (there are some cases when the transfer
0701             // can notify for changes before the gui has been correctly initialized)
0702             if (item->child(row, 0)) {
0703                 if (changesFlags & Transfer::Tc_FileName)
0704                     static_cast<ModelItem *>(item->child(row, column(Transfer::Tc_FileName)))->emitDataChanged();
0705                 if (changesFlags & Transfer::Tc_Status)
0706                     static_cast<ModelItem *>(item->child(row, column(Transfer::Tc_Status)))->emitDataChanged();
0707                 if (changesFlags & Transfer::Tc_TotalSize)
0708                     static_cast<ModelItem *>(item->child(row, column(Transfer::Tc_TotalSize)))->emitDataChanged();
0709                 if (changesFlags & Transfer::Tc_Percent)
0710                     static_cast<ModelItem *>(item->child(row, column(Transfer::Tc_Percent)))->emitDataChanged();
0711                 if (changesFlags & Transfer::Tc_DownloadSpeed)
0712                     static_cast<ModelItem *>(item->child(row, column(Transfer::Tc_DownloadSpeed)))->emitDataChanged();
0713                 if (changesFlags & Transfer::Tc_RemainingTime)
0714                     static_cast<ModelItem *>(item->child(row, column(Transfer::Tc_RemainingTime)))->emitDataChanged();
0715 
0716                 transfer->resetChangesFlags();
0717                 updatedTransfers.insert(transfer, changesFlags);
0718             }
0719         }
0720     }
0721 
0722     if (!updatedTransfers.isEmpty())
0723         Q_EMIT transfersChangedEvent(updatedTransfers);
0724 
0725     foreach (TransferGroupHandler *group, m_changedGroups) {
0726         if (!updatedGroups.contains(group)) {
0727             TransferGroup::ChangesFlags changesFlags = group->changesFlags();
0728 
0729             Q_EMIT group->groupChangedEvent(group, changesFlags);
0730 
0731             int row = itemFromHandler(group)->row();
0732 
0733             if (changesFlags & TransferGroup::Gc_GroupName)
0734                 static_cast<ModelItem *>(item(row, column(TransferGroup::Gc_GroupName)))->emitDataChanged();
0735             if (changesFlags & TransferGroup::Gc_Status)
0736                 static_cast<ModelItem *>(item(row, column(TransferGroup::Gc_Status)))->emitDataChanged();
0737             if (changesFlags & TransferGroup::Gc_TotalSize)
0738                 static_cast<ModelItem *>(item(row, column(TransferGroup::Gc_TotalSize)))->emitDataChanged();
0739             if (changesFlags & TransferGroup::Gc_Percent)
0740                 static_cast<ModelItem *>(item(row, column(TransferGroup::Gc_Percent)))->emitDataChanged();
0741             if (changesFlags & TransferGroup::Gc_DownloadSpeed)
0742                 static_cast<ModelItem *>(item(row, column(TransferGroup::Gc_DownloadSpeed)))->emitDataChanged();
0743 
0744             /*for(int i=0; i<8; i++)
0745             {
0746                 if(((changesFlags >> i) & 0x00000001))
0747                 {
0748                     QStandardItem *groupItem = itemFromHandler(group);
0749                     dynamic_cast<ModelItem*>(invisibleRootItem()->child(groupItem->row(), i))->emitDataChanged();
0750                     //QModelIndex index = createIndex(m_transferGroups.indexOf(group->m_group), i, group);
0751                     //Q_EMIT dataChanged(index,index);
0752                 }
0753             }*/
0754 
0755             group->resetChangesFlags();
0756             updatedGroups.insert(group, changesFlags);
0757         }
0758     }
0759 
0760     if (!updatedGroups.isEmpty())
0761         Q_EMIT groupsChangedEvent(updatedGroups);
0762 
0763     m_changedTransfers.clear();
0764     m_changedGroups.clear();
0765 
0766     killTimer(m_timerId);
0767     m_timerId = -1;
0768 }
0769 
0770 #include "moc_transfertreemodel.cpp"