diff --git a/src/core/qtlibtorrent/qbtsession.cpp b/src/core/qtlibtorrent/qbtsession.cpp index 9df1dd2f5..aaa8f8c18 100644 --- a/src/core/qtlibtorrent/qbtsession.cpp +++ b/src/core/qtlibtorrent/qbtsession.cpp @@ -817,10 +817,10 @@ void QBtSession::pauseTorrent(const QString &hash) { } } -void QBtSession::resumeTorrent(const QString &hash) { +void QBtSession::resumeTorrent(const QString &hash, const bool force) { QTorrentHandle h = getTorrentHandle(hash); - if (h.is_paused()) { - h.resume(); + if (h.is_paused() || (h.is_forced() != force)) { + h.resume(force); emit resumedTorrent(h); } } diff --git a/src/core/qtlibtorrent/qbtsession.h b/src/core/qtlibtorrent/qbtsession.h index 6b4afbd8c..cfc96edb7 100644 --- a/src/core/qtlibtorrent/qbtsession.h +++ b/src/core/qtlibtorrent/qbtsession.h @@ -157,7 +157,7 @@ public slots: /* Needed by Web UI */ void pauseAllTorrents(); void pauseTorrent(const QString &hash); - void resumeTorrent(const QString &hash); + void resumeTorrent(const QString &hash, const bool force = false); void resumeAllTorrents(); /* End Web UI */ void preAllocateAllFiles(bool b); diff --git a/src/core/qtlibtorrent/qtorrenthandle.cpp b/src/core/qtlibtorrent/qtorrenthandle.cpp index 9e3eab6c7..79c923e1d 100644 --- a/src/core/qtlibtorrent/qtorrenthandle.cpp +++ b/src/core/qtlibtorrent/qtorrenthandle.cpp @@ -505,6 +505,11 @@ void QTorrentHandle::toggleFirstLastPiecePrio() prioritize_first_last_piece(!first_last_piece_first()); } +bool QTorrentHandle::is_forced() const +{ + return is_forced(status(0x0)); +} + // // Setters // @@ -517,10 +522,11 @@ void QTorrentHandle::pause() const torrent_handle::save_resume_data(); } -void QTorrentHandle::resume() const +void QTorrentHandle::resume(const bool force) const { if (has_error()) torrent_handle::clear_error(); + torrent_handle::set_upload_mode(false); const QString torrent_hash = hash(); TorrentPersistentData* const TorPersistent = TorrentPersistentData::instance(); @@ -535,7 +541,7 @@ void QTorrentHandle::resume() const if (!final_save_path.isEmpty()) move_storage(final_save_path); } - torrent_handle::auto_managed(true); + torrent_handle::auto_managed(!force); torrent_handle::resume(); if (has_persistant_error && temp_path_enabled) // Force recheck @@ -803,6 +809,11 @@ QString QTorrentHandle::filepath_at(const libtorrent::torrent_info &info, unsign } +bool QTorrentHandle::is_forced(const libtorrent::torrent_status &status) +{ + return !status.paused && !status.auto_managed; +} + QTorrentState::QTorrentState(int value) : m_value(value) diff --git a/src/core/qtlibtorrent/qtorrenthandle.h b/src/core/qtlibtorrent/qtorrenthandle.h index 9fc1e7364..51ebee4f9 100644 --- a/src/core/qtlibtorrent/qtorrenthandle.h +++ b/src/core/qtlibtorrent/qtorrenthandle.h @@ -130,12 +130,13 @@ public: qulonglong eta() const; void toggleSequentialDownload(); void toggleFirstLastPiecePrio(); + bool is_forced() const; // // Setters // void pause() const; - void resume() const; + void resume(const bool force = false) const; void remove_url_seed(const QString& seed) const; void add_url_seed(const QString& seed) const; void set_tracker_login(const QString& username, const QString& password) const; @@ -159,6 +160,7 @@ public: static bool has_error(const libtorrent::torrent_status &status); static float progress(const libtorrent::torrent_status &status); static QString filepath_at(const libtorrent::torrent_info &info, unsigned int index); + static bool is_forced(const libtorrent::torrent_status &status); private: void prioritize_first_last_piece(int file_index, bool b) const; diff --git a/src/core/qtlibtorrent/torrentmodel.cpp b/src/core/qtlibtorrent/torrentmodel.cpp index 2fe7a788e..e694a551e 100644 --- a/src/core/qtlibtorrent/torrentmodel.cpp +++ b/src/core/qtlibtorrent/torrentmodel.cpp @@ -148,10 +148,16 @@ TorrentModelItem::State TorrentModelItem::state() const { case torrent_status::downloading_metadata: return STATE_DOWNLOADING_META; case torrent_status::downloading: - return m_lastStatus.download_payload_rate > 0 ? STATE_DOWNLOADING : STATE_STALLED_DL; + if (!m_torrent.is_forced(m_lastStatus)) + return m_lastStatus.download_payload_rate > 0 ? STATE_DOWNLOADING : STATE_STALLED_DL; + else + return STATE_FORCED_DL; case torrent_status::finished: case torrent_status::seeding: - return m_lastStatus.upload_payload_rate > 0 ? STATE_SEEDING : STATE_STALLED_UP; + if (!m_torrent.is_forced(m_lastStatus)) + return m_lastStatus.upload_payload_rate > 0 ? STATE_SEEDING : STATE_STALLED_UP; + else + return STATE_FORCED_UP; case torrent_status::queued_for_checking: return STATE_QUEUED_CHECK; case torrent_status::checking_resume_data: @@ -170,6 +176,7 @@ QIcon TorrentModelItem::getIconByState(State state) { switch (state) { case STATE_DOWNLOADING: case STATE_DOWNLOADING_META: + case STATE_FORCED_DL: return get_downloading_icon(); case STATE_ALLOCATING: case STATE_STALLED_DL: @@ -177,6 +184,7 @@ QIcon TorrentModelItem::getIconByState(State state) { case STATE_STALLED_UP: return get_stalled_uploading_icon(); case STATE_SEEDING: + case STATE_FORCED_UP: return get_uploading_icon(); case STATE_PAUSED_DL: return get_paused_icon(); @@ -204,6 +212,7 @@ QColor TorrentModelItem::getColorByState(State state) { switch (state) { case STATE_DOWNLOADING: case STATE_DOWNLOADING_META: + case STATE_FORCED_DL: return QColor(34, 139, 34); // Forest Green case STATE_ALLOCATING: case STATE_STALLED_DL: @@ -213,6 +222,7 @@ QColor TorrentModelItem::getColorByState(State state) { else return QColor(255, 255, 255); // White case STATE_SEEDING: + case STATE_FORCED_UP: if (!dark) return QColor(65, 105, 225); // Royal Blue else @@ -596,6 +606,7 @@ TorrentStatusReport TorrentModel::getTorrentStatusReport() const for ( ; it != itend; ++it) { switch((*it)->state()) { case TorrentModelItem::STATE_DOWNLOADING: + case TorrentModelItem::STATE_FORCED_DL: ++report.nb_active; ++report.nb_downloading; break; @@ -613,6 +624,7 @@ TorrentStatusReport TorrentModel::getTorrentStatusReport() const break; } case TorrentModelItem::STATE_SEEDING: + case TorrentModelItem::STATE_FORCED_UP: ++report.nb_active; ++report.nb_seeding; ++report.nb_completed; @@ -690,8 +702,10 @@ bool TorrentModel::inhibitSystem() switch((*it)->data(TorrentModelItem::TR_STATUS).toInt()) { case TorrentModelItem::STATE_DOWNLOADING: case TorrentModelItem::STATE_DOWNLOADING_META: + case TorrentModelItem::STATE_FORCED_DL: case TorrentModelItem::STATE_STALLED_DL: case TorrentModelItem::STATE_SEEDING: + case TorrentModelItem::STATE_FORCED_UP: case TorrentModelItem::STATE_STALLED_UP: return true; default: diff --git a/src/core/qtlibtorrent/torrentmodel.h b/src/core/qtlibtorrent/torrentmodel.h index 3da636fe5..9284feb0b 100644 --- a/src/core/qtlibtorrent/torrentmodel.h +++ b/src/core/qtlibtorrent/torrentmodel.h @@ -53,7 +53,7 @@ class TorrentModelItem : public QObject { Q_OBJECT public: - enum State {STATE_DOWNLOADING, STATE_DOWNLOADING_META, STATE_ALLOCATING, STATE_STALLED_DL, STATE_SEEDING, STATE_STALLED_UP, STATE_QUEUED_DL, STATE_QUEUED_UP, STATE_CHECKING_UP, STATE_CHECKING_DL, STATE_QUEUED_CHECK, STATE_QUEUED_FASTCHECK, STATE_PAUSED_DL, STATE_PAUSED_UP, STATE_PAUSED_MISSING, STATE_INVALID}; + enum State {STATE_DOWNLOADING, STATE_DOWNLOADING_META, STATE_ALLOCATING, STATE_STALLED_DL, STATE_SEEDING, STATE_STALLED_UP, STATE_QUEUED_DL, STATE_QUEUED_UP, STATE_CHECKING_UP, STATE_CHECKING_DL, STATE_QUEUED_CHECK, STATE_QUEUED_FASTCHECK, STATE_PAUSED_DL, STATE_PAUSED_UP, STATE_PAUSED_MISSING, STATE_FORCED_DL, STATE_FORCED_UP, STATE_INVALID}; enum Column {TR_NAME, TR_PRIORITY, TR_SIZE, TR_TOTAL_SIZE, TR_PROGRESS, TR_STATUS, TR_SEEDS, TR_PEERS, TR_DLSPEED, TR_UPSPEED, TR_ETA, TR_RATIO, TR_LABEL, TR_ADD_DATE, TR_SEED_DATE, TR_TRACKER, TR_DLLIMIT, TR_UPLIMIT, TR_AMOUNT_DOWNLOADED, TR_AMOUNT_UPLOADED, TR_AMOUNT_LEFT, TR_TIME_ELAPSED, TR_SAVE_PATH, TR_COMPLETED, TR_RATIO_LIMIT, TR_SEEN_COMPLETE_DATE, TR_LAST_ACTIVITY, TR_AMOUNT_DOWNLOADED_SESSION, TR_AMOUNT_UPLOADED_SESSION, NB_COLUMNS}; public: diff --git a/src/gui/transferlistdelegate.cpp b/src/gui/transferlistdelegate.cpp index be5eea21a..eb660401b 100644 --- a/src/gui/transferlistdelegate.cpp +++ b/src/gui/transferlistdelegate.cpp @@ -96,6 +96,9 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem case TorrentModelItem::STATE_DOWNLOADING_META: display = tr("Downloading metadata", "used when loading a magnet link"); break; + case TorrentModelItem::STATE_FORCED_DL: + display = tr("[F] Downloading", "used when the torrent is forced started. You probably shouldn't translate the F."); + break; case TorrentModelItem::STATE_ALLOCATING: display = tr("Allocating", "qBittorrent is allocating the files on disk"); break; @@ -106,6 +109,9 @@ void TransferListDelegate::paint(QPainter * painter, const QStyleOptionViewItem case TorrentModelItem::STATE_STALLED_UP: display = tr("Seeding", "Torrent is complete and in upload-only mode"); break; + case TorrentModelItem::STATE_FORCED_UP: + display = tr("[F] Seeding", "used when the torrent is forced started. You probably shouldn't translate the F."); + break; case TorrentModelItem::STATE_QUEUED_DL: case TorrentModelItem::STATE_QUEUED_UP: display = tr("Queued", "i.e. torrent is queued"); diff --git a/src/gui/transferlistsortmodel.cpp b/src/gui/transferlistsortmodel.cpp index 7e108fb4b..0574e44c4 100644 --- a/src/gui/transferlistsortmodel.cpp +++ b/src/gui/transferlistsortmodel.cpp @@ -152,8 +152,10 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex switch (model->data(model->index(left.row(), TorrentModelItem::TR_STATUS)).toInt()) { case TorrentModelItem::STATE_DOWNLOADING: case TorrentModelItem::STATE_DOWNLOADING_META: + case TorrentModelItem::STATE_FORCED_DL: case TorrentModelItem::STATE_STALLED_DL: case TorrentModelItem::STATE_SEEDING: + case TorrentModelItem::STATE_FORCED_UP: case TorrentModelItem::STATE_STALLED_UP: activeL = true; break; @@ -164,8 +166,10 @@ bool TransferListSortModel::lessThan(const QModelIndex &left, const QModelIndex switch (model->data(model->index(right.row(), TorrentModelItem::TR_STATUS)).toInt()) { case TorrentModelItem::STATE_DOWNLOADING: case TorrentModelItem::STATE_DOWNLOADING_META: + case TorrentModelItem::STATE_FORCED_DL: case TorrentModelItem::STATE_STALLED_DL: case TorrentModelItem::STATE_SEEDING: + case TorrentModelItem::STATE_FORCED_UP: case TorrentModelItem::STATE_STALLED_UP: activeR = true; break; @@ -288,16 +292,17 @@ bool TransferListSortModel::matchStatusFilter(int sourceRow, const QModelIndex & return (state == TorrentModelItem::STATE_DOWNLOADING || state == TorrentModelItem::STATE_STALLED_DL || state == TorrentModelItem::STATE_PAUSED_DL || state == TorrentModelItem::STATE_CHECKING_DL || state == TorrentModelItem::STATE_QUEUED_DL || state == TorrentModelItem::STATE_DOWNLOADING_META - || state == TorrentModelItem::STATE_PAUSED_MISSING); + || state == TorrentModelItem::STATE_PAUSED_MISSING || state == TorrentModelItem::STATE_FORCED_DL); case TorrentFilter::SEEDING: return (state == TorrentModelItem::STATE_SEEDING || state == TorrentModelItem::STATE_STALLED_UP - || state == TorrentModelItem::STATE_CHECKING_UP || state == TorrentModelItem::STATE_QUEUED_UP); + || state == TorrentModelItem::STATE_CHECKING_UP || state == TorrentModelItem::STATE_QUEUED_UP + || state == TorrentModelItem::STATE_FORCED_UP); case TorrentFilter::COMPLETED: return (state == TorrentModelItem::STATE_SEEDING || state == TorrentModelItem::STATE_STALLED_UP || state == TorrentModelItem::STATE_PAUSED_UP || state == TorrentModelItem::STATE_CHECKING_UP - || state == TorrentModelItem::STATE_QUEUED_UP); + || state == TorrentModelItem::STATE_QUEUED_UP || state == TorrentModelItem::STATE_FORCED_UP); case TorrentFilter::PAUSED: return (state == TorrentModelItem::STATE_PAUSED_DL || state == TorrentModelItem::STATE_PAUSED_MISSING); @@ -312,7 +317,8 @@ bool TransferListSortModel::matchStatusFilter(int sourceRow, const QModelIndex & return (up_speed > 0); } - return (state == TorrentModelItem::STATE_DOWNLOADING || state == TorrentModelItem::STATE_SEEDING); + return (state == TorrentModelItem::STATE_DOWNLOADING || state == TorrentModelItem::STATE_SEEDING + || state == TorrentModelItem::STATE_FORCED_DL || state == TorrentModelItem::STATE_FORCED_UP); case TorrentFilter::INACTIVE: if (state == TorrentModelItem::STATE_STALLED_DL) { @@ -320,7 +326,8 @@ bool TransferListSortModel::matchStatusFilter(int sourceRow, const QModelIndex & return !(up_speed > 0); } - return (state != TorrentModelItem::STATE_DOWNLOADING && state != TorrentModelItem::STATE_SEEDING); + return (state != TorrentModelItem::STATE_DOWNLOADING && state != TorrentModelItem::STATE_SEEDING + && state != TorrentModelItem::STATE_FORCED_DL && state != TorrentModelItem::STATE_FORCED_UP); default: return false; diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp index 1e0aede6c..9909e127a 100644 --- a/src/gui/transferlistwidget.cpp +++ b/src/gui/transferlistwidget.cpp @@ -282,6 +282,13 @@ void TransferListWidget::startSelectedTorrents() BTSession->resumeTorrent(hash); } +void TransferListWidget::forceStartSelectedTorrents() +{ + const QStringList hashes = getSelectedTorrentsHashes(); + foreach (const QString &hash, hashes) + BTSession->resumeTorrent(hash, true); +} + void TransferListWidget::startVisibleTorrents() { QStringList hashes; @@ -725,6 +732,8 @@ void TransferListWidget::displayListMenu(const QPoint&) // Create actions QAction actionStart(IconProvider::instance()->getIcon("media-playback-start"), tr("Resume", "Resume/start the torrent"), 0); connect(&actionStart, SIGNAL(triggered()), this, SLOT(startSelectedTorrents())); + QAction actionForceStart(tr("Force Resume", "Force Resume/start the torrent"), 0); + connect(&actionForceStart, SIGNAL(triggered()), this, SLOT(forceStartSelectedTorrents())); QAction actionPause(IconProvider::instance()->getIcon("media-playback-pause"), tr("Pause", "Pause the torrent"), 0); connect(&actionPause, SIGNAL(triggered()), this, SLOT(pauseSelectedTorrents())); QAction actionDelete(IconProvider::instance()->getIcon("edit-delete"), tr("Delete", "Delete the torrent"), 0); @@ -753,10 +762,8 @@ void TransferListWidget::displayListMenu(const QPoint&) connect(&actionForce_recheck, SIGNAL(triggered()), this, SLOT(recheckSelectedTorrents())); QAction actionCopy_magnet_link(QIcon(":/icons/magnet.png"), tr("Copy magnet link"), 0); connect(&actionCopy_magnet_link, SIGNAL(triggered()), this, SLOT(copySelectedMagnetURIs())); - QAction actionCopy_name(IconProvider::instance()->getIcon("edit-copy"), tr("Copy name"), 0); connect(&actionCopy_name, SIGNAL(triggered()), this, SLOT(copySelectedNames())); - QAction actionSuper_seeding_mode(tr("Super seeding mode"), 0); actionSuper_seeding_mode.setCheckable(true); connect(&actionSuper_seeding_mode, SIGNAL(triggered()), this, SLOT(toggleSelectedTorrentsSuperSeeding())); @@ -771,13 +778,14 @@ void TransferListWidget::displayListMenu(const QPoint&) // End of actions QMenu listMenu(this); // Enable/disable pause/start action given the DL state - bool has_pause = false, has_start = false, has_preview = false; + bool has_pause = false, has_start = false, has_force = false, has_preview = false; bool all_same_super_seeding = true; bool super_seeding_mode = false; bool all_same_sequential_download_mode = true, all_same_prio_firstlast = true; bool sequential_download_mode = false, prioritize_first_last = false; bool one_has_metadata = false, one_not_seed = false; bool first = true; + bool forced = false; QTorrentHandle h; qDebug("Displaying menu"); foreach (const QModelIndex &index, selectedIndexes) { @@ -788,6 +796,7 @@ void TransferListWidget::displayListMenu(const QPoint&) if (!h.is_valid()) continue; if (h.has_metadata()) one_has_metadata = true; + forced = h.is_forced(); if (!h.is_seed()) { one_not_seed = true; if (h.has_metadata()) { @@ -818,8 +827,26 @@ void TransferListWidget::displayListMenu(const QPoint&) listMenu.addAction(&actionStart); has_start = true; } + if (!has_force) { + listMenu.addAction(&actionForceStart); + has_force = true; + } } else { + + if (!forced) { + if (!has_force) { + listMenu.addAction(&actionForceStart); + has_force = true; + } + } + else { + if (!has_start) { + listMenu.addAction(&actionStart); + has_start = true; + } + } + if (!has_pause) { listMenu.addAction(&actionPause); has_pause = true; @@ -828,7 +855,7 @@ void TransferListWidget::displayListMenu(const QPoint&) if (h.has_metadata() && BTSession->isFilePreviewPossible(hash) && !has_preview) has_preview = true; first = false; - if (has_pause && has_start && has_preview && one_not_seed) break; + if (has_pause && has_start && has_force && has_preview && one_not_seed) break; } listMenu.addSeparator(); listMenu.addAction(&actionDelete); diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h index d8459a07b..5077ca1cc 100644 --- a/src/gui/transferlistwidget.h +++ b/src/gui/transferlistwidget.h @@ -61,6 +61,7 @@ public slots: void setRefreshInterval(int t); void setSelectedTorrentsLocation(); void startSelectedTorrents(); + void forceStartSelectedTorrents(); void startVisibleTorrents(); void pauseSelectedTorrents(); void pauseVisibleTorrents();