- DownloadView columns can be now hidden by user preference. Settings are persistent
authorlvaatamoinen <lassi.vaatamoinen@ixonos.com>
Thu, 31 Dec 2009 08:56:54 +0000 (08:56 +0000)
committerlvaatamoinen <lassi.vaatamoinen@ixonos.com>
Thu, 31 Dec 2009 08:56:54 +0000 (08:56 +0000)
- 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

13 files changed:
dbus/com.ixonos.qtrapids.xml
src/client/CMakeLists.txt
src/client/ColumnSelectorDialog.cpp [new file with mode: 0644]
src/client/ColumnSelectorDialog.h [new file with mode: 0644]
src/client/DownloadView.cpp
src/client/DownloadView.h
src/client/MainWindow.cpp
src/client/MainWindow.h
src/include/qtrapids/dbus.hpp
src/include/qtrapids/format.hpp
src/server/TorrentHandle.cpp
src/server/TorrentHandle.hpp
src/server/TorrentSession.cpp

index 520085d..05d9bbf 100644 (file)
@@ -20,7 +20,7 @@
     </method>
 
     <signal name="alert">
-      <arg type="(ssuuuuuuuut)" name="info" direction="out"/>
+      <arg type="(ssuuuuuuuutt)" name="info" direction="out"/>
       <annotation name="com.trolltech.QtDBus.QtTypeName.In0" 
                   value="qtrapids::TorrentState"/>
       <arg type="a{ss}" name="other_info" direction="out"/>
index 5546525..dccbcee 100644 (file)
@@ -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 (file)
index 0000000..153199a
--- /dev/null
@@ -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 <QGridLayout>
+#include <QTreeWidgetItem>
+#include <QCheckBox>
+#include <QDialogButtonBox>
+#include <QAbstractButton>
+
+#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 (file)
index 0000000..d803f3a
--- /dev/null
@@ -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 <vector>
+#include <QDialog>
+#include <QSettings>
+
+class QTreeWidget;
+class QDialogButtonBox;
+class QGridLayout;
+class QTreeWidget;
+class QCheckBox;
+class QAbstractButton;
+
+/**
+   @author Lassi Väätämöinen <lassi.vaatamoinen@ixonos.com>
+   @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<QCheckBox*> checkBoxes_;
+
+       private:
+               void ApplySettings();
+       
+};
+
+#endif
index dc18f06..7416ecb 100644 (file)
@@ -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<QVariant> 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<QVariant> 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) {
index 459bde2..add63a6 100644 (file)
@@ -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);
+       
 };
 
 
index 8b89ae8..221ac60 100644 (file)
 #include <QAction>
 #include <QFileDialog>
 #include <QMessageBox>
+//#include <QTreeWidgetItem>
 #include <QApplication>
 #include <QPluginLoader>
 
 #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_) {
index fb643eb..1c7efd3 100644 (file)
@@ -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();
index 173afbf..52462c8 100644 (file)
@@ -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<QString, QString> 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;
index 2fcbc6f..1c6e3d3 100644 (file)
@@ -4,7 +4,7 @@
 #include <qtrapids/info.hpp>
 #include <QtCore/QString>
 
-
+#include <QDebug>
 
 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_
index 5cb7b72..1d09359 100644 (file)
@@ -65,6 +65,11 @@ size_t TorrentHandle::getTotalSize() const
        return static_cast<size_t> (info.total_size());
 }
 
+size_t TorrentHandle::getTotalDone() const
+{
+       TorrentStatus_t statusTmp = status();
+       return static_cast<size_t> (statusTmp.total_done);
+}
 
 TorrentStatus::Id TorrentHandle::state() const
 {
index 9bd716f..712b1bd 100644 (file)
@@ -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;
index 38140b1..09bde96 100644 (file)
@@ -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);
                }