#include "QCustomTransfersModel.h" #include #include "MegaApplication.h" using namespace mega; QCustomTransfersModel::QCustomTransfersModel(int type, QObject *parent) : QTransfersModel(type, parent) { modelState = IDLE; activeUploadTag = -1; activeDownloadTag = -1; } void QCustomTransfersModel::refreshTransfers() { if (transferOrder.size()) { emit dataChanged(index(0, 0, QModelIndex()), index(int(transferOrder.size()) - 1, 0, QModelIndex())); } } MegaTransfer *QCustomTransfersModel::getTransferByTag(int tag) { MegaTransfer *transfer = ((MegaApplication *)qApp)->getFinishedTransferByTag(tag); if (transfer) { return transfer->copy(); } return megaApi->getTransferByTag(tag); } void QCustomTransfersModel::onTransferStart(MegaApi*, MegaTransfer* transfer) { TransferItemData *ti = transfers.value(transfer->getTag()); if (ti) { return; } TransferItemData *item = new TransferItemData(transfer); transfer_it it = getInsertPosition(transfer); const int row = static_cast(it - transferOrder.begin()); beginInsertRows(QModelIndex(), row, row); transfers.insert(item->data.tag, item); transferOrder.insert(it, item); // Update model state if (transfer->getType() == MegaTransfer::TYPE_DOWNLOAD) { modelState |= DOWNLOAD; activeDownloadTag = transfer->getTag(); } else if (transfer->getType() == MegaTransfer::TYPE_UPLOAD) { modelState |= UPLOAD; activeUploadTag = transfer->getTag(); } endInsertRows(); if (transferOrder.size() == 1) { emit onTransferAdded(); } } void QCustomTransfersModel::onTransferFinish(MegaApi*, MegaTransfer* t, MegaError*) { QPointer model = this; MegaTransfer *transfer = t->copy(); removeTransferByTag(transfer->getTag()); if (transfer->getState() == MegaTransfer::STATE_COMPLETED || transfer->getState() == MegaTransfer::STATE_FAILED) { mThreadPool->push([this, model, transfer]() {//thread pool function if (!model) { delete transfer; return; } bool isPublicNode = false; int access = MegaShare::ACCESS_UNKNOWN; MegaNode *ownNode = ((MegaApplication*)qApp)->getMegaApi()->getNodeByHandle(transfer->getNodeHandle()); if (ownNode) { access = ((MegaApplication*)qApp)->getMegaApi()->getAccess(ownNode); if (access == MegaShare::ACCESS_OWNER) { isPublicNode = true; } delete ownNode; } Utilities::queueFunctionInAppThread([this, model, isPublicNode, access, transfer]() {//queued function if (model) { TransferItemData *item = new TransferItemData(transfer); item->data.publicNode = isPublicNode; item->data.nodeAccess = access; if ((int)transfers.size() == (int)Preferences::MAX_COMPLETED_ITEMS) { TransferItemData *itemData = transferOrder.back(); int row = int(transferOrder.size()) - 1; beginRemoveRows(QModelIndex(), row, row); transfers.remove(itemData->data.tag); transferOrder.pop_back(); transferItems.remove(itemData->data.tag); endRemoveRows(); delete itemData; } transfer_it it = getInsertPosition(transfer); const int row = static_cast(it - transferOrder.begin()); beginInsertRows(QModelIndex(), row, row); transfers.insert(item->data.tag, item); transferOrder.insert(it, item); endInsertRows(); if (transfers.isEmpty()) { emit noTransfers(); } else { if (transferOrder.size() == 1) { emit onTransferAdded(); } } } delete transfer; });//end of queued function });// end of thread pool function; } } void QCustomTransfersModel::onTransferUpdate(MegaApi*, MegaTransfer* transfer) { updateTransferInfo(transfer); } void QCustomTransfersModel::onTransferTemporaryError(MegaApi*, MegaTransfer* transfer, MegaError*) { updateTransferInfo(transfer); } void QCustomTransfersModel::refreshTransferItem(int tag) { int row = 0; for (transfer_it it = transferOrder.begin(); it != transferOrder.end() && (*it)->data.tag != tag; ++it) { ++row; } const int transferOrderSize = static_cast(transferOrder.size()); assert(row < transferOrderSize); if (row >= transferOrderSize) { return; } emit dataChanged(index(row, 0, QModelIndex()), index(row, 0, QModelIndex())); } void QCustomTransfersModel::updateTransferInfo(MegaTransfer *transfer) { TransferItemData *itemData = transfers.value(transfer->getTag()); if (!itemData) { return; } unsigned long long newPriority = transfer->getPriority(); TransferItem *item = transferItems[transfer->getTag()]; if (item) { if (item->getType() < 0) { item->setType(transfer->getType(), transfer->isSyncTransfer()); item->setFileName(QString::fromUtf8(transfer->getFileName())); item->setTotalSize(transfer->getTotalBytes()); } // Get http speed, which reports speed changes faster than the transfer. long long httpSpeed; if (item->getType() == MegaTransfer::TYPE_DOWNLOAD) { httpSpeed = static_cast(qApp)->getMegaApi()->getCurrentDownloadSpeed(); } else { httpSpeed = static_cast(qApp)->getMegaApi()->getCurrentUploadSpeed(); } item->setSpeed(std::min(transfer->getSpeed(), httpSpeed), transfer->getMeanSpeed()); item->setTransferredBytes(transfer->getTransferredBytes(), !transfer->isSyncTransfer()); item->setTransferState(transfer->getState()); item->setPriority(newPriority); int tError = transfer->getLastError().getErrorCode(); if (tError != MegaError::API_OK) { assert(transfer->getLastErrorExtended()); item->setTransferError(tError, transfer->getLastErrorExtended()->getValue()); } } //Update modified item refreshTransferItem(transfer->getTag()); } void QCustomTransfersModel::replaceWithTransfer(MegaTransfer *transfer) { int transferToReplaced; int type = transfer->getType(); if (type == MegaTransfer::TYPE_DOWNLOAD) { transferToReplaced = activeDownloadTag; activeDownloadTag = transfer->getTag(); } else { transferToReplaced = activeUploadTag; activeUploadTag = transfer->getTag(); } int row = 0; transfer_it it; for (it = transferOrder.begin(); it != transferOrder.end() && (*it)->data.tag != transferToReplaced; ++it) { ++row; } TransferItemData *item = transfers.value(transferToReplaced); assert(item && row < static_cast(transferOrder.size())); //Generate new element and place it TransferItemData *newItem = new TransferItemData(transfer); beginResetModel(); transfers.insert(newItem->data.tag, newItem); transferOrder[row] = newItem; transfers.remove(transferToReplaced); transferItems.remove(transferToReplaced); endResetModel(); delete item; } void QCustomTransfersModel::removeAllTransfers() { removeAllCompletedTransfers(); } void QCustomTransfersModel::removeAllCompletedTransfers() { if (transfers.size()) { int initialDelPos = 0; if (activeDownloadTag > -1) { initialDelPos++; } if (activeUploadTag > -1) { initialDelPos++; } if (initialDelPos <= (transfers.size() - 1)) { beginRemoveRows(QModelIndex(), initialDelPos, transfers.size() - 1); for (QMap::iterator it = transfers.begin(); it != transfers.end();) { int tag = it.key(); if (tag != activeDownloadTag && tag != activeUploadTag) { TransferItemData *item = it.value(); transferItems.remove(tag); it = transfers.erase(it); delete item; } else { it++; } } transferOrder.erase(transferOrder.begin() + initialDelPos, transferOrder.end()); endRemoveRows(); } } if (transfers.isEmpty()) { emit noTransfers(); } } void QCustomTransfersModel::removeTransferByTag(int transferTag) { TransferItemData *item = transfers.value(transferTag); if (!item) { return; } int row = 0; transfer_it it; for (it = transferOrder.begin(); it != transferOrder.end() && (*it)->data.tag != transferTag; ++it) { ++row; } assert(row < static_cast(transferOrder.size())); beginRemoveRows(QModelIndex(), row, row); if (activeDownloadTag == transferTag) { modelState &= static_cast(~DOWNLOAD); activeDownloadTag = -1; } else if (activeUploadTag == transferTag) { modelState &= static_cast(~UPLOAD); activeUploadTag = -1; } transfers.remove(transferTag); transferOrder.erase(it); transferItems.remove(transferTag); endRemoveRows(); delete item; if (transfers.isEmpty()) { emit noTransfers(); } } void QCustomTransfersModel::updateActiveTransfer(MegaApi *api, MegaTransfer *newtransfer) { if (newtransfer->isFinished()) { return; } int type = newtransfer->getType(); if (type == MegaTransfer::TYPE_DOWNLOAD) { if (activeDownloadTag == -1) { onTransferStart(api, newtransfer); } else if (activeDownloadTag != newtransfer->getTag()) { replaceWithTransfer(newtransfer); } } else { if (activeUploadTag == -1) { onTransferStart(api, newtransfer); } else if (activeUploadTag != newtransfer->getTag()) { replaceWithTransfer(newtransfer); } } } transfer_it QCustomTransfersModel::getInsertPosition(MegaTransfer *transfer) { transfer_it it = transferOrder.begin(); if (transfer->isFinished()) { if (modelState & DOWNLOAD) { std::advance(it, 1); } if (modelState & UPLOAD) { std::advance(it, 1); } } else { if (modelState & DOWNLOAD) { std::advance(it, 1); } } return it; }