diff --git a/ktorrent/trayicon.cpp b/ktorrent/trayicon.cpp index a0b9f6ed..7175883c 100644 --- a/ktorrent/trayicon.cpp +++ b/ktorrent/trayicon.cpp @@ -1,450 +1,450 @@ /*************************************************************************** * Copyright (C) 2005-2007 by * * Joris Guisson * * Ivan Vasic * * * * 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. * ***************************************************************************/ #include "trayicon.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core.h" #include "gui.h" using namespace bt; namespace kt { TrayIcon::TrayIcon(Core* core, GUI* parent) : QObject(parent) , core(core) , mwnd(parent) , previousDownloadHeight(0) , previousUploadHeight(0) , max_upload_rate(nullptr) , max_download_rate(nullptr) , status_notifier_item(nullptr) , queue_suspended(false) , menu(nullptr) { connect(core, &Core::openedSilently, this, &TrayIcon::torrentSilentlyOpened); connect(core, &Core::finished, this, &TrayIcon::finished); connect(core, &Core::torrentStoppedByError, this, &TrayIcon::torrentStoppedByError); connect(core, &Core::maxShareRatioReached, this, &TrayIcon::maxShareRatioReached); connect(core, &Core::maxSeedTimeReached, this, &TrayIcon::maxSeedTimeReached); connect(core, &Core::corruptedData, this, &TrayIcon::corruptedData); connect(core, &Core::queuingNotPossible, this, &TrayIcon::queuingNotPossible); connect(core, &Core::canNotStart, this, &TrayIcon::canNotStart); connect(core, &Core::lowDiskSpace, this, &TrayIcon::lowDiskSpace); connect(core, &Core::canNotLoadSilently, this, &TrayIcon::cannotLoadTorrentSilently); connect(core, &Core::dhtNotEnabled, this, &TrayIcon::dhtNotEnabled); connect(core->getQueueManager(), SIGNAL(suspendStateChanged(bool)), this, SLOT(suspendStateChanged(bool))); suspendStateChanged(core->getQueueManager()->getSuspendedState()); } TrayIcon::~TrayIcon() {} void TrayIcon::hide() { if (!status_notifier_item) return; delete status_notifier_item; status_notifier_item = nullptr; menu = nullptr; max_download_rate = max_upload_rate = nullptr; } void TrayIcon::show() { if (status_notifier_item) { suspendStateChanged(core->getQueueManager()->getSuspendedState()); return; } status_notifier_item = new KStatusNotifierItem(mwnd); connect(status_notifier_item, &KStatusNotifierItem::secondaryActivateRequested, this, &TrayIcon::secondaryActivate); menu = status_notifier_item->contextMenu(); max_upload_rate = new SetMaxRate(core, SetMaxRate::UPLOAD, menu); max_upload_rate->setTitle(i18n("Set max upload speed")); max_download_rate = new SetMaxRate(core, SetMaxRate::DOWNLOAD, menu); max_download_rate->setTitle(i18n("Set max download speed")); menu->addMenu(max_download_rate); menu->addMenu(max_upload_rate); menu->addSeparator(); KActionCollection* ac = mwnd->getTorrentActivity()->part()->actionCollection(); menu->addAction(ac->action(QStringLiteral("start_all"))); menu->addAction(ac->action(QStringLiteral("stop_all"))); menu->addAction(ac->action(QStringLiteral("queue_suspend"))); menu->addSeparator(); ac = mwnd->actionCollection(); menu->addAction(ac->action(QStringLiteral("paste_url"))); menu->addAction(ac->action(QString::fromUtf8(KStandardAction::name(KStandardAction::Open)))); menu->addSeparator(); menu->addAction(ac->action(QString::fromUtf8(KStandardAction::name(KStandardAction::Preferences)))); menu->addSeparator(); status_notifier_item->setIconByName(QStringLiteral("ktorrent")); status_notifier_item->setCategory(KStatusNotifierItem::ApplicationStatus); status_notifier_item->setStatus(KStatusNotifierItem::Passive); status_notifier_item->setStandardActionsEnabled(true); status_notifier_item->setContextMenu(menu); queue_suspended = core->getQueueManager()->getSuspendedState(); if (queue_suspended) status_notifier_item->setOverlayIconByName(QStringLiteral("kt-pause")); } void TrayIcon::updateStats(const CurrentStats& stats) { if (!status_notifier_item) return; status_notifier_item->setStatus(core->getQueueManager()->getNumRunning(QueueManager::DOWNLOADS) > 0 ? KStatusNotifierItem::Active : KStatusNotifierItem::Passive); QString tip = i18n("Download speed: %1
" "Upload speed: %2
" "Received: %3
" "Transmitted: %4", BytesPerSecToString((double)stats.download_speed), BytesPerSecToString((double)stats.upload_speed), BytesToString(stats.bytes_downloaded), BytesToString(stats.bytes_uploaded)); status_notifier_item->setToolTip(QStringLiteral("ktorrent"), i18n("Status"), tip); } void TrayIcon::showPassivePopup(const QString& msg, const QString& title) { if (status_notifier_item) status_notifier_item->showMessage(title, msg, QStringLiteral("ktorrent")); } void TrayIcon::cannotLoadTorrentSilently(const QString& msg) { if (!Settings::showPopups()) return; KNotification::event(QStringLiteral("CannotLoadSilently"), msg, QPixmap(), mwnd); } void TrayIcon::dhtNotEnabled(const QString& msg) { if (!Settings::showPopups()) return; KNotification::event(QStringLiteral("DHTNotEnabled"), msg, QPixmap(), mwnd); } void TrayIcon::torrentSilentlyOpened(bt::TorrentInterface* tc) { if (!Settings::showPopups()) return; QString msg = i18n("%1 was silently opened.", tc->getDisplayName()); KNotification::event(QStringLiteral("TorrentSilentlyOpened"), msg, QPixmap(), mwnd); } void TrayIcon::finished(bt::TorrentInterface* tc) { if (!Settings::showPopups()) return; const TorrentStats& s = tc->getStats(); double speed_up = (double)s.bytes_uploaded; double speed_down = (double)(s.bytes_downloaded - s.imported_bytes); QString msg = i18n("%1 has completed downloading." "
Average speed: %2 DL / %3 UL.", tc->getDisplayName(), BytesPerSecToString(speed_down / tc->getRunningTimeDL()), BytesPerSecToString(speed_up / tc->getRunningTimeUL())); KNotification::event(QStringLiteral("TorrentFinished"), msg, QPixmap(), mwnd); } void TrayIcon::maxShareRatioReached(bt::TorrentInterface* tc) { if (!Settings::showPopups()) return; const TorrentStats& s = tc->getStats(); double speed_up = (double)s.bytes_uploaded; QString msg = i18n("%1 has reached its maximum share ratio of %2 and has been stopped." "
Uploaded %3 at an average speed of %4.", tc->getDisplayName(), - QLocale().toString(s.max_share_ratio, 'g', 2), + QLocale().toString(s.max_share_ratio, 'f', 2), BytesToString(s.bytes_uploaded), BytesPerSecToString(speed_up / tc->getRunningTimeUL())); KNotification::event(QStringLiteral("MaxShareRatioReached"), msg, QPixmap(), mwnd); } void TrayIcon::maxSeedTimeReached(bt::TorrentInterface* tc) { if (!Settings::showPopups()) return; const TorrentStats& s = tc->getStats(); double speed_up = (double)s.bytes_uploaded; QString msg = i18n("%1 has reached its maximum seed time of %2 hours and has been stopped." "
Uploaded %3 at an average speed of %4.", tc->getDisplayName(), - QLocale().toString(s.max_seed_time, 'g', 2), + QLocale().toString(s.max_seed_time, 'f', 2), BytesToString(s.bytes_uploaded), BytesPerSecToString(speed_up / tc->getRunningTimeUL())); KNotification::event(QStringLiteral("MaxSeedTimeReached"), msg, QPixmap(), mwnd); } void TrayIcon::torrentStoppedByError(bt::TorrentInterface* tc, QString msg) { if (!Settings::showPopups()) return; QString err_msg = i18n("%1 has been stopped with the following error:
%2", tc->getDisplayName(), msg); KNotification::event(QStringLiteral("TorrentStoppedByError"), err_msg, QPixmap(), mwnd); } void TrayIcon::corruptedData(bt::TorrentInterface* tc) { if (!Settings::showPopups()) return; QString err_msg = i18n("Corrupted data has been found in the torrent %1" "
It would be a good idea to do a data integrity check on the torrent.", tc->getDisplayName()); KNotification::event(QStringLiteral("CorruptedData"), err_msg, QPixmap(), mwnd); } void TrayIcon::queuingNotPossible(bt::TorrentInterface* tc) { if (!Settings::showPopups()) return; const TorrentStats& s = tc->getStats(); QString msg; if (tc->overMaxRatio()) msg = i18n("%1 has reached its maximum share ratio of %2 and cannot be enqueued. " "
Remove the limit manually if you want to continue seeding.", - tc->getDisplayName(), QLocale().toString(s.max_share_ratio, 'g', 2)); + tc->getDisplayName(), QLocale().toString(s.max_share_ratio, 'f', 2)); else msg = i18n("%1 has reached its maximum seed time of %2 hours and cannot be enqueued. " "
Remove the limit manually if you want to continue seeding.", - tc->getDisplayName(), QLocale().toString(s.max_seed_time, 'g', 2)); + tc->getDisplayName(), QLocale().toString(s.max_seed_time, 'f', 2)); KNotification::event(QStringLiteral("QueueNotPossible"), msg, QPixmap(), mwnd); } void TrayIcon::canNotStart(bt::TorrentInterface* tc, bt::TorrentStartResponse reason) { if (!Settings::showPopups()) return; QString msg = i18n("Cannot start %1:
", tc->getDisplayName()); switch (reason) { case bt::QM_LIMITS_REACHED: if (tc->getStats().bytes_left_to_download == 0) { // is a seeder msg += i18np("Cannot seed more than 1 torrent.
", "Cannot seed more than %1 torrents.
", Settings::maxSeeds()); } else { msg += i18np("Cannot download more than 1 torrent.
", "Cannot download more than %1 torrents.
", Settings::maxDownloads()); } msg += i18n("Go to Settings -> Configure KTorrent, if you want to change the limits."); KNotification::event(QStringLiteral("CannotStart"), msg, QPixmap(), mwnd); break; case bt::NOT_ENOUGH_DISKSPACE: msg += i18n("There is not enough diskspace available."); KNotification::event(QStringLiteral("CannotStart"), msg, QPixmap(), mwnd); break; default: break; } } void TrayIcon::lowDiskSpace(bt::TorrentInterface* tc, bool stopped) { if (!Settings::showPopups()) return; QString msg = i18n("Your disk is running out of space.
%1 is being downloaded to '%2'.", tc->getDisplayName(), tc->getDataDir()); if (stopped) msg.prepend(i18n("Torrent has been stopped.
")); KNotification::event(QStringLiteral("LowDiskSpace"), msg); } void TrayIcon::updateMaxRateMenus() { if (max_download_rate && max_upload_rate) { max_upload_rate->update(); max_download_rate->update(); } } SetMaxRate::SetMaxRate(Core* core, Type t, QWidget* parent) : QMenu(parent) { setIcon(t == UPLOAD ? QIcon::fromTheme(QStringLiteral("kt-set-max-upload-speed")) : QIcon::fromTheme(QStringLiteral("kt-set-max-download-speed"))); m_core = core; type = t; makeMenu(); connect(this, &SetMaxRate::triggered, this, &SetMaxRate::onTriggered); connect(this, &SetMaxRate::aboutToShow, this, &SetMaxRate::update); } SetMaxRate::~SetMaxRate() {} void SetMaxRate::makeMenu() { int rate = (type == UPLOAD) ? net::SocketMonitor::getUploadCap() / 1024 : net::SocketMonitor::getDownloadCap() / 1024; int maxBandwidth = (rate > 0) ? rate : (type == UPLOAD) ? 0 : 20 ; int delta = 0; int maxBandwidthRounded; setTitle(i18n("Speed limit in KiB/s")); unlimited = addAction(i18n("Unlimited")); unlimited->setCheckable(true); unlimited->setChecked(rate == 0); if ((maxBandwidth % 5) >= 3) maxBandwidthRounded = maxBandwidth + 5 - (maxBandwidth % 5); else maxBandwidthRounded = maxBandwidth - (maxBandwidth % 5); QList values; for (int i = 0; i < 15; i++) { if (delta == 0) values.append(maxBandwidth); else { if ((maxBandwidth % 5) != 0) { values.append(maxBandwidthRounded - delta); values.append(maxBandwidthRounded + delta); } else { values.append(maxBandwidth - delta); values.append(maxBandwidth + delta); } } delta += (delta >= 50) ? 50 : (delta >= 20) ? 10 : 5; } std::sort(values.begin(), values.end()); for (int v : qAsConst(values)) { if (v >= 1) { QAction* act = addAction(QString::number(v)); act->setCheckable(true); act->setChecked(rate == v); } } } void SetMaxRate::update() { clear(); makeMenu(); } void SetMaxRate::onTriggered(QAction* act) { int rate; if (act == unlimited) rate = 0; else rate = act->text().remove(QLatin1Char('&')).toInt(); // remove ampersands if (type == UPLOAD) { Settings::setMaxUploadRate(rate); net::SocketMonitor::setUploadCap(Settings::maxUploadRate() * 1024); } else { Settings::setMaxDownloadRate(rate); net::SocketMonitor::setDownloadCap(Settings::maxDownloadRate() * 1024); } Settings::self()->save(); } void TrayIcon::suspendStateChanged(bool suspended) { queue_suspended = suspended; if (status_notifier_item) status_notifier_item->setOverlayIconByName(suspended?QStringLiteral("kt-pause"):QString()); } void TrayIcon::secondaryActivate(const QPoint& pos) { Q_UNUSED(pos); core->setSuspendedState(!core->getSuspendedState()); } } diff --git a/plugins/infowidget/peerviewmodel.cpp b/plugins/infowidget/peerviewmodel.cpp index d7ff12b4..119b1dd8 100644 --- a/plugins/infowidget/peerviewmodel.cpp +++ b/plugins/infowidget/peerviewmodel.cpp @@ -1,353 +1,353 @@ /*************************************************************************** * Copyright (C) 2008 by Joris Guisson and Ivan Vasic * * joris.guisson@gmail.com * * ivasic@gmail.com * * * * 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. * ***************************************************************************/ #include "peerviewmodel.h" #include #include #include #include #include #include #include "flagdb.h" #include "geoipmanager.h" using namespace bt; namespace kt { static QIcon yes, no; static bool icons_loaded = false; static FlagDB flagDB(22, 18); PeerViewModel::Item::Item(bt::PeerInterface* peer, GeoIPManager* geo_ip) : peer(peer) { stats = peer->getStats(); if (!icons_loaded) { yes = QIcon::fromTheme(QStringLiteral("dialog-ok")); no = QIcon::fromTheme(QStringLiteral("dialog-cancel")); icons_loaded = true; QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf5/locale/countries"), QStandardPaths::LocateDirectory); if (!path.isEmpty()) flagDB.addFlagSource(path + QStringLiteral("/%1/flag.png")); } if (geo_ip) { int country_id = geo_ip->findCountry(stats.ip_address); if (country_id > 0) { country = geo_ip->countryName(country_id); flag = flagDB.getFlag(geo_ip->countryCode(country_id)); } } } bool PeerViewModel::Item::changed() const { const PeerInterface::Stats& s = peer->getStats(); bool ret = s.download_rate != stats.download_rate || s.upload_rate != stats.upload_rate || s.choked != stats.choked || s.snubbed != stats.snubbed || s.perc_of_file != stats.perc_of_file || s.aca_score != stats.aca_score || s.has_upload_slot != stats.has_upload_slot || s.num_down_requests != stats.num_down_requests || s.num_up_requests != stats.num_up_requests || s.bytes_downloaded != stats.bytes_downloaded || s.bytes_uploaded != stats.bytes_uploaded || s.interested != stats.interested || s.am_interested != stats.am_interested; stats = s; return ret; } QVariant PeerViewModel::Item::data(int col) const { switch (col) { case 0: if (stats.transport_protocol == bt::UTP) return QString(stats.address() + i18n(" (µTP)")); else return stats.address(); case 1: return country; case 2: return stats.client; case 3: if (stats.download_rate >= 103) return BytesPerSecToString(stats.download_rate); else return QVariant(); case 4: if (stats.upload_rate >= 103) return BytesPerSecToString(stats.upload_rate); else return QVariant(); case 5: return stats.choked ? i18nc("Choked", "Yes") : i18nc("Not choked", "No"); case 6: return stats.snubbed ? i18nc("Snubbed", "Yes") : i18nc("Not snubbed", "No"); case 7: return QString(QString::number((int)stats.perc_of_file) + QLatin1String(" %")); case 8: return QVariant(); - case 9: return QLocale().toString(stats.aca_score, 'g', 2); + case 9: return QLocale().toString(stats.aca_score, 'f', 2); case 10: return QVariant(); case 11: return QString(QString::number(stats.num_down_requests) + QLatin1String(" / ") + QString::number(stats.num_up_requests)); case 12: return BytesToString(stats.bytes_downloaded); case 13: return BytesToString(stats.bytes_uploaded); case 14: return stats.interested ? i18nc("Interested", "Yes") : i18nc("Not Interested", "No"); case 15: return stats.am_interested ? i18nc("Interesting", "Yes") : i18nc("Not Interesting", "No"); default: return QVariant(); } return QVariant(); } QVariant PeerViewModel::Item::sortData(int col) const { switch (col) { case 0: return stats.address(); case 1: return country; case 2: return stats.client; case 3: return stats.download_rate; case 4: return stats.upload_rate; case 5: return stats.choked; case 6: return stats.snubbed; case 7: return stats.perc_of_file; case 8: return stats.dht_support; case 9: return stats.aca_score; case 10: return stats.has_upload_slot; case 11: return stats.num_down_requests + stats.num_up_requests; case 12: return stats.bytes_downloaded; case 13: return stats.bytes_uploaded; case 14: return stats.interested; case 15: return stats.am_interested; default: return QVariant(); } } QVariant PeerViewModel::Item::decoration(int col) const { switch (col) { case 0: if (stats.encrypted) return QIcon::fromTheme(QStringLiteral("kt-encrypted")); break; case 1: return flag; case 8: return stats.dht_support ? yes : no; case 10: return stats.has_upload_slot ? yes : QIcon(); } return QVariant(); } ///////////////////////////////////////////////////////////// PeerViewModel::PeerViewModel(QObject* parent) : QAbstractTableModel(parent), geo_ip(nullptr) { geo_ip = new GeoIPManager(this); } PeerViewModel::~PeerViewModel() { qDeleteAll(items); } void PeerViewModel::peerAdded(bt::PeerInterface* peer) { items.append(new Item(peer, geo_ip)); insertRow(items.count() - 1); } void PeerViewModel::peerRemoved(bt::PeerInterface* peer) { for (QVector::iterator i = items.begin(); i != items.end(); i++) { if ((*i)->peer == peer) { removeRow(i - items.begin()); break; } } } void PeerViewModel::clear() { beginResetModel(); qDeleteAll(items); items.clear(); endResetModel(); } void PeerViewModel::update() { int idx = 0; int lowest = -1; int highest = -1; foreach (Item* i, items) { if (i->changed()) { if (lowest == -1) lowest = idx; highest = idx; } idx++; } // emit only one data changed signal if (lowest != -1) emit dataChanged(index(lowest, 3), index(highest, 15)); } QModelIndex PeerViewModel::index(int row, int column, const QModelIndex& parent) const { if (!hasIndex(row, column, parent) || parent.isValid()) return QModelIndex(); else return createIndex(row, column, items[row]); } int PeerViewModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; else return items.count(); } int PeerViewModel::columnCount(const QModelIndex& parent) const { if (parent.isValid()) return 0; else return 16; } QVariant PeerViewModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation != Qt::Horizontal) return QVariant(); if (role == Qt::DisplayRole) { switch (section) { case 0: return i18n("Address"); case 1: return i18n("Country"); case 2: return i18n("Client"); case 3: return i18n("Down Speed"); case 4: return i18n("Up Speed"); case 5: return i18n("Choked"); case 6: return i18n("Snubbed"); case 7: return i18n("Availability"); case 8: return i18n("DHT"); case 9: return i18n("Score"); case 10: return i18n("Upload Slot"); case 11: return i18n("Requests"); case 12: return i18n("Downloaded"); case 13: return i18n("Uploaded"); case 14: return i18n("Interested"); case 15: return i18n("Interesting"); default: return QVariant(); } } else if (role == Qt::ToolTipRole) { switch (section) { case 0: return i18n("IP address of the peer"); case 1: return i18n("Country the peer is in"); case 2: return i18n("Which client the peer is using"); case 3: return i18n("Download speed"); case 4: return i18n("Upload speed"); case 5: return i18n("Whether or not the peer has choked us - when we are choked the peer will not send us any data"); case 6: return i18n("Snubbed means the peer has not sent us any data in the last 2 minutes"); case 7: return i18n("How much data the peer has of the torrent"); case 8: return i18n("Whether or not the peer has DHT enabled"); case 9: return i18n("The score of the peer, KTorrent uses this to determine who to upload to"); case 10: return i18n("Only peers which have an upload slot will get data from us"); case 11: return i18n("The number of download and upload requests"); case 12: return i18n("How much data we have downloaded from this peer"); case 13: return i18n("How much data we have uploaded to this peer"); case 14: return i18n("Whether the peer is interested in downloading data from us"); case 15: return i18n("Whether we are interested in downloading from this peer"); default: return QVariant(); } } return QVariant(); } QVariant PeerViewModel::data(const QModelIndex& index, int role) const { if (!index.isValid() || index.row() >= items.count()) return QVariant(); Item* item = items[index.row()]; if (role == Qt::DisplayRole) return item->data(index.column()); else if (role == Qt::UserRole) return item->sortData(index.column()); else if (role == Qt::DecorationRole) return item->decoration(index.column()); return QVariant(); } bool PeerViewModel::removeRows(int row, int count, const QModelIndex& /*parent*/) { beginRemoveRows(QModelIndex(), row, row + count - 1); for (int i = 0; i < count; i++) delete items[row + i]; items.remove(row, count); endRemoveRows(); return true; } bool PeerViewModel::insertRows(int row, int count, const QModelIndex& /*parent*/) { beginInsertRows(QModelIndex(), row, row + count - 1); endInsertRows(); return true; } bt::PeerInterface* PeerViewModel::indexToPeer(const QModelIndex& index) { if (!index.isValid() || index.row() >= items.count()) return nullptr; else return ((Item*)index.internalPointer())->peer; } } diff --git a/plugins/infowidget/statustab.cpp b/plugins/infowidget/statustab.cpp index e6e42605..79266e96 100644 --- a/plugins/infowidget/statustab.cpp +++ b/plugins/infowidget/statustab.cpp @@ -1,351 +1,351 @@ /*************************************************************************** * Copyright (C) 2005-2007 by Joris Guisson * * joris.guisson@gmail.com * * * * 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. * ***************************************************************************/ #include #include #include #include #include #include #include #include #include "downloadedchunkbar.h" #include "availabilitychunkbar.h" #include "statustab.h" #include "settings.h" using namespace bt; namespace kt { StatusTab::StatusTab(QWidget* parent) : QWidget(parent) { setupUi(this); // do not use hardcoded colors hdr_info->setBackgroundRole(QPalette::Mid); hdr_chunks->setBackgroundRole(QPalette::Mid); hdr_sharing->setBackgroundRole(QPalette::Mid); QFont f = font(); f.setBold(true); share_ratio->setFont(f); avg_down_speed->setFont(f); avg_up_speed->setFont(f); type->setFont(f); comments->setFont(f); info_hash->setFont(f); ratio_limit->setMinimum(0.0f); ratio_limit->setMaximum(100.0f); ratio_limit->setSingleStep(0.1f); ratio_limit->setKeyboardTracking(false); connect(ratio_limit, static_cast(&QDoubleSpinBox::valueChanged), this, &StatusTab::maxRatioChanged); connect(use_ratio_limit, &QCheckBox::toggled, this, &StatusTab::useRatioLimitToggled); time_limit->setMinimum(0.0f); time_limit->setMaximum(10000000.0f); time_limit->setSingleStep(0.05f); time_limit->setSpecialValueText(i18n("No limit")); time_limit->setKeyboardTracking(false); connect(use_time_limit, &QCheckBox::toggled, this, &StatusTab::useTimeLimitToggled); connect(time_limit, static_cast(&QDoubleSpinBox::valueChanged), this, &StatusTab::maxTimeChanged); int h = (int)ceil(fontMetrics().height() * 1.25); downloaded_bar->setFixedHeight(h); availability_bar->setFixedHeight(h); comments->setTextInteractionFlags(Qt::LinksAccessibleByMouse | Qt::LinksAccessibleByKeyboard | Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard); connect(comments, &KSqueezedTextLabel::linkActivated, this, &StatusTab::linkActivated); // initialize everything with curr_tc == 0 setEnabled(false); ratio_limit->setValue(0.00f); share_ratio->clear(); type->clear(); comments->clear(); avg_up_speed->clear(); avg_down_speed->clear(); info_hash->clear(); } StatusTab::~StatusTab() {} void StatusTab::changeTC(bt::TorrentInterface* tc) { if (tc == curr_tc.data()) return; curr_tc = tc; downloaded_bar->setTC(tc); availability_bar->setTC(tc); setEnabled(tc != 0); if (curr_tc) { info_hash->setText(tc->getInfoHash().toString()); type->setText(tc->getStats().priv_torrent ? i18n("Private") : i18n("Public")); // Don't allow multiple lines in the comments field QString text = tc->getComments(); if (text.contains(QLatin1String("\n"))) text = text.replace(QLatin1Char('\n'), QLatin1Char(' ')); // Make links clickable QStringList words = text.split(QLatin1Char(' '), QString::KeepEmptyParts); for (QStringList::iterator i = words.begin(); i != words.end(); i++) { QString& w = *i; if (w.startsWith(QLatin1String("http://")) || w.startsWith(QLatin1String("https://")) || w.startsWith(QLatin1String("ftp://"))) w = QStringLiteral("") + w + QStringLiteral(""); } comments->setText(words.join(QStringLiteral(" "))); float ratio = tc->getMaxShareRatio(); if (ratio > 0) { use_ratio_limit->setChecked(true); ratio_limit->setValue(ratio); ratio_limit->setEnabled(true); } else { ratio_limit->setValue(0.0); use_ratio_limit->setChecked(false); ratio_limit->setEnabled(false); } float hours = tc->getMaxSeedTime(); if (hours > 0) { time_limit->setEnabled(true); use_time_limit->setChecked(true); time_limit->setValue(hours); } else { time_limit->setEnabled(false); time_limit->setValue(0.0); use_time_limit->setChecked(false); } } else { info_hash->clear(); ratio_limit->setValue(0.00f); time_limit->setValue(0.0); share_ratio->clear(); type->clear(); comments->clear(); avg_up_speed->clear(); avg_down_speed->clear(); } update(); } void StatusTab::update() { if (!curr_tc) return; bt::TorrentInterface* tc = curr_tc.data(); const bt::TorrentStats& s = tc->getStats(); downloaded_bar->updateBar(); availability_bar->updateBar(); float ratio = s.shareRatio(); if (!ratio_limit->hasFocus()) maxRatioUpdate(); if (!time_limit->hasFocus()) maxSeedTimeUpdate(); static QLocale locale; - share_ratio->setText(QStringLiteral("%2").arg(ratio <= Settings::greenRatio() ? QStringLiteral("#ff0000") : QStringLiteral("#1c9a1c")).arg(locale.toString(ratio, 'g', 2))); + share_ratio->setText(QStringLiteral("%2").arg(ratio <= Settings::greenRatio() ? QStringLiteral("#ff0000") : QStringLiteral("#1c9a1c")).arg(locale.toString(ratio, 'f', 2))); Uint32 secs = tc->getRunningTimeUL(); if (secs == 0) { avg_up_speed->setText(BytesPerSecToString(0)); } else { double r = (double)s.bytes_uploaded; avg_up_speed->setText(BytesPerSecToString(r / secs)); } secs = tc->getRunningTimeDL(); if (secs == 0) { avg_down_speed->setText(BytesPerSecToString(0)); } else { double r = 0; if (s.imported_bytes <= s.bytes_downloaded) r = (double)(s.bytes_downloaded - s.imported_bytes); else r = (double)s.bytes_downloaded; avg_down_speed->setText(BytesPerSecToString(r / secs)); } } void StatusTab::maxRatioChanged(double v) { if (!curr_tc) return; curr_tc.data()->setMaxShareRatio(v); } void StatusTab::useRatioLimitToggled(bool state) { if (!curr_tc) return; bt::TorrentInterface* tc = curr_tc.data(); ratio_limit->setEnabled(state); if (!state) { tc->setMaxShareRatio(0.00f); ratio_limit->setValue(0.00f); } else { float msr = tc->getMaxShareRatio(); if (msr == 0.00f) { tc->setMaxShareRatio(1.00f); ratio_limit->setValue(1.00f); } float sr = tc->getStats().shareRatio(); if (sr >= 1.00f) { //always add 1 to max share ratio to prevent stopping if torrent is running. tc->setMaxShareRatio(sr + 1.00f); ratio_limit->setValue(sr + 1.00f); } } } void StatusTab::maxRatioUpdate() { if (!curr_tc) return; float ratio = curr_tc.data()->getMaxShareRatio(); if (ratio > 0.00f) { // only update when needed if (ratio_limit->isEnabled() && use_ratio_limit->isChecked() && ratio_limit->value() == ratio) return; ratio_limit->setEnabled(true); use_ratio_limit->setChecked(true); ratio_limit->setValue(ratio); } else { // only update when needed if (!ratio_limit->isEnabled() && !use_ratio_limit->isChecked() && ratio_limit->value() != 0.00f) return; ratio_limit->setEnabled(false); use_ratio_limit->setChecked(false); ratio_limit->setValue(0.00f); } } void StatusTab::maxSeedTimeUpdate() { if (!curr_tc) return; float time = curr_tc.data()->getMaxSeedTime(); if (time > 0.00f) { // only update when needed if (time_limit->isEnabled() && use_time_limit->isChecked() && time_limit->value() == time) return; time_limit->setEnabled(true); use_time_limit->setChecked(true); time_limit->setValue(time); } else { // only update when needed if (!time_limit->isEnabled() && !use_time_limit->isChecked() && time_limit->value() != 0.00f) return; time_limit->setEnabled(false); use_time_limit->setChecked(false); time_limit->setValue(0.00f); } } void StatusTab::useTimeLimitToggled(bool on) { if (!curr_tc) return; bt::TorrentInterface* tc = curr_tc.data(); time_limit->setEnabled(on); if (on) { Uint32 dl = tc->getRunningTimeDL(); Uint32 ul = tc->getRunningTimeUL(); float hours = (ul - dl) / 3600.0f + 1.0; // add one hour to current seed time to not stop immediately time_limit->setValue(hours); tc->setMaxSeedTime(hours); } else { tc->setMaxSeedTime(0.0f); } } void StatusTab::maxTimeChanged(double v) { if (curr_tc) curr_tc.data()->setMaxSeedTime(v); } void StatusTab::linkActivated(const QString& link) { new KRun(QUrl(link), QApplication::activeWindow()); } }