From 8ab7be77524b50a38852b0623c47d00b01253bdb Mon Sep 17 00:00:00 2001 From: lvaatamoinen Date: Thu, 31 Dec 2009 08:56:54 +0000 Subject: [PATCH] - DownloadView columns can be now hidden by user preference. Settings are persistent - ETA counter working - DBus interface etended a bit to incorporate downloaded data amout in alerts git-svn-id: file:///svnroot/qtrapids/trunk@57 42ac0dd5-4c8c-4c71-bb3e-ecdfe252ffda --- dbus/com.ixonos.qtrapids.xml | 2 +- src/client/CMakeLists.txt | 2 + src/client/ColumnSelectorDialog.cpp | 105 +++++++++++++++++++++++++++++++++++ src/client/ColumnSelectorDialog.h | 60 ++++++++++++++++++++ src/client/DownloadView.cpp | 40 ++++++++++++- src/client/DownloadView.h | 21 +++++-- src/client/MainWindow.cpp | 29 +++++++++- src/client/MainWindow.h | 1 + src/include/qtrapids/dbus.hpp | 8 ++- src/include/qtrapids/format.hpp | 44 ++++++++++++++- src/server/TorrentHandle.cpp | 5 ++ src/server/TorrentHandle.hpp | 1 + src/server/TorrentSession.cpp | 4 +- 13 files changed, 307 insertions(+), 15 deletions(-) create mode 100644 src/client/ColumnSelectorDialog.cpp create mode 100644 src/client/ColumnSelectorDialog.h diff --git a/dbus/com.ixonos.qtrapids.xml b/dbus/com.ixonos.qtrapids.xml index 520085d..05d9bbf 100644 --- a/dbus/com.ixonos.qtrapids.xml +++ b/dbus/com.ixonos.qtrapids.xml @@ -20,7 +20,7 @@ - + diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 5546525..dccbcee 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -22,6 +22,7 @@ SET(MOC_HEADERS ./PreferencesDialog.h ./proxy.h ./SeedView.h + ./ColumnSelectorDialog.h ) SET(SRC @@ -31,6 +32,7 @@ SET(SRC ./PreferencesDialog.cpp ./proxy.cpp ./SeedView.cpp + ./ColumnSelectorDialog.cpp ) QT4_WRAP_CPP(SRC ${MOC_HEADERS}) diff --git a/src/client/ColumnSelectorDialog.cpp b/src/client/ColumnSelectorDialog.cpp new file mode 100644 index 0000000..153199a --- /dev/null +++ b/src/client/ColumnSelectorDialog.cpp @@ -0,0 +1,105 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.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., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include +#include +#include +#include +#include + +#include "ColumnSelectorDialog.h" + + +ColumnSelectorDialog::ColumnSelectorDialog(QTreeWidget *treewidget, QWidget* parent, Qt::WindowFlags f) : + QDialog(parent, f), // Superclass construct + dialogButtons_(0), + grid_(0), + treeWidget_(treewidget), + checkBoxes_() +{ + QBoxLayout *verticalBox = new QBoxLayout(QBoxLayout::TopToBottom); + grid_ = new QGridLayout; + QCheckBox *cbox = NULL; + + setLayout(verticalBox); + verticalBox->addLayout(grid_); + + if (treeWidget_ != NULL) { + QTreeWidgetItem *item = treeWidget_->headerItem(); + + for (unsigned i = 0; i < item->columnCount(); ++i) { + cbox = new QCheckBox(item->text(i)); + grid_->addWidget(cbox, i, 0); + treeWidget_->isColumnHidden(i) ? cbox->setCheckState(Qt::Unchecked) : cbox->setCheckState(Qt::Checked); + checkBoxes_.push_back(cbox); + cbox = NULL; + } + } + + dialogButtons_ = new QDialogButtonBox(this); + dialogButtons_->setStandardButtons(QDialogButtonBox::Ok + | QDialogButtonBox::Cancel); + + verticalBox->addWidget(dialogButtons_); + + connect(dialogButtons_, SIGNAL(clicked(QAbstractButton*)), + this, SLOT(on_buttonClicked(QAbstractButton*))); +} + + +ColumnSelectorDialog::~ColumnSelectorDialog() +{ +} + + +void ColumnSelectorDialog::on_buttonClicked(QAbstractButton *button) +{ + switch (dialogButtons_->buttonRole ( button ) ) { + case QDialogButtonBox::AcceptRole : + ApplySettings(); + done(QDialog::Accepted); + break; + case QDialogButtonBox::ApplyRole : + ApplySettings(); + done(QDialog::Accepted); + break; + case QDialogButtonBox::RejectRole : + done(QDialog::Rejected); + break; + default: + return; + } +} + + +void ColumnSelectorDialog::ApplySettings() +{ + if (treeWidget_ != NULL) { + QTreeWidgetItem *item = treeWidget_->headerItem(); + QCheckBox *cbox = NULL; + + for (unsigned i = 0; i < checkBoxes_.size(); ++i) { + cbox = checkBoxes_.at(i); + cbox->isChecked() ? treeWidget_->showColumn(i) : treeWidget_->hideColumn(i); + cbox = NULL; + } + } +} + diff --git a/src/client/ColumnSelectorDialog.h b/src/client/ColumnSelectorDialog.h new file mode 100644 index 0000000..d803f3a --- /dev/null +++ b/src/client/ColumnSelectorDialog.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2009 by Lassi Väätämöinen * + * lassi.vaatamoinen@ixonos.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., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef COLUMNSELECTORDIALOG_H +#define COLUMNSELECTORDIALOG_H + +#include +#include +#include + +class QTreeWidget; +class QDialogButtonBox; +class QGridLayout; +class QTreeWidget; +class QCheckBox; +class QAbstractButton; + +/** + @author Lassi Väätämöinen + @brief Dialog for selecting columns in QTreeViewWidget +*/ +class ColumnSelectorDialog : public QDialog +{ + Q_OBJECT + + public: + ColumnSelectorDialog(QTreeWidget *treewidget, QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~ColumnSelectorDialog(); + + private slots: + void on_buttonClicked(QAbstractButton *button); + + private: + QDialogButtonBox *dialogButtons_; + QGridLayout *grid_; + QTreeWidget *treeWidget_; + std::vector checkBoxes_; + + private: + void ApplySettings(); + +}; + +#endif diff --git a/src/client/DownloadView.cpp b/src/client/DownloadView.cpp index dc18f06..7416ecb 100644 --- a/src/client/DownloadView.cpp +++ b/src/client/DownloadView.cpp @@ -30,7 +30,8 @@ namespace qtrapids DownloadView::DownloadView(QWidget* parent) : QTreeWidget(parent), - items_() + items_(), + settings_() { setRootIsDecorated(false); // Hide branch lines, making one-level treeview (similar to list) setHeaderItem(DownloadViewItem::getHeaderItem()); @@ -127,7 +128,17 @@ void DownloadView::updateItem_(DownloadViewItem *item QVariant(formatSize(info.up_rate))); item->setData(6, Qt::DisplayRole, QString::number(info.seeds) + "/" + QString::number(info.leeches)); - + item->setData(7, Qt::DisplayRole, QString::number(info.ratio)); + + // Calculate ETA + if (info.down_rate > 0) { + qulonglong eta = (info.total_size - info.total_done) / info.down_rate; + item->setData(8, Qt::DisplayRole, formatElapsedTime(eta)); + } else { + item->setData(8, Qt::DisplayRole, "N/A"); + } + + // Set color for status text QBrush brushTmp(GetStatusColor((TorrentStatus::Id)info.state)); item->setForeground(2, brushTmp); } @@ -161,6 +172,31 @@ void DownloadView::on_itemClicked(QTreeWidgetItem * , int) } +void DownloadView::saveView() +{ + QTreeWidgetItem *item = headerItem(); + QList columns; + + for (int i = 0; i < item->columnCount(); ++i) { + isColumnHidden(i) ? columns.push_back(QVariant(false)) : columns.push_back(QVariant(true)); + } + + settings_.setValue("downloadview_columns", QVariant(columns)); +} + + +void DownloadView::restoreView() +{ + QTreeWidgetItem *item = headerItem(); + QVariant columns(settings_.value("downloadview_columns")); + QList columnList = columns.toList(); + + for (int i = 0; i < columnList.size(); ++i) { + columnList.at(i).toBool() ? setColumnHidden(i, false) : setColumnHidden(i, true); + } +} + + QString DownloadView::GetStatusString(TorrentStatus::Id status) { switch (status) { diff --git a/src/client/DownloadView.h b/src/client/DownloadView.h index 459bde2..add63a6 100644 --- a/src/client/DownloadView.h +++ b/src/client/DownloadView.h @@ -50,23 +50,34 @@ public: void updateItem(TorrentState const& info, ParamsMap_t other_info); QString prepareRemoveSelected(); - + + /// Saves current view settings via QSettings + void saveView(); + /// Reads view settigns via QSettings + void restoreView(); + private slots: void on_itemClicked(QTreeWidgetItem * item, int column); + private: + // Maps torrent to downloadview item. + // Key: SHA1 info hash of torrent. Data: View item corresponding to torrent. + DownloadItems_t items_; + // Used for saving view settings + QSettings settings_; + +private: + // Private functions. void addItem_(TorrentState const& info, ParamsMap_t other_info); void updateItem_(DownloadViewItem *item , TorrentState const& info, ParamsMap_t other_info); void removeItem_(DownloadViewItem *item, TorrentState const& info); - // Maps torrent to downloadview item. - // Key: SHA1 info hash of torrent. Data: View item corresponding to torrent. - DownloadItems_t items_; - // Private functions. static QString GetStatusString(TorrentStatus::Id status); static QColor GetStatusColor(TorrentStatus::Id status); + }; diff --git a/src/client/MainWindow.cpp b/src/client/MainWindow.cpp index 8b89ae8..221ac60 100644 --- a/src/client/MainWindow.cpp +++ b/src/client/MainWindow.cpp @@ -27,12 +27,14 @@ #include #include #include +//#include #include #include #include "DownloadView.h" #include "SeedView.h" #include "PreferencesDialog.h" +#include "ColumnSelectorDialog.h" #include "MainWindow.h" @@ -44,7 +46,7 @@ const QString ABOUT_TEXT "\nQt and Libtorrent." "\n\nURL: http://qtrapids.garage.maemo.org/" "\n\nAuthors:\nLassi Väätämöinen, lassi.vaatamoinen@ixonos.com" - "\nDenis Zalevskiy, denis.zalewsky@ixonos.com" + "\nDenis Zalevskiy, denis.zalewsky@gmail.com" "\n\nIxonos Plc, Finland\n")); const QString PLUGINS_DIR = "plugins"; @@ -74,6 +76,9 @@ MainWindow::MainWindow() : removeAction->setEnabled(false); QAction *quitAction = tempMenu->addAction(tr("&Quit")); + tempMenu = menuBar->addMenu(tr("&View")); + QAction *columnsAction = tempMenu->addAction(tr("&Columns")); + tempMenu = menuBar->addMenu(tr("&Settings")); QAction *preferencesAction = tempMenu->addAction(tr("&Preferences")); @@ -86,6 +91,7 @@ MainWindow::MainWindow() : connect(removeAction, SIGNAL(triggered()), this, SLOT(on_removeAction_clicked())); connect(this, SIGNAL(itemSelected(bool)), removeAction, SLOT(setEnabled(bool))); connect(quitAction, SIGNAL(triggered()), this, SLOT(on_quitAction_clicked())); + connect(columnsAction, SIGNAL(triggered()), this, SLOT(on_columnsAction_clicked())); connect(preferencesAction, SIGNAL(triggered()), this, SLOT(on_preferencesAction_clicked())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(on_aboutAction_clicked())); connect(aboutQtAction, SIGNAL(triggered()), this, SLOT(on_aboutQtAction_clicked())); @@ -290,6 +296,9 @@ void MainWindow::RestoreSettings() restoreGeometry(geometry.toByteArray()); } + // Restore DownloadView columns: + dlView_->restoreView(); + // Restore torrent session settings to server: qtrapids::ParamsMap_t options; options["net/downloadRate"] = settings_.value("net/downloadRate").toString(); @@ -320,7 +329,7 @@ void MainWindow::on_removeAction_clicked() try { server_.removeTorrent(hash); } catch (...) { - qDebug() << "Exception removing torrent"; + qDebug() << "Exception while removing torrent"; } } @@ -331,6 +340,22 @@ void MainWindow::on_quitAction_clicked() } +void MainWindow::on_columnsAction_clicked() +{ + ColumnSelectorDialog *dialog = new ColumnSelectorDialog(dlView_); + dialog->show(); + dialog->exec(); +// dialog->raise(); +// dialog->activateWindow(); + qDebug() << "dialog exit"; + + if (dialog->result() == QDialog::Accepted) { + qDebug() << "saved"; + dlView_->saveView(); + } +} + + void MainWindow::on_preferencesAction_clicked() { if (!preferencesDialog_) { diff --git a/src/client/MainWindow.h b/src/client/MainWindow.h index fb643eb..1c7efd3 100644 --- a/src/client/MainWindow.h +++ b/src/client/MainWindow.h @@ -80,6 +80,7 @@ private slots: void on_openAction_clicked(); void on_removeAction_clicked(); void on_quitAction_clicked(); + void on_columnsAction_clicked(); void on_preferencesAction_clicked(); void on_aboutAction_clicked(); void on_aboutQtAction_clicked(); diff --git a/src/include/qtrapids/dbus.hpp b/src/include/qtrapids/dbus.hpp index 173afbf..52462c8 100644 --- a/src/include/qtrapids/dbus.hpp +++ b/src/include/qtrapids/dbus.hpp @@ -29,7 +29,8 @@ struct TorrentState { , seeds(0) , leeches(0) , ratio(0) - , total_size(0) { } + , total_size(0) + , total_done(0){ } QString hash; QString name; @@ -42,6 +43,7 @@ struct TorrentState { uint leeches; uint ratio; qulonglong total_size; + qulonglong total_done; }; typedef QHash ParamsMap_t; @@ -58,7 +60,7 @@ static inline QDBusArgument& operator << (QDBusArgument& argument argument.beginStructure(); argument << state.hash << state.name << (uint)(state.action) << state.state << state.progress << state.down_rate << state.up_rate << state.seeds - << state.leeches << state.ratio << state.total_size; + << state.leeches << state.ratio << state.total_size << state.total_done; argument.endStructure(); return argument; } @@ -73,7 +75,7 @@ static inline QDBusArgument const& operator >> (QDBusArgument const& argument uint action; argument >> state.hash >> state.name >> action >> state.state >> state.progress >> state.down_rate >> state.up_rate >> state.seeds - >> state.leeches >> state.ratio >> state.total_size; + >> state.leeches >> state.ratio >> state.total_size >> state.total_done; state.action = (TorrentState::torrent_action)action; argument.endStructure(); return argument; diff --git a/src/include/qtrapids/format.hpp b/src/include/qtrapids/format.hpp index 2fcbc6f..1c6e3d3 100644 --- a/src/include/qtrapids/format.hpp +++ b/src/include/qtrapids/format.hpp @@ -4,7 +4,7 @@ #include #include - +#include namespace qtrapids { @@ -27,6 +27,8 @@ static char const* size_names[] = { "KB", "B" }; + +const qulonglong SECONDS_IN_DAY = 60*60*24; } static inline QString formatSize(qulonglong size) @@ -45,6 +47,46 @@ static inline QString formatSize(qulonglong size) } +inline QString formatElapsedTime(qulonglong seconds) +{ + qulonglong hours = 0, minutes = 0, secsLeft = 0; + QString dayStr, hourStr, minStr, secStr; + dayStr = hourStr = minStr = secStr = QString::number(0); + + //result.reserve(8); + + hours = seconds / 3600; + secsLeft = seconds % 3600; + minutes = secsLeft / 60; + secsLeft = secsLeft % 60; + + // If more than 24 hours, format time as days, hours. + // Otherwise hours : mins : secs + if (hours >= 24) { + dayStr = QString::number(hours / 24); + hourStr = QString::number(hours % 24); + return dayStr + 'd' + ' ' + hourStr + 'h'; + } else if (hours < 10) { + hourStr.append(QString::number(hours)); + } else { + hourStr = QString::number(hours); + } + + if (minutes < 10) { + minStr.append(QString::number(minutes)); + } else { + minStr = QString::number(minutes); + } + + if (secsLeft < 10) { + secStr.append(QString::number(secsLeft)); + } else { + secStr = QString::number(secsLeft); + } + + return hourStr + ':' + minStr + ':' + secStr; +} + } // namespace qtrapids #endif // _QTRAPIDS_FORMAT_HPP_ diff --git a/src/server/TorrentHandle.cpp b/src/server/TorrentHandle.cpp index 5cb7b72..1d09359 100644 --- a/src/server/TorrentHandle.cpp +++ b/src/server/TorrentHandle.cpp @@ -65,6 +65,11 @@ size_t TorrentHandle::getTotalSize() const return static_cast (info.total_size()); } +size_t TorrentHandle::getTotalDone() const +{ + TorrentStatus_t statusTmp = status(); + return static_cast (statusTmp.total_done); +} TorrentStatus::Id TorrentHandle::state() const { diff --git a/src/server/TorrentHandle.hpp b/src/server/TorrentHandle.hpp index 9bd716f..712b1bd 100644 --- a/src/server/TorrentHandle.hpp +++ b/src/server/TorrentHandle.hpp @@ -61,6 +61,7 @@ public: QString name() const; size_t getTotalSize() const; + size_t getTotalDone() const; TorrentStatus::Id state() const; float progress() const; float uploadRate() const; diff --git a/src/server/TorrentSession.cpp b/src/server/TorrentSession.cpp index 38140b1..09bde96 100644 --- a/src/server/TorrentSession.cpp +++ b/src/server/TorrentSession.cpp @@ -84,7 +84,9 @@ void TorrentSession::on_alert() state.up_rate = handle.uploadRate(); state.seeds = handle.numSeeds(); state.leeches = handle.numLeeches(); - + state.total_size = handle.getTotalSize(); + state.total_done = handle.getTotalDone(); + ParamsMap_t params; emit alert(state, params); } -- 1.7.9.5