From ccdb2a82c36d1c7eb511723176cd49c579373875 Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Thu, 19 Nov 2009 11:09:03 +0000 Subject: [PATCH] - New tracker list (displays tracker status and error/warning messages) --- Changelog | 1 + src/misc.h | 7 - src/propertiesWidget.ui | 251 +----------------- src/propertieswidget.cpp | 174 +----------- src/propertieswidget.h | 8 +- src/qtorrenthandle.cpp | 5 + src/qtorrenthandle.h | 1 + src/src.pro | 5 +- src/trackerlist.h | 196 ++++++++++++++ ...ersAdditionDlg.h => trackersadditiondlg.h} | 26 +- 10 files changed, 235 insertions(+), 439 deletions(-) create mode 100644 src/trackerlist.h rename src/{TrackersAdditionDlg.h => trackersadditiondlg.h} (77%) diff --git a/Changelog b/Changelog index 7aaaaac4f..82d1ecaa0 100644 --- a/Changelog +++ b/Changelog @@ -14,6 +14,7 @@ - FEATURE: Support peer manual ban - FEATURE: Display total amounts transferred in status bar - FEATURE: Announce to all trackers specified for a torrent (µTorrent behavior) + - FEATURE: Display trackers status as well as error/warning messages - FEATURE: Dropped Qt 4.3 support (Qt >= 4.4 is now required) - FEATURE: Added per-torrent super seeding mode (libtorrent >= v0.15 only) - FEATURE: Support for storing symbolic links in .torrent files (libtorrent >= v0.15 only) diff --git a/src/misc.h b/src/misc.h index 90daa9dea..7275dc2b7 100644 --- a/src/misc.h +++ b/src/misc.h @@ -223,13 +223,6 @@ public: return qBtPath; } - static void fixTrackersTiers(std::vector trackers) { - unsigned int nbTrackers = trackers.size(); - for(unsigned int i=0; i static void insertSort(QList > &list, const QPair& value, Qt::SortOrder sortOrder) { diff --git a/src/propertiesWidget.ui b/src/propertiesWidget.ui index 006c5e5d4..e15ac973e 100644 --- a/src/propertiesWidget.ui +++ b/src/propertiesWidget.ui @@ -479,255 +479,8 @@ - - - - - - 6 - - - 0 - - - - - 6 - - - 0 - - - - - - 0 - 0 - - - - QAbstractItemView::ExtendedSelection - - - - - - - 6 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 24 - 24 - - - - - 24 - 24 - - - - - - - - :/Icons/oxygen/list-remove.png:/Icons/oxygen/list-remove.png - - - - - - - - 24 - 24 - - - - - 24 - 24 - - - - - - - - :/Icons/oxygen/list-add.png:/Icons/oxygen/list-add.png - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 6 - - - 0 - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 24 - 24 - - - - - 24 - 24 - - - - - - - - :/Icons/uparrow.png:/Icons/uparrow.png - - - - - - - - 24 - 24 - - - - - 24 - 24 - - - - - - - - :/Icons/downarrow.png:/Icons/downarrow.png - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - 6 - - - 0 - - - - - - 16777215 - 16 - - - - Current tracker: - - - - - - - - 16777215 - 16 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - + + diff --git a/src/propertieswidget.cpp b/src/propertieswidget.cpp index 5d721b2a7..ede0e30ed 100644 --- a/src/propertieswidget.cpp +++ b/src/propertieswidget.cpp @@ -45,9 +45,9 @@ #include "realprogressbarthread.h" #include "bittorrent.h" #include "PropListDelegate.h" -#include "TrackersAdditionDlg.h" #include "TorrentFilesModel.h" #include "peerlistwidget.h" +#include "trackerlist.h" #ifdef Q_WS_MAC #define DEFAULT_BUTTON_CSS "" @@ -86,10 +86,6 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, TransferListWidget *transfer connect(collapseAllButton, SIGNAL(clicked()), filesList, SLOT(collapseAll())); connect(expandAllButton, SIGNAL(clicked()), filesList, SLOT(expandAll())); connect(filesList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFilesListMenu(const QPoint&))); - connect(addTracker_button, SIGNAL(clicked()), this, SLOT(askForTracker())); - connect(removeTracker_button, SIGNAL(clicked()), this, SLOT(deleteSelectedTrackers())); - connect(riseTracker_button, SIGNAL(clicked()), this, SLOT(riseSelectedTracker())); - connect(lowerTracker_button, SIGNAL(clicked()), this, SLOT(lowerSelectedTracker())); connect(actionIgnored, SIGNAL(triggered()), this, SLOT(ignoreSelection())); connect(actionNormal, SIGNAL(triggered()), this, SLOT(normalSelection())); connect(actionHigh, SIGNAL(triggered()), this, SLOT(highSelection())); @@ -105,6 +101,9 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, TransferListWidget *transfer progressBar = new RealProgressBar(this); progressBar->setForegroundColor(Qt::blue); ProgressHLayout->insertWidget(1, progressBar); + // Tracker list + trackerList = new TrackerList(this); + verticalLayout_trackers->addWidget(trackerList); // Peers list peersList = new PeerListWidget(this); peerpage_layout->addWidget(peersList); @@ -113,7 +112,7 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, TransferListWidget *transfer // Dynamic data refresher refreshTimer = new QTimer(this); connect(refreshTimer, SIGNAL(timeout()), this, SLOT(loadDynamicData())); - refreshTimer->start(10000); // 10sec + refreshTimer->start(3000); // 3sec } PropertiesWidget::~PropertiesWidget() { @@ -121,6 +120,7 @@ PropertiesWidget::~PropertiesWidget() { delete refreshTimer; if(progressBarUpdater) delete progressBarUpdater; + delete trackerList; delete peersList; delete progressBar; delete PropListModel; @@ -166,8 +166,7 @@ void PropertiesWidget::clear() { hash_lbl->clear(); comment_lbl->clear(); incrementalDownload->setChecked(false); - trackersURLS->clear(); - trackerURL->clear(); + trackerList->clear(); progressBar->setProgress(QRealArray()); wasted->clear(); upTotal->clear(); @@ -214,8 +213,6 @@ void PropertiesWidget::loadTorrentInfos(QTorrentHandle &_h) { comment_lbl->setText(h.comment()); // Sequential download incrementalDownload->setChecked(TorrentPersistentData::isSequentialDownload(h.hash())); - // Trackers - loadTrackers(); // URL seeds loadUrlSeeds(); // downloaded pieces updater @@ -328,6 +325,11 @@ void PropertiesWidget::loadDynamicData() { progress_lbl->setText(QString::number(h.progress()*100., 'f', 1)+"%"); return; } + if(stackedProperties->currentIndex() == TRACKERS_TAB) { + // Trackers + trackerList->loadTrackers(); + return; + } if(stackedProperties->currentIndex() == PEERS_TAB) { // Load peers peersList->loadPeers(h); @@ -348,41 +350,6 @@ void PropertiesWidget::setIncrementalDownload(int checkboxState) { TorrentPersistentData::saveSequentialStatus(h); } -void PropertiesWidget::loadTrackers() { - if(!h.is_valid()) return; - //Trackers - std::vector trackers = h.trackers(); - trackersURLS->clear(); - QHash errors = BTSession->getTrackersErrors(h.hash()); - unsigned int nbTrackers = trackers.size(); - for(unsigned int i=0; isetForeground(QBrush(QColor("red"))); - // Set tooltip - QString msg=""; - unsigned int i=0; - foreach(QString word, errors[current_tracker].split(" ")) { - if(i > 0 && i%5!=1) msg += " "; - msg += word; - if(i> 0 && i%5==0) msg += "\n"; - ++i; - } - item->setToolTip(msg); - } else { - item->setForeground(QBrush(QColor("green"))); - } - } - QString tracker = h.current_tracker().trimmed(); - if(!tracker.isEmpty()){ - trackerURL->setText(tracker); - }else{ - trackerURL->setText(tr("None - Unreachable?")); - } -} - void PropertiesWidget::loadUrlSeeds(){ QStringList already_added; listWebSeeds->clear(); @@ -578,30 +545,6 @@ void PropertiesWidget::askWebSeed(){ loadUrlSeeds(); } -// Ask the user for a new tracker -// and add it to the download list -// if it is not already in it -void PropertiesWidget::askForTracker(){ - TrackersAddDlg *dlg = new TrackersAddDlg(this); - connect(dlg, SIGNAL(TrackersToAdd(QStringList)), this, SLOT(addTrackerList(QStringList))); -} - -void PropertiesWidget::addTrackerList(QStringList myTrackers) { - // Add the trackers to the list - std::vector trackers = h.trackers(); - foreach(const QString& tracker, myTrackers) { - announce_entry new_tracker(misc::toString(tracker.trimmed().toLocal8Bit().data())); - new_tracker.tier = 0; // Will be fixed a bit later - trackers.push_back(new_tracker); - misc::fixTrackersTiers(trackers); - } - h.replace_trackers(trackers); - h.force_reannounce(); - // Reload Trackers - loadTrackers(); - BTSession->saveTrackerFile(h.hash()); -} - void PropertiesWidget::deleteSelectedUrlSeeds(){ QList selectedItems = listWebSeeds->selectedItems(); bool change = false; @@ -618,99 +561,6 @@ void PropertiesWidget::deleteSelectedUrlSeeds(){ } } -void PropertiesWidget::deleteSelectedTrackers(){ - QList selectedItems = trackersURLS->selectedItems(); - if(!selectedItems.size()) return; - std::vector trackers = h.trackers(); - unsigned int nbTrackers = trackers.size(); - if(nbTrackers == (unsigned int) selectedItems.size()){ - QMessageBox::warning(this, tr("qBittorrent"), - tr("Trackers list can't be empty."), - QMessageBox::Ok); - return; - } - foreach(QListWidgetItem *item, selectedItems){ - QString url = item->text(); - for(unsigned int i=0; isaveTrackerFile(h.hash()); -} - -void PropertiesWidget::riseSelectedTracker(){ - unsigned int i = 0; - std::vector trackers = h.trackers(); - QList selectedItems = trackersURLS->selectedItems(); - bool change = false; - unsigned int nbTrackers = trackers.size(); - foreach(QListWidgetItem *item, selectedItems){ - QString url = item->text(); - for(i=0; i 0){ - announce_entry tmp = trackers[i]; - trackers[i] = trackers[i-1]; - trackers[i-1] = tmp; - change = true; - } - break; - } - } - } - if(change){ - misc::fixTrackersTiers(trackers); - h.replace_trackers(trackers); - h.force_reannounce(); - // Reload Trackers - loadTrackers(); - trackersURLS->item(i-1)->setSelected(true); - BTSession->saveTrackerFile(h.hash()); - } -} - -void PropertiesWidget::lowerSelectedTracker(){ - unsigned int i = 0; - std::vector trackers = h.trackers(); - QList selectedItems = trackersURLS->selectedItems(); - bool change = false; - unsigned int nbTrackers = trackers.size(); - foreach(QListWidgetItem *item, selectedItems){ - QString url = item->text(); - for(i=0; iitem(i+1)->setSelected(true); - BTSession->saveTrackerFile(h.hash()); - } -} - bool PropertiesWidget::savePiecesPriorities() { qDebug("Saving pieces priorities"); std::vector priorities = PropListModel->getFilesPriorities(h.get_torrent_info().num_files()); diff --git a/src/propertieswidget.h b/src/propertieswidget.h index 896174705..76d9eb7bd 100644 --- a/src/propertieswidget.h +++ b/src/propertieswidget.h @@ -46,6 +46,7 @@ class PropListDelegate; class QAction; class torrent_file; class PeerListWidget; +class TrackerList; enum Tab {MAIN_TAB, TRACKERS_TAB, PEERS_TAB, URLSEEDS_TAB, FILES_TAB}; enum SlideState {REDUCED, VISIBLE}; @@ -64,6 +65,7 @@ private: TorrentFilesModel *PropListModel; PropListDelegate *PropDelegate; PeerListWidget *peersList; + TrackerList *trackerList; QAction *actionIgnored; QAction *actionNormal; QAction *actionMaximum; @@ -79,7 +81,6 @@ protected slots: void loadTorrentInfos(QTorrentHandle &h); void loadDynamicData(); void setIncrementalDownload(int checkboxState); - void loadTrackers(); void loadUrlSeeds(); void on_main_infos_button_clicked(); void on_trackers_button_clicked(); @@ -92,13 +93,8 @@ protected slots: void maximumSelection(); void askWebSeed(); void deleteSelectedUrlSeeds(); - void askForTracker(); - void deleteSelectedTrackers(); - void lowerSelectedTracker(); - void riseSelectedTracker(); void displayFilesListMenu(const QPoint& pos); void on_changeSavePathButton_clicked(); - void addTrackerList(QStringList myTrackers); void filteredFilesChanged(); public slots: diff --git a/src/qtorrenthandle.cpp b/src/qtorrenthandle.cpp index 562bb16e1..7b20c91f4 100644 --- a/src/qtorrenthandle.cpp +++ b/src/qtorrenthandle.cpp @@ -522,6 +522,11 @@ void QTorrentHandle::set_peer_download_limit(asio::ip::tcp::endpoint ip, int lim h.set_peer_download_limit(ip, limit); } +void QTorrentHandle::add_tracker(announce_entry const& url) { + Q_ASSERT(h.is_valid()); + h.add_tracker(url); +} + // // Operators // diff --git a/src/qtorrenthandle.h b/src/qtorrenthandle.h index 5ce9871dd..968aa0939 100644 --- a/src/qtorrenthandle.h +++ b/src/qtorrenthandle.h @@ -153,6 +153,7 @@ class QTorrentHandle { void connect_peer(asio::ip::tcp::endpoint const& adr, int source = 0) const; void set_peer_upload_limit(asio::ip::tcp::endpoint ip, int limit) const; void set_peer_download_limit(asio::ip::tcp::endpoint ip, int limit) const; + void add_tracker(announce_entry const& url); // // Operators diff --git a/src/src.pro b/src/src.pro index db5f33e77..d9ec49931 100644 --- a/src/src.pro +++ b/src/src.pro @@ -173,7 +173,7 @@ HEADERS += GUI.h \ json.h \ eventmanager.h \ filterParserThread.h \ - TrackersAdditionDlg.h \ + trackersadditiondlg.h \ searchTab.h \ console_imp.h \ ico.h \ @@ -195,7 +195,8 @@ HEADERS += GUI.h \ geoip.h \ peeraddition.h \ deletionconfirmationdlg.h \ - statusbar.h + statusbar.h \ + trackerlist.h FORMS += MainWindow.ui \ options.ui \ about.ui \ diff --git a/src/trackerlist.h b/src/trackerlist.h new file mode 100644 index 000000000..27328d867 --- /dev/null +++ b/src/trackerlist.h @@ -0,0 +1,196 @@ +/* + * Bittorrent Client using Qt4 and libtorrent. + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + * + * Contact : chris@qbittorrent.org + */ + +#ifndef TRACKERLIST_H +#define TRACKERLIST_H + +#include +#include +#include +#include +#include +#include +#include "propertieswidget.h" +#include "trackersadditiondlg.h" +#include "misc.h" +#include "bittorrent.h" + +enum TrackerListColumn {COL_URL, COL_STATUS, COL_MSG}; + +class TrackerList: public QTreeWidget { + Q_OBJECT + +private: + PropertiesWidget *properties; + QHash tracker_items; + +public: + TrackerList(PropertiesWidget *properties): QTreeWidget(), properties(properties) { + // Graphical settings + setRootIsDecorated(false); + setAllColumnsShowFocus(true); + setItemsExpandable(false); + setSelectionMode(QAbstractItemView::ExtendedSelection); + // Context menu + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showTrackerListMenu(QPoint))); + // Set header + QStringList header; + header << tr("URL"); + header << tr("Status"); + header << tr("Message"); + setHeaderItem(new QTreeWidgetItem(header)); + } + + ~TrackerList() { + + } + +public slots: + + void loadTrackers() { + QStringList old_trackers_urls = tracker_items.keys(); + // Load trackers from torrent handle + QTorrentHandle h = properties->getCurrentTorrent(); + if(!h.is_valid()) return; + QHash errors = properties->getBTSession()->getTrackersErrors(h.hash()); + std::vector trackers = h.trackers(); + std::vector::iterator it; + for(it = trackers.begin(); it != trackers.end(); it++) { + QStringList item_list; + QString tracker_url = misc::toQString((*it).url); + QTreeWidgetItem *item = tracker_items.value(tracker_url, 0); + if(!item) { + item = new QTreeWidgetItem(); + item->setText(COL_URL, tracker_url); + addTopLevelItem(item); + tracker_items[tracker_url] = item; + } else { + old_trackers_urls.removeOne(tracker_url); + } + if((*it).verified) { + item->setText(COL_STATUS, tr("Working")); + } else { + if((*it).updating) { + item->setText(COL_STATUS, tr("Updating...")); + } else { + if((*it).fails > 0) { + item->setText(COL_STATUS, tr("Not working")); + } else { + item->setText(COL_STATUS, tr("Not contacted yet")); + } + } + } + item->setText(COL_MSG, errors.value(tracker_url, "")); + } + // Remove old trackers + foreach(const QString &tracker, old_trackers_urls) { + delete tracker_items.take(tracker); + } + } + + // Ask the user for new trackers and add them to the torrent + void askForTrackers(){ + QStringList trackers = TrackersAdditionDlg::asForTrackers(); + if(!trackers.empty()) { + QTorrentHandle h = properties->getCurrentTorrent(); + if(!h.is_valid()) return; + foreach(const QString& tracker, trackers) { + announce_entry url(tracker.toStdString()); + url.tier = 0; + h.add_tracker(url); + } + // Reannounce to new trackers + h.force_reannounce(); + // Reload tracker list + loadTrackers(); + // XXX: I don't think this is necessary now + //BTSession->saveTrackerFile(h.hash()); + } + } + + void deleteSelectedTrackers(){ + QTorrentHandle h = properties->getCurrentTorrent(); + if(!h.is_valid()) { + clear(); + return; + } + QList selected_items = selectedItems(); + if(selected_items.isEmpty()) return; + QStringList urls_to_remove; + foreach(QTreeWidgetItem *item, selected_items){ + QString tracker_url = item->data(COL_URL, Qt::DisplayRole).toString(); + urls_to_remove << tracker_url; + tracker_items.remove(tracker_url); + delete item; + } + // Iterate of trackers and remove selected ones + std::vector trackers = h.trackers(); + std::vector::iterator it = trackers.begin(); + while(it != trackers.end()) { + int index = urls_to_remove.indexOf(misc::toQString((*it).url)); + if(index >= 0) { + trackers.erase(it); + urls_to_remove.removeAt(index); + } else { + it++; + } + } + h.replace_trackers(trackers); + h.force_reannounce(); + // Reload Trackers + loadTrackers(); + //XXX: I don't think this is necessary + //BTSession->saveTrackerFile(h.hash()); + } + + void showTrackerListMenu(QPoint) { + QList selected_items = selectedItems(); + QMenu menu; + // Add actions + QAction *addAct = menu.addAction(QIcon(":/Icons/oxygen/list-add.png"), tr("Add a new tracker")); + QAction *delAct = 0; + if(!selectedItems().isEmpty()) { + delAct = menu.addAction(QIcon(":/Icons/oxygen/list-remove.png"), "Remove tracker"); + } + QAction *act = menu.exec(QCursor::pos()); + if(act == addAct) { + askForTrackers(); + return; + } + if(act == delAct) { + deleteSelectedTrackers(); + return; + } + } + +}; + +#endif // TRACKERLIST_H diff --git a/src/TrackersAdditionDlg.h b/src/trackersadditiondlg.h similarity index 77% rename from src/TrackersAdditionDlg.h rename to src/trackersadditiondlg.h index 1a4d318d5..3c8a355b5 100644 --- a/src/TrackersAdditionDlg.h +++ b/src/trackersadditiondlg.h @@ -35,27 +35,27 @@ #include #include "ui_trackersAdd.h" -class TrackersAddDlg : public QDialog, private Ui::TrackersAdditionDlg{ +class TrackersAdditionDlg : public QDialog, private Ui::TrackersAdditionDlg{ Q_OBJECT public: - TrackersAddDlg(QWidget *parent): QDialog(parent){ + TrackersAdditionDlg(QWidget *parent=0): QDialog(parent){ setupUi(this); - setAttribute(Qt::WA_DeleteOnClose); - show(); } - ~TrackersAddDlg(){} + ~TrackersAdditionDlg(){} + + QStringList newTrackers() const { + return trackers_list->toPlainText().trimmed().split("\n"); + } - signals: - void TrackersToAdd(QStringList trackers); - - public slots: - void on_buttonBox_accepted() { - QStringList trackers = trackers_list->toPlainText().trimmed().split("\n"); - if(trackers.size()) { - emit TrackersToAdd(trackers); + static QStringList asForTrackers() { + QStringList trackers; + TrackersAdditionDlg dlg; + if(dlg.exec() == QDialog::Accepted) { + return dlg.newTrackers(); } + return trackers; } };