diff --git a/Changelog b/Changelog index 243dfd1c3..296dd2b8b 100644 --- a/Changelog +++ b/Changelog @@ -4,7 +4,7 @@ - FEATURE: Display more information regarding the torrent in its properties - FEATURE: Various optimizations to save CPU and memory - FEATURE: Folder scanning now works with CIFS and NFS mounted folders - - FEATURE: Speed up qBittorrent startup + - FEATURE: Speed up qBittorrent startup and shutdown - FEATURE: Display per-torrent peer list - FEATURE: Make sure torrent files are always sorted by name - FEATURE: Seeds and Peers columns are now sortable diff --git a/src/GUI.cpp b/src/GUI.cpp index a82b77905..47b6d29cf 100644 --- a/src/GUI.cpp +++ b/src/GUI.cpp @@ -196,17 +196,21 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), dis GUI::~GUI() { qDebug("GUI destruction"); hide(); + // Async deletion of Bittorrent session as early as possible + // in order to speed up exit + session_proxy sp = BTSession->asyncDeletion(); + // Delete other GUI objects delete status_bar; + delete transferList; + delete guiUpdater; + if(rssWidget) delete rssWidget; delete searchEngine; delete transferListFilters; delete properties; - delete transferList; delete hSplitter; delete vSplitter; - delete guiUpdater; - qDebug("1"); if(systrayCreator) { delete systrayCreator; } @@ -214,19 +218,21 @@ GUI::~GUI() { delete systrayIcon; delete myTrayIconMenu; } - qDebug("2"); localServer->close(); delete localServer; delete tabs; - qDebug("3"); // Keyboard shortcuts delete switchSearchShortcut; delete switchSearchShortcut2; delete switchTransferShortcut; delete switchRSSShortcut; - qDebug("4"); + // Delete BTSession objects delete BTSession; - qDebug("5"); + // May freeze for a few seconds after the next line + // because the Bittorrent session proxy will + // actually be deleted now and destruction + // becomes synchronous + qDebug("Exiting GUI destructor..."); } void GUI::displayRSSTab(bool enable) { diff --git a/src/Icons/skin/checkingDL.png b/src/Icons/skin/checkingDL.png index 3f1c6247b..0f40b4486 100644 Binary files a/src/Icons/skin/checkingDL.png and b/src/Icons/skin/checkingDL.png differ diff --git a/src/Icons/skin/checkingUP.png b/src/Icons/skin/checkingUP.png index c40034552..0f40b4486 100644 Binary files a/src/Icons/skin/checkingUP.png and b/src/Icons/skin/checkingUP.png differ diff --git a/src/Icons/skin/pausedDL.png b/src/Icons/skin/pausedDL.png index d4e3939f4..e746bfd23 100644 Binary files a/src/Icons/skin/pausedDL.png and b/src/Icons/skin/pausedDL.png differ diff --git a/src/Icons/skin/pausedUP.png b/src/Icons/skin/pausedUP.png index 9b5a283f0..902064722 100644 Binary files a/src/Icons/skin/pausedUP.png and b/src/Icons/skin/pausedUP.png differ diff --git a/src/Icons/skin/queuedDL.png b/src/Icons/skin/queuedDL.png index 94ed8268d..963f7125b 100644 Binary files a/src/Icons/skin/queuedDL.png and b/src/Icons/skin/queuedDL.png differ diff --git a/src/Icons/skin/queuedUP.png b/src/Icons/skin/queuedUP.png index 272cb5709..8786a6268 100644 Binary files a/src/Icons/skin/queuedUP.png and b/src/Icons/skin/queuedUP.png differ diff --git a/src/Icons/skin/stalledDL.png b/src/Icons/skin/stalledDL.png index ef2438eb8..60fd87bdd 100644 Binary files a/src/Icons/skin/stalledDL.png and b/src/Icons/skin/stalledDL.png differ diff --git a/src/Icons/skin/stalledUP.png b/src/Icons/skin/stalledUP.png index dd487b432..1918277b7 100644 Binary files a/src/Icons/skin/stalledUP.png and b/src/Icons/skin/stalledUP.png differ diff --git a/src/bittorrent.cpp b/src/bittorrent.cpp index e993bdd54..f1fbdc5dd 100644 --- a/src/bittorrent.cpp +++ b/src/bittorrent.cpp @@ -63,7 +63,7 @@ enum ProxyType {HTTP=1, SOCKS5=2, HTTP_PW=3, SOCKS5_PW=4}; // Main constructor -Bittorrent::Bittorrent() : preAllocateAll(false), addInPause(false), ratio_limit(-1), UPnPEnabled(false), NATPMPEnabled(false), LSDEnabled(false), DHTEnabled(false), queueingEnabled(false), geoipDBLoaded(false) { +Bittorrent::Bittorrent() : preAllocateAll(false), addInPause(false), ratio_limit(-1), UPnPEnabled(false), NATPMPEnabled(false), LSDEnabled(false), DHTEnabled(false), queueingEnabled(false), geoipDBLoaded(false), exiting(false) { resolve_countries = false; // To avoid some exceptions fs::path::default_name_check(fs::no_check); @@ -102,9 +102,9 @@ Bittorrent::Bittorrent() : preAllocateAll(false), addInPause(false), ratio_limit qDebug("* BTSession constructed"); } -// Main destructor -Bittorrent::~Bittorrent() { - qDebug("BTSession deletion"); +session_proxy Bittorrent::asyncDeletion() { + qDebug("Bittorrent session async deletion IN"); + exiting = true; // Do some BT related saving saveDHTEntry(); saveSessionState(); @@ -112,6 +112,22 @@ Bittorrent::~Bittorrent() { // Delete session session_proxy sp = s->abort(); delete s; + qDebug("Bittorrent session async deletion OUT"); + return sp; +} + +// Main destructor +Bittorrent::~Bittorrent() { + qDebug("BTSession destructor IN"); + if(!exiting) { + // Do some BT related saving + saveDHTEntry(); + saveSessionState(); + saveFastResumeData(); + // Delete session + session_proxy sp = s->abort(); + delete s; + } // Disable directory scanning disableDirectoryScanning(); // Delete our objects @@ -129,7 +145,7 @@ Bittorrent::~Bittorrent() { delete httpServer; if(timerETA) delete timerETA; - qDebug("Deleting session..."); + qDebug("BTSession destructor OUT"); } void Bittorrent::preAllocateAllFiles(bool b) { diff --git a/src/bittorrent.h b/src/bittorrent.h index b672d9182..e2d8116d1 100644 --- a/src/bittorrent.h +++ b/src/bittorrent.h @@ -120,6 +120,8 @@ private: // Web UI QPointer httpServer; QStringList url_skippingDlg; + // Fast exit (async) + bool exiting; protected: QString getSavePath(QString hash); @@ -163,6 +165,7 @@ public slots: void downloadFromUrl(QString url); void deleteTorrent(QString hash, bool delete_local_files = false); void startUpTorrents(); + session_proxy asyncDeletion(); /* Needed by Web UI */ void pauseAllTorrents(); void pauseTorrent(QString hash); diff --git a/src/eventmanager.cpp b/src/eventmanager.cpp index 84f3b9b89..e58a314cf 100644 --- a/src/eventmanager.cpp +++ b/src/eventmanager.cpp @@ -161,19 +161,11 @@ QVariantMap EventManager::getPropGeneralInfo(QString hash) const { data["time_elapsed"] = elapsed_txt; data["nb_connections"] = QString::number(h.num_connections())+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(h.connections_limit()))+")"; // Update ratio info - float ratio; - if(h.total_payload_download() == 0){ - if(h.total_payload_upload() == 0) - ratio = 1.; + double ratio = BTSession->getRealRatio(h.hash()); + if(ratio > 100.) + data["share_ratio"] = QString::fromUtf8("∞"); else - ratio = 10.; // Max ratio - }else{ - ratio = (double)h.total_payload_upload()/(double)h.total_payload_download(); - if(ratio > 10.){ - ratio = 10.; - } - } - data["share_ratio"] = QString(QByteArray::number(ratio, 'f', 1)); + data["share_ratio"] = QString(QByteArray::number(ratio, 'f', 1)); } return data; } @@ -210,7 +202,7 @@ void EventManager::modifiedTorrent(QTorrentHandle h) case torrent_status::finished: case torrent_status::seeding: if(h.upload_payload_rate() > 0) { - event["state"] = QVariant("seeding"); + event["state"] = QVariant("uploading"); } else { event["state"] = QVariant("stalledUP"); } @@ -263,7 +255,7 @@ void EventManager::modifiedTorrent(QTorrentHandle h) event["seed"] = QVariant(h.is_seed()); double ratio = BTSession->getRealRatio(hash); if(ratio > 100.) - QString::fromUtf8("∞"); + event["ratio"] = QString::fromUtf8("∞"); else event["ratio"] = QVariant(QString::number(ratio, 'f', 1)); event["hash"] = QVariant(hash); diff --git a/src/main.cpp b/src/main.cpp index 78d3a9770..248cd1bfc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -211,8 +211,10 @@ int main(int argc, char *argv[]){ } int ret = app->exec(); delete window; - qDebug("app children: %d", app->children().size()); + qDebug("GUI was deleted!"); + qDebug("Deleting app..."); delete app; + qDebug("App was deleted! All good."); return ret; } diff --git a/src/propertieswidget.cpp b/src/propertieswidget.cpp index 4680f1cd8..b724bcafb 100644 --- a/src/propertieswidget.cpp +++ b/src/propertieswidget.cpp @@ -356,8 +356,8 @@ void PropertiesWidget::loadDynamicData() { // Files progress std::vector fp; h.file_progress(fp); - PropListModel->updateFilesProgress(fp); PropListModel->updateFilesPriorities(h.file_priorities()); + PropListModel->updateFilesProgress(fp); } } catch(invalid_handle e) {} } diff --git a/src/torrentfilesmodel.h b/src/torrentfilesmodel.h index 93ca68e27..89bb2ec89 100644 --- a/src/torrentfilesmodel.h +++ b/src/torrentfilesmodel.h @@ -133,13 +133,13 @@ public: Q_ASSERT(type == FOLDER); qulonglong size = 0; foreach(TreeItem* child, childItems) { - size += child->getSize(); + if(child->getPriority() > 0) + size += child->getSize(); } setSize(size); } void setProgress(qulonglong done) { - if(done == total_done) return; total_done = done; qulonglong size = getSize(); Q_ASSERT(total_done <= size); @@ -149,6 +149,7 @@ public: else progress = 1.; Q_ASSERT(progress >= 0. && progress <= 1.); + //qDebug("setProgress(%s): %f", getName().toLocal8Bit().data(), progress); itemData.replace(2, progress); if(parentItem) parentItem->updateProgress(); @@ -169,9 +170,12 @@ public: if(type == ROOT) return; Q_ASSERT(type == FOLDER); total_done = 0; + //qDebug("Folder %s is updating its progress", getName().toLocal8Bit().data()); foreach(TreeItem* child, childItems) { - total_done += child->getTotalDone(); + if(child->getPriority() > 0) + total_done += child->getTotalDone(); } + //qDebug("Folder: total_done: %llu/%llu", total_done, getSize()); Q_ASSERT(total_done <= getSize()); setProgress(total_done); } @@ -180,16 +184,24 @@ public: return itemData.value(3).toInt(); } - void setPriority(int priority) { - if(getPriority() != priority) { - itemData.replace(3, priority); + void setPriority(int new_prio) { + int old_prio = getPriority(); + if(old_prio != new_prio) { + itemData.replace(3, new_prio); // Update parent - if(parentItem) + if(parentItem) { + if(new_prio == 0 || old_prio == 0) { + // Files got filtered or unfiltered + // Update parent size and progress + parentItem->updateSize(); + parentItem->updateProgress(); + } parentItem->updatePriority(); + } } // Update children foreach(TreeItem* child, childItems) { - child->setPriority(priority); + child->setPriority(new_prio); } } diff --git a/src/transferlistwidget.cpp b/src/transferlistwidget.cpp index 760c3962d..f407423d2 100644 --- a/src/transferlistwidget.cpp +++ b/src/transferlistwidget.cpp @@ -163,7 +163,7 @@ void TransferListWidget::addTorrent(QTorrentHandle& h) { listModel->setData(listModel->index(row, TR_STATUS), STATE_PAUSED_DL); listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/pausedDL.png"))), Qt::DecorationRole); } - //setRowColor(row, QString::fromUtf8("red")); + setRowColor(row, QString::fromUtf8("red")); }else{ if(h.is_seed()) { listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalledUP.png"))), Qt::DecorationRole); @@ -172,7 +172,7 @@ void TransferListWidget::addTorrent(QTorrentHandle& h) { listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalledDL.png"))), Qt::DecorationRole); listModel->setData(listModel->index(row, TR_STATUS), STATE_STALLED_DL); } - //setRowColor(row, QString::fromUtf8("grey")); + setRowColor(row, QApplication::palette().color(QPalette::WindowText)); } // Select first torrent to be added if(listModel->rowCount() == 1) @@ -184,12 +184,12 @@ void TransferListWidget::addTorrent(QTorrentHandle& h) { } } -/*void TransferListWidget::setRowColor(int row, QColor color) { +void TransferListWidget::setRowColor(int row, QColor color) { unsigned int nbColumns = listModel->columnCount()-1; for(unsigned int i=0; isetData(listModel->index(row, i), QVariant(color), Qt::ForegroundRole); } -}*/ +} void TransferListWidget::deleteTorrent(int row, bool refresh_list) { listModel->removeRow(row); @@ -216,7 +216,7 @@ void TransferListWidget::pauseTorrent(int row, bool refresh_list) { } listModel->setData(listModel->index(row, TR_SEEDS), QVariant(0.0)); listModel->setData(listModel->index(row, TR_PEERS), QVariant(0.0)); - //setRowColor(row, QString::fromUtf8("red")); + setRowColor(row, QString::fromUtf8("red")); if(refresh_list) refreshList(); } @@ -236,6 +236,7 @@ void TransferListWidget::resumeTorrent(int row, bool refresh_list) { listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(":/Icons/skin/stalledDL.png")), Qt::DecorationRole); listModel->setData(listModel->index(row, TR_STATUS), STATE_STALLED_DL); } + setRowColor(row, QApplication::palette().color(QPalette::WindowText)); if(refresh_list) refreshList(); } @@ -312,7 +313,7 @@ int TransferListWidget::updateTorrent(int row) { listModel->setData(listModel->index(row, TR_UPSPEED), QVariant((double)0.)); listModel->setData(listModel->index(row, TR_SEEDS), QVariant(0.0)); listModel->setData(listModel->index(row, TR_PEERS), QVariant(0.0)); - //setRowColor(row, QString::fromUtf8("grey")); + setRowColor(row, QString::fromUtf8("grey")); return s; } } @@ -340,7 +341,7 @@ int TransferListWidget::updateTorrent(int row) { } listModel->setData(listModel->index(row, TR_PROGRESS), QVariant((double)h.progress())); listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)-1)); - //setRowColor(row, QString::fromUtf8("grey")); + setRowColor(row, QString::fromUtf8("grey")); break; case torrent_status::downloading: case torrent_status::downloading_metadata: @@ -348,12 +349,12 @@ int TransferListWidget::updateTorrent(int row) { listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole); listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)BTSession->getETA(hash))); s = STATE_DOWNLOADING; - //setRowColor(row, QString::fromUtf8("green")); + setRowColor(row, QString::fromUtf8("green")); }else{ listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalledDL.png"))), Qt::DecorationRole); listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)-1)); s = STATE_STALLED_DL; - //setRowColor(row, QApplication::palette().color(QPalette::WindowText)); + setRowColor(row, QApplication::palette().color(QPalette::WindowText)); } listModel->setData(listModel->index(row, TR_DLSPEED), QVariant((double)h.download_payload_rate())); listModel->setData(listModel->index(row, TR_PROGRESS), QVariant((double)h.progress())); @@ -363,9 +364,11 @@ int TransferListWidget::updateTorrent(int row) { if(h.upload_payload_rate() > 0) { s = STATE_SEEDING; listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/uploading.png"))), Qt::DecorationRole); + setRowColor(row, "orange"); } else { s = STATE_STALLED_UP; listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalledUP.png"))), Qt::DecorationRole); + setRowColor(row, QApplication::palette().color(QPalette::WindowText)); } } // Common to both downloads and uploads @@ -389,11 +392,11 @@ void TransferListWidget::setFinished(QTorrentHandle &h) { if(h.is_paused()) { listModel->setData(listModel->index(row, TR_NAME), QIcon(":/Icons/skin/pausedUP.png"), Qt::DecorationRole); listModel->setData(listModel->index(row, TR_STATUS), STATE_PAUSED_UP); - //setRowColor(row, "red"); + setRowColor(row, "red"); }else{ listModel->setData(listModel->index(row, TR_NAME), QVariant(QIcon(":/Icons/skin/stalledUP.png")), Qt::DecorationRole); listModel->setData(listModel->index(row, TR_STATUS), STATE_STALLED_UP); - //setRowColor(row, "orange"); + setRowColor(row, QApplication::palette().color(QPalette::WindowText)); } listModel->setData(listModel->index(row, TR_ETA), QVariant((qlonglong)-1)); listModel->setData(listModel->index(row, TR_DLSPEED), QVariant((double)0.)); diff --git a/src/transferlistwidget.h b/src/transferlistwidget.h index c876d9b51..d40f685f8 100644 --- a/src/transferlistwidget.h +++ b/src/transferlistwidget.h @@ -84,7 +84,7 @@ protected slots: #endif void toggleSelectedTorrentsSequentialDownload(); void toggleSelectedFirstLastPiecePrio(); - //void setRowColor(int row, QColor color); + void setRowColor(int row, QColor color); public slots: void refreshList(); diff --git a/src/webui/preferences.html b/src/webui/preferences.html index c9acd6749..6140f0e8c 100644 --- a/src/webui/preferences.html +++ b/src/webui/preferences.html @@ -14,10 +14,10 @@
- + - +
_(Upload:)  _(KiB/s)_(Upload:)  _(KiB/s)
_(Download:)  _(KiB/s)_(Download:)  _(KiB/s)
@@ -28,13 +28,13 @@
- + - + - +
_(Global maximum number of connections:)_(Global maximum number of connections:)
_(Maximum number of connections per torrent:)_(Maximum number of connections per torrent:)
_(Maximum number of upload slots per torrent:)_(Maximum number of upload slots per torrent:)
@@ -45,7 +45,7 @@
- +
_(Enable DHT network (decentralized))_(Enable DHT network (decentralized))
@@ -226,4 +226,4 @@ loadPreferences = function() { loadPreferences(); - \ No newline at end of file + diff --git a/src/webui/scripts/dynamicTable.js b/src/webui/scripts/dynamicTable.js index 97c905dd8..747f3ca10 100644 --- a/src/webui/scripts/dynamicTable.js +++ b/src/webui/scripts/dynamicTable.js @@ -194,21 +194,21 @@ var dynamicTable = new Class ({ } break; case 'completed': - if(status == "seeding" || status == "stalledUP" || status == "checkingUP" || status == "pausedUP" || status == "queuedUP") { + if(status == "uploading" || status == "stalledUP" || status == "checkingUP" || status == "pausedUP" || status == "queuedUP") { tr.removeClass("invisible"); } else { tr.addClass("invisible"); } break; case 'active': - if(status == "downloading" || status == "seeding") { + if(status == "downloading" || status == "uploading") { tr.removeClass("invisible"); } else { tr.addClass("invisible"); } break; case 'inactive': - if(status != "downloading" && status != "seeding") { + if(status != "downloading" && status != "uploading") { tr.removeClass("invisible"); } else { tr.addClass("invisible");