From 7b736b6ae3d50c86b3533200e5bd9175e8bdef0d Mon Sep 17 00:00:00 2001 From: Anton Lashkov Date: Mon, 25 Aug 2014 15:58:48 +0400 Subject: [PATCH] Add speedwidget based on QGraphicsView --- src/core/bittorrent/sessionstatus.cpp | 40 ++++ src/core/bittorrent/sessionstatus.h | 10 + src/core/preferences.cpp | 19 ++ src/core/preferences.h | 6 + src/gui/properties/properties.pri | 8 +- src/gui/properties/propertieswidget.cpp | 5 + src/gui/properties/propertieswidget.h | 3 + src/gui/properties/propertieswidget.ui | 4 + src/gui/properties/proptabbar.cpp | 4 + src/gui/properties/proptabbar.h | 2 +- src/gui/properties/speedplotview.cpp | 253 ++++++++++++++++++++++++ src/gui/properties/speedplotview.h | 107 ++++++++++ src/gui/properties/speedwidget.cpp | 218 ++++++++++++++++++++ src/gui/properties/speedwidget.h | 79 ++++++++ src/icons.qrc | 1 + src/icons/oxygen/office-chart-line.png | Bin 0 -> 877 bytes 16 files changed, 756 insertions(+), 3 deletions(-) create mode 100644 src/gui/properties/speedplotview.cpp create mode 100644 src/gui/properties/speedplotview.h create mode 100644 src/gui/properties/speedwidget.cpp create mode 100644 src/gui/properties/speedwidget.h create mode 100644 src/icons/oxygen/office-chart-line.png diff --git a/src/core/bittorrent/sessionstatus.cpp b/src/core/bittorrent/sessionstatus.cpp index 81c7f700f..4bfc5a877 100644 --- a/src/core/bittorrent/sessionstatus.cpp +++ b/src/core/bittorrent/sessionstatus.cpp @@ -50,6 +50,46 @@ int SessionStatus::payloadUploadRate() const return m_nativeStatus.payload_upload_rate; } +int SessionStatus::downloadRate() const +{ + return m_nativeStatus.download_rate; +} + +int SessionStatus::uploadRate() const +{ + return m_nativeStatus.upload_rate; +} + +int SessionStatus::ipOverheadDownloadRate() const +{ + return m_nativeStatus.ip_overhead_download_rate; +} + +int SessionStatus::ipOverheadUploadRate() const +{ + return m_nativeStatus.ip_overhead_upload_rate; +} + +int SessionStatus::dhtDownloadRate() const +{ + return m_nativeStatus.dht_download_rate; +} + +int SessionStatus::dhtUploadRate() const +{ + return m_nativeStatus.dht_upload_rate; +} + +int SessionStatus::trackerDownloadRate() const +{ + return m_nativeStatus.tracker_download_rate; +} + +int SessionStatus::trackerUploadRate() const +{ + return m_nativeStatus.tracker_upload_rate; +} + qlonglong SessionStatus::totalDownload() const { return m_nativeStatus.total_download; diff --git a/src/core/bittorrent/sessionstatus.h b/src/core/bittorrent/sessionstatus.h index f0a18e2f5..e306207c1 100644 --- a/src/core/bittorrent/sessionstatus.h +++ b/src/core/bittorrent/sessionstatus.h @@ -51,6 +51,16 @@ namespace BitTorrent // account "useful" part of the rate int payloadUploadRate() const; + // Additional download/upload rates + int uploadRate() const; + int downloadRate() const; + int ipOverheadUploadRate() const; + int ipOverheadDownloadRate() const; + int dhtUploadRate() const; + int dhtDownloadRate() const; + int trackerUploadRate() const; + int trackerDownloadRate() const; + qlonglong totalDownload() const; qlonglong totalUpload() const; qlonglong totalPayloadDownload() const; diff --git a/src/core/preferences.cpp b/src/core/preferences.cpp index bb73d4a14..2259661a6 100644 --- a/src/core/preferences.cpp +++ b/src/core/preferences.cpp @@ -2501,6 +2501,25 @@ void Preferences::setHostNameCookies(const QString &host_name, const QList getHostNameQNetworkCookies(const QString& host_name) const; void setHostNameCookies(const QString &host_name, const QList &cookies); + // SpeedWidget + int getSpeedWidgetPeriod() const; + void setSpeedWidgetPeriod(const int period); + bool getSpeedWidgetGraphEnable(int id) const; + void setSpeedWidgetGraphEnable(int id, const bool enable); + public slots: void setStatusFilterState(bool checked); void setLabelFilterState(bool checked); diff --git a/src/gui/properties/properties.pri b/src/gui/properties/properties.pri index 347d70242..3551a3796 100644 --- a/src/gui/properties/properties.pri +++ b/src/gui/properties/properties.pri @@ -14,7 +14,9 @@ HEADERS += $$PWD/propertieswidget.h \ $$PWD/peeraddition.h \ $$PWD/trackersadditiondlg.h \ $$PWD/pieceavailabilitybar.h \ - $$PWD/proptabbar.h + $$PWD/proptabbar.h \ + $$PWD/speedwidget.h \ + $$PWD/speedplotview.h SOURCES += $$PWD/propertieswidget.cpp \ $$PWD/proplistdelegate.cpp \ @@ -24,4 +26,6 @@ SOURCES += $$PWD/propertieswidget.cpp \ $$PWD/downloadedpiecesbar.cpp \ $$PWD/peeraddition.cpp \ $$PWD/trackersadditiondlg.cpp \ - $$PWD/pieceavailabilitybar.cpp + $$PWD/pieceavailabilitybar.cpp \ + $$PWD/speedwidget.cpp \ + $$PWD/speedplotview.cpp diff --git a/src/gui/properties/propertieswidget.cpp b/src/gui/properties/propertieswidget.cpp index f1edb955f..ea96b0138 100644 --- a/src/gui/properties/propertieswidget.cpp +++ b/src/gui/properties/propertieswidget.cpp @@ -52,6 +52,7 @@ #include "torrentcontentfiltermodel.h" #include "torrentcontentmodel.h" #include "peerlistwidget.h" +#include "speedwidget.h" #include "trackerlist.h" #include "mainwindow.h" #include "downloadedpiecesbar.h" @@ -122,6 +123,9 @@ PropertiesWidget::PropertiesWidget(QWidget *parent, MainWindow* main_window, Tra connect(peersList->header(), SIGNAL(sectionMoved(int, int, int)), peersList, SLOT(saveSettings())); connect(peersList->header(), SIGNAL(sectionResized(int, int, int)), peersList, SLOT(saveSettings())); connect(peersList->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), peersList, SLOT(saveSettings())); + // Speed widget + speedWidget = new SpeedWidget(this); + speed_layout->addWidget(speedWidget); // Tab bar m_tabBar = new PropTabBar(); verticalLayout->addLayout(m_tabBar); @@ -149,6 +153,7 @@ PropertiesWidget::~PropertiesWidget() { delete refreshTimer; delete trackerList; delete peersList; + delete speedWidget; delete downloaded_pieces; delete pieces_availability; delete PropListModel; diff --git a/src/gui/properties/propertieswidget.h b/src/gui/properties/propertieswidget.h index 0f56b071e..5222db46b 100644 --- a/src/gui/properties/propertieswidget.h +++ b/src/gui/properties/propertieswidget.h @@ -43,6 +43,7 @@ class PropListDelegate; class torrent_file; class PeerListWidget; class TrackerList; +class SpeedWidget; class MainWindow; class DownloadedPiecesBar; class PieceAvailabilityBar; @@ -68,6 +69,7 @@ public: TrackerList* getTrackerList() const { return trackerList; } PeerListWidget* getPeerList() const { return peersList; } QTreeView* getFilesList() const { return filesList; } + SpeedWidget* getSpeedWidget() const { return speedWidget; } protected: QPushButton* getButtonFromIndex(int index); @@ -113,6 +115,7 @@ private: PropListDelegate *PropDelegate; PeerListWidget *peersList; TrackerList *trackerList; + SpeedWidget *speedWidget; QList slideSizes; DownloadedPiecesBar *downloaded_pieces; PieceAvailabilityBar *pieces_availability; diff --git a/src/gui/properties/propertieswidget.ui b/src/gui/properties/propertieswidget.ui index 55e899498..2340f5e32 100644 --- a/src/gui/properties/propertieswidget.ui +++ b/src/gui/properties/propertieswidget.ui @@ -1168,6 +1168,10 @@ + + + + diff --git a/src/gui/properties/proptabbar.cpp b/src/gui/properties/proptabbar.cpp index e2defb738..5b0b2c591 100644 --- a/src/gui/properties/proptabbar.cpp +++ b/src/gui/properties/proptabbar.cpp @@ -64,6 +64,10 @@ PropTabBar::PropTabBar(QWidget *parent) : m_btnGroup->addButton(files_button, FILES_TAB); // Spacer addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum)); + // Speed tab + QPushButton *speed_button = new QPushButton(GuiIconProvider::instance()->getIcon("office-chart-line"), tr("Speed"), parent); + addWidget(speed_button); + m_btnGroup->addButton(speed_button, SPEED_TAB); // SIGNAL/SLOT connect(m_btnGroup, SIGNAL(buttonClicked(int)), SLOT(setCurrentIndex(int))); // Disable buttons focus diff --git a/src/gui/properties/proptabbar.h b/src/gui/properties/proptabbar.h index 23c1d3774..85fffe9d2 100644 --- a/src/gui/properties/proptabbar.h +++ b/src/gui/properties/proptabbar.h @@ -43,7 +43,7 @@ class PropTabBar : public QHBoxLayout Q_DISABLE_COPY(PropTabBar) public: - enum PropertyTab {MAIN_TAB, TRACKERS_TAB, PEERS_TAB, URLSEEDS_TAB, FILES_TAB}; + enum PropertyTab {MAIN_TAB, TRACKERS_TAB, PEERS_TAB, URLSEEDS_TAB, FILES_TAB, SPEED_TAB}; public: explicit PropTabBar(QWidget *parent = 0); diff --git a/src/gui/properties/speedplotview.cpp b/src/gui/properties/speedplotview.cpp new file mode 100644 index 000000000..d671c8061 --- /dev/null +++ b/src/gui/properties/speedplotview.cpp @@ -0,0 +1,253 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015 Anton Lashkov + * + * 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. + */ + +#include "speedplotview.h" + +#include +#include +#include "core/utils/misc.h" + +SpeedPlotView::SpeedPlotView(QWidget *parent) + : QGraphicsView(parent) + , m_viewablePointsCount(MIN5_SEC) + , m_maxCapacity(HOUR6_SEC) +{ + QPen greenPen; + greenPen.setWidthF(1.5); + greenPen.setColor(QColor(134, 196, 63)); + QPen bluePen; + bluePen.setWidthF(1.5); + bluePen.setColor(QColor(50, 153, 255)); + + m_properties[UP] = GraphProperties(tr("Total Upload"), bluePen); + m_properties[DOWN] = GraphProperties(tr("Total Download"), greenPen); + + bluePen.setStyle(Qt::DashLine); + greenPen.setStyle(Qt::DashLine); + m_properties[PAYLOAD_UP] = GraphProperties(tr("Payload Upload"), bluePen); + m_properties[PAYLOAD_DOWN] = GraphProperties(tr("Payload Download"), greenPen); + + bluePen.setStyle(Qt::DashDotLine); + greenPen.setStyle(Qt::DashDotLine); + m_properties[OVERHEAD_UP] = GraphProperties(tr("Overhead Upload"), bluePen); + m_properties[OVERHEAD_DOWN] = GraphProperties(tr("Overhead Download"), greenPen); + + bluePen.setStyle(Qt::DashDotDotLine); + greenPen.setStyle(Qt::DashDotDotLine); + m_properties[DHT_UP] = GraphProperties(tr("DHT Upload"), bluePen); + m_properties[DHT_DOWN] = GraphProperties(tr("DHT Download"), greenPen); + + bluePen.setStyle(Qt::DotLine); + greenPen.setStyle(Qt::DotLine); + m_properties[TRACKER_UP] = GraphProperties(tr("Tracker Upload"), bluePen); + m_properties[TRACKER_DOWN] = GraphProperties(tr("Tracker Download"), greenPen); +} + +void SpeedPlotView::setGraphEnable(int id, bool enable) +{ + m_properties[id].enable = enable; +} + +void SpeedPlotView::pushXPoint(double x) +{ + while (m_xData.size() >= m_maxCapacity) + m_xData.pop_front(); + + m_xData.append(x); +} + +void SpeedPlotView::pushYPoint(int id, double y) +{ + while (m_yData[id].size() >= m_maxCapacity) + m_yData[id].pop_front(); + + m_yData[id].append(y); +} + +void SpeedPlotView::setViewableLastPoints(int period) +{ + m_viewablePointsCount = period; +} + +void SpeedPlotView::replot() +{ + this->viewport()->update(); +} + +double SpeedPlotView::maxYValue() +{ + double maxYValue = 0; + for (QMap >::const_iterator it = m_yData.begin(); it != m_yData.end(); ++it) { + + if (!m_properties[it.key()].enable) + continue; + + QQueue &queue = m_yData[it.key()]; + + for (int i = queue.size() - 1, j = 0; i >= 0 && j <= m_viewablePointsCount; --i, ++j) { + if (queue.at(i) > maxYValue) + maxYValue = queue.at(i); + } + } + + return maxYValue; +} + +void SpeedPlotView::paintEvent(QPaintEvent *) +{ + QPainter painter(this->viewport()); + + QRect full_rect = this->viewport()->rect(); + QRect rect = this->viewport()->rect(); + QFontMetrics font_metrics = painter.fontMetrics(); + + rect.adjust(4, 4, 0, -4); // Add padding + + double max_y = maxYValue(); + + rect.adjust(0, font_metrics.height(), 0, 0); // Add top padding for top speed text + + // draw Y axis speed labels + QVector speed_labels(QVector() << + Utils::Misc::friendlyUnit(max_y, true) << + Utils::Misc::friendlyUnit(0.75 * max_y, true) << + Utils::Misc::friendlyUnit(0.5 * max_y, true) << + Utils::Misc::friendlyUnit(0.25 * max_y, true) << + Utils::Misc::friendlyUnit(0, true)); + + int y_axe_width = 0; + for (int i = 0; i < speed_labels.size(); ++i) { + if (font_metrics.width(speed_labels[i]) > y_axe_width) + y_axe_width = font_metrics.width(speed_labels[i]); + } + + for (int i = 0; i < speed_labels.size(); ++i) { + QRectF label_rect(rect.topLeft() + QPointF(-y_axe_width, i * 0.25 * rect.height() - font_metrics.height()), + QSizeF(2 * y_axe_width, font_metrics.height())); + painter.drawText(label_rect, speed_labels[i], QTextOption((Qt::AlignRight) | (Qt::AlignTop))); + } + + // draw grid lines + rect.adjust(y_axe_width + 4, 0, 0, 0); + + QPen grid_pen; + grid_pen.setStyle(Qt::DashLine); + grid_pen.setWidthF(1); + grid_pen.setColor(QColor(128, 128, 128, 128)); + painter.setPen(grid_pen); + + painter.drawLine(full_rect.left(), rect.top(), rect.right(), rect.top()); + painter.drawLine(full_rect.left(), rect.top() + 0.25 * rect.height(), rect.right(), rect.top() + 0.25 * rect.height()); + painter.drawLine(full_rect.left(), rect.top() + 0.50 * rect.height(), rect.right(), rect.top() + 0.50 * rect.height()); + painter.drawLine(full_rect.left(), rect.top() + 0.75 * rect.height(), rect.right(), rect.top() + 0.75 * rect.height()); + painter.drawLine(full_rect.left(), rect.bottom(), rect.right(), rect.bottom()); + + painter.drawLine(rect.left(), full_rect.top(), rect.left(), full_rect.bottom()); + painter.drawLine(rect.left() + 0.2 * rect.width(), full_rect.top(), rect.left() + 0.2 * rect.width(), full_rect.bottom()); + painter.drawLine(rect.left() + 0.4 * rect.width(), full_rect.top(), rect.left() + 0.4 * rect.width(), full_rect.bottom()); + painter.drawLine(rect.left() + 0.6 * rect.width(), full_rect.top(), rect.left() + 0.6 * rect.width(), full_rect.bottom()); + painter.drawLine(rect.left() + 0.8 * rect.width(), full_rect.top(), rect.left() + 0.8 * rect.width(), full_rect.bottom()); + + // Set antialiasing for graphs + painter.setRenderHints(QPainter::Antialiasing | QPainter::HighQualityAntialiasing); + + // draw graphs + rect.adjust(3, 0, 0, 0); // Need, else graphs cross left gridline + + double y_multiplier = rect.height() / max_y; + double x_tick_size = double(rect.width()) / m_viewablePointsCount; + + for (QMap >::const_iterator it = m_yData.begin(); it != m_yData.end(); ++it) { + + if (!m_properties[it.key()].enable) + continue; + + QQueue &queue = m_yData[it.key()]; + QVector points; + + for (int i = queue.size() - 1, j = 0; i >= 0 && j <= m_viewablePointsCount; --i, ++j) { + points.push_back(QPointF(rect.right() - j * x_tick_size, + rect.bottom() - queue.at(i) * y_multiplier)); + } + + painter.setPen(m_properties[it.key()].pen); + painter.drawPolyline(points.data(), points.size()); + } + + // draw legend + QPoint legend_top_left(rect.left() + 4, full_rect.top() + 4); + + double legend_height = 0; + int legend_width = 0; + for (QMap::const_iterator it = m_properties.begin(); it != m_properties.end(); ++it) { + + if (!it.value().enable) + continue; + + if (font_metrics.width(it.value().name) > legend_width) + { + legend_width = font_metrics.width(it.value().name); + } + legend_height += 1.5 * font_metrics.height(); + } + + QRectF legend_background_rect(legend_top_left, QSizeF(legend_width, legend_height)); + painter.fillRect(legend_background_rect, QColor(255, 255, 255, 128)); // 50% transparent + + int i = 0; + for (QMap::const_iterator it = m_properties.begin(); it != m_properties.end(); ++it) { + + if (!it.value().enable) + continue; + + int name_size = font_metrics.width(it.value().name); + double indent = 1.5 * i * font_metrics.height(); + + painter.setPen(it.value().pen); + painter.drawLine(legend_top_left + QPointF(0, indent + font_metrics.height()), + legend_top_left + QPointF(name_size, indent + font_metrics.height())); + painter.drawText(QRectF(legend_top_left + QPointF(0, indent), QSizeF(2 * name_size, font_metrics.height())), + it.value().name, QTextOption(Qt::AlignVCenter)); + ++i; + } +} + +SpeedPlotView::GraphProperties::GraphProperties() + : name() + , pen() + , enable(false) +{ +} + +SpeedPlotView::GraphProperties::GraphProperties(const QString &_name, const QPen &_pen, bool _enable) + : name(_name) + , pen(_pen) + , enable(_enable) +{ +} + diff --git a/src/gui/properties/speedplotview.h b/src/gui/properties/speedplotview.h new file mode 100644 index 000000000..dcf9e1b0b --- /dev/null +++ b/src/gui/properties/speedplotview.h @@ -0,0 +1,107 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015 Anton Lashkov + * + * 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. + */ + +#ifndef SPEEDPLOTVIEW_H +#define SPEEDPLOTVIEW_H + +#include +#include +#include +class QPen; + +class SpeedPlotView : public QGraphicsView +{ + Q_OBJECT +public: + explicit SpeedPlotView(QWidget *parent = 0); + + void setGraphEnable(int id, bool enable); + + void pushXPoint(double x); + void pushYPoint(int id, double y); + + void setViewableLastPoints(int period); + + void replot(); + + enum GraphID + { + UP = 0, + DOWN, + PAYLOAD_UP, + PAYLOAD_DOWN, + OVERHEAD_UP, + OVERHEAD_DOWN, + DHT_UP, + DHT_DOWN, + TRACKER_UP, + TRACKER_DOWN, + NB_GRAPHS + }; + + enum TimePeriod + { + MIN1 = 0, + MIN5, + MIN30, + HOUR6 + }; + + enum PeriodInSeconds + { + MIN1_SEC = 60, + MIN5_SEC = 300, + MIN30_SEC = 1800, + HOUR6_SEC = 21600 + }; + +protected: + virtual void paintEvent(QPaintEvent *event); + +private: + struct GraphProperties + { + GraphProperties(); + GraphProperties(const QString &_name, const QPen &_pen, bool _enable = false); + + QString name; + QPen pen; + bool enable; + }; + + QQueue m_xData; + QMap > m_yData; + QMap m_properties; + + int m_viewablePointsCount; + int m_maxCapacity; + + double maxYValue(); +}; + +#endif // SPEEDPLOTVIEW_H diff --git a/src/gui/properties/speedwidget.cpp b/src/gui/properties/speedwidget.cpp new file mode 100644 index 000000000..e03f78add --- /dev/null +++ b/src/gui/properties/speedwidget.cpp @@ -0,0 +1,218 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015 Anton Lashkov + * + * 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. + */ + +#include "speedwidget.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "propertieswidget.h" +#include "core/bittorrent/session.h" +#include "core/bittorrent/sessionstatus.h" +#include "core/preferences.h" +#include "core/utils/misc.h" + +SpeedWidget::SpeedWidget(PropertiesWidget *parent) + : QWidget(parent) + , m_properties(parent) +{ + m_layout = new QVBoxLayout(this); + m_layout->setContentsMargins(0, 0, 0, 0); + + m_hlayout = new QHBoxLayout(); + m_hlayout->setContentsMargins(0, 0, 0, 0); + + m_periodLabel = new QLabel("" + tr("Period:") + ""); + + m_periodCombobox = new QComboBox(); + m_periodCombobox->addItem(tr("1 Minute")); + m_periodCombobox->addItem(tr("5 Minutes")); + m_periodCombobox->addItem(tr("30 Minutes")); + m_periodCombobox->addItem(tr("6 Hours")); + + connect(m_periodCombobox, SIGNAL(currentIndexChanged(int)), this, SLOT(onPeriodChange(int))); + + m_graphsButton = new QToolButton(); + m_graphsButton->setText(tr("Select Graphs")); + m_graphsButton->setPopupMode(QToolButton::InstantPopup); + m_graphsButton->setAutoExclusive(true); + + m_graphsMenu = new QMenu(); + m_graphsMenu->addAction(tr("Total Upload")); + m_graphsMenu->addAction(tr("Total Download")); + m_graphsMenu->addAction(tr("Payload Upload")); + m_graphsMenu->addAction(tr("Payload Download")); + m_graphsMenu->addAction(tr("Overhead Upload")); + m_graphsMenu->addAction(tr("Overhead Download")); + m_graphsMenu->addAction(tr("DHT Upload")); + m_graphsMenu->addAction(tr("DHT Download")); + m_graphsMenu->addAction(tr("Tracker Upload")); + m_graphsMenu->addAction(tr("Tracker Download")); + + m_graphsMenuActions = m_graphsMenu->actions(); + m_graphsSignalMapper = new QSignalMapper(); + + for (int id = SpeedPlotView::UP; id < SpeedPlotView::NB_GRAPHS; ++id) { + QAction *action = m_graphsMenuActions.at(id); + action->setCheckable(true); + action->setChecked(true); + connect(action, SIGNAL(changed()), m_graphsSignalMapper, SLOT(map())); + m_graphsSignalMapper->setMapping(action, id); + } + connect(m_graphsSignalMapper, SIGNAL(mapped(int)), this, SLOT(onGraphChange(int))); + + m_graphsButton->setMenu(m_graphsMenu); + + m_hlayout->addWidget(m_periodLabel); + m_hlayout->addWidget(m_periodCombobox); + m_hlayout->addStretch(); + m_hlayout->addWidget(m_graphsButton); + + m_plot = new SpeedPlotView(this); + + m_layout->addLayout(m_hlayout); + m_layout->addWidget(m_plot); + + loadSettings(); + + m_isUpdating = true; + m_updateFuture = QtConcurrent::run(this, &SpeedWidget::update); + + m_plot->show(); +} + +SpeedWidget::~SpeedWidget() +{ + qDebug("SpeedWidget::~SpeedWidget() ENTER"); + + m_isUpdating = false; + m_updateFuture.waitForFinished(); + + saveSettings(); + + qDebug("SpeedWidget::~SpeedWidget() EXIT"); +} + +void SpeedWidget::update() +{ + while (m_isUpdating) { + + BitTorrent::SessionStatus btStatus = BitTorrent::Session::instance()->status(); + + m_plot->pushXPoint(QDateTime::currentDateTime().toTime_t()); + m_plot->pushYPoint(SpeedPlotView::UP, btStatus.uploadRate()); + m_plot->pushYPoint(SpeedPlotView::DOWN, btStatus.downloadRate()); + m_plot->pushYPoint(SpeedPlotView::PAYLOAD_UP, btStatus.payloadUploadRate()); + m_plot->pushYPoint(SpeedPlotView::PAYLOAD_DOWN, btStatus.payloadDownloadRate()); + m_plot->pushYPoint(SpeedPlotView::OVERHEAD_UP, btStatus.ipOverheadUploadRate()); + m_plot->pushYPoint(SpeedPlotView::OVERHEAD_DOWN, btStatus.ipOverheadDownloadRate()); + m_plot->pushYPoint(SpeedPlotView::DHT_UP, btStatus.dhtUploadRate()); + m_plot->pushYPoint(SpeedPlotView::DHT_DOWN, btStatus.dhtDownloadRate()); + m_plot->pushYPoint(SpeedPlotView::TRACKER_UP, btStatus.trackerUploadRate()); + m_plot->pushYPoint(SpeedPlotView::TRACKER_DOWN, btStatus.trackerDownloadRate()); + + QMetaObject::invokeMethod(this, "graphUpdate"); + Utils::Misc::msleep(1000); + } +} + +void SpeedWidget::graphUpdate() +{ + m_plot->replot(); +} + +void SpeedWidget::onPeriodChange(int period) +{ + switch (period) { + case SpeedPlotView::MIN1: + m_plot->setViewableLastPoints(SpeedPlotView::MIN1_SEC); + break; + case SpeedPlotView::MIN5: + m_plot->setViewableLastPoints(SpeedPlotView::MIN5_SEC); + break; + case SpeedPlotView::MIN30: + m_plot->setViewableLastPoints(SpeedPlotView::MIN30_SEC); + break; + case SpeedPlotView::HOUR6: + m_plot->setViewableLastPoints(SpeedPlotView::HOUR6_SEC); + break; + default: + break; + } + + graphUpdate(); +} + +void SpeedWidget::onGraphChange(int id) +{ + QAction *action = m_graphsMenuActions.at(id); + m_plot->setGraphEnable(id, action->isChecked()); + + graphUpdate(); +} + +void SpeedWidget::loadSettings() +{ + Preferences *preferences = Preferences::instance(); + + int periodIndex = preferences->getSpeedWidgetPeriod(); + m_periodCombobox->setCurrentIndex(periodIndex); + onPeriodChange(periodIndex); + + for (int id = SpeedPlotView::UP; id < SpeedPlotView::NB_GRAPHS; ++id) { + QAction *action = m_graphsMenuActions.at(id); + + if (preferences->getSpeedWidgetGraphEnable(id)) { + action->setChecked(true); + m_plot->setGraphEnable(id, true); + } else { + action->setChecked(false); + m_plot->setGraphEnable(id, false); + } + } +} + +void SpeedWidget::saveSettings() const +{ + Preferences *preferences = Preferences::instance(); + + preferences->setSpeedWidgetPeriod(m_periodCombobox->currentIndex()); + + for (int id = SpeedPlotView::UP; id < SpeedPlotView::NB_GRAPHS; ++id) { + QAction *action = m_graphsMenuActions.at(id); + preferences->setSpeedWidgetGraphEnable(id, action->isChecked()); + } +} + diff --git a/src/gui/properties/speedwidget.h b/src/gui/properties/speedwidget.h new file mode 100644 index 000000000..0e6fde2e5 --- /dev/null +++ b/src/gui/properties/speedwidget.h @@ -0,0 +1,79 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015 Anton Lashkov + * + * 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. + */ + +#ifndef SPEEDWIDGET_H +#define SPEEDWIDGET_H + +#include +#include + +#include "speedplotview.h" + +class QVBoxLayout; +class QHBoxLayout; +class QLabel; +class QComboBox; +class QToolButton; +class QMenu; +class QSignalMapper; +class PropertiesWidget; + +class SpeedWidget : public QWidget +{ + Q_OBJECT +public: + SpeedWidget(PropertiesWidget *parent); + ~SpeedWidget(); + +private slots: + void onPeriodChange(int period); + void onGraphChange(int id); + +private: + void update(); + void loadSettings(); + void saveSettings() const; + Q_INVOKABLE void graphUpdate(); + + QVBoxLayout *m_layout; + QHBoxLayout *m_hlayout; + QLabel *m_periodLabel; + QComboBox *m_periodCombobox; + SpeedPlotView *m_plot; + PropertiesWidget *m_properties; + + QToolButton *m_graphsButton; + QMenu *m_graphsMenu; + QList m_graphsMenuActions; + QSignalMapper *m_graphsSignalMapper; + + QFuture m_updateFuture; + bool m_isUpdating; +}; + +#endif // SPEEDWIDGET_H diff --git a/src/icons.qrc b/src/icons.qrc index 860c6653d..724a96fce 100644 --- a/src/icons.qrc +++ b/src/icons.qrc @@ -368,5 +368,6 @@ icons/oxygen/go-bottom.png icons/oxygen/go-top.png icons/oxygen/checked.png + icons/oxygen/office-chart-line.png diff --git a/src/icons/oxygen/office-chart-line.png b/src/icons/oxygen/office-chart-line.png new file mode 100644 index 0000000000000000000000000000000000000000..816b2c5dd4dd292642241327f5c893190d094678 GIT binary patch literal 877 zcmV-z1CsoSP)Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L02{9W02{9XUK)`c00007bV*G`2iXD; z7a|s!Go?HL00QkvL_t(|+U=KLNYhai$IsdCH_OV2LLiY3$;^6aVfLuB22GG=VQE$* zmR1t^P%TrCWF<^!Rxd&>jl#0P9&%H`gdAjVVW1B_Xb=5)@GYCB53zguZuE`a7ThZApr#8nond2Iulj`&DH}*gsB9p zudnZf%Z~@(de4GERmi65c>MO!jblq@prxgy3T`A;(CWwYhMKPV)3x36uY{z}Qc|g0 zCId0E^7bFOP}>xc(yU1K0ooG~RMA?N?5B7KP|`NXP}?B{y%0!iQjgS=6VnL3w6(9 zs2{wNBL8s|M{Yu-+d@)#&r*5Iq*!fJ&!H?&EKUBX7KbMk<$FufGDUx0z8?NOb z0|vKcAf>~!(f|NIk%wA`QVw5eo9dnpKi}Q>odZJN40b-6@fu6LwSQ}~buqZzFkpD- zM)@A$IqHf7V5$2F_$h!LwvW#O+J2^ehIZVTF$M%R0!~7Z_waPH9~roSs2=E@w_C3eb~D@(VY6> z4>0|nI|LIO>_qGW+)9$q13VP<-aJiMwwwD2Hp3=S(gE1Iny{jc8%F>C7n z{`lcY-vv_2d}bbr(Vk|#Xm}4rG;K_;VlP4l5^ui%qZe0MT5;J|00000NkvXXu0mjf D1ptdC literal 0 HcmV?d00001