From df37f9235ec253566e7f88017c1775d34fe1392a Mon Sep 17 00:00:00 2001 From: lvaatamoinen Date: Sun, 29 Jan 2012 14:27:46 +0000 Subject: [PATCH] Reverted invalid commit 82 git-svn-id: file:///svnroot/qtrapids/trunk@83 42ac0dd5-4c8c-4c71-bb3e-ecdfe252ffda --- CMakeLists.txt | 3 +- src/client/CMakeLists.txt | 59 +-- src/client/models/Plugin.cpp | 19 - src/client/models/Plugin.h | 18 - .../models/QDeclarativeDownloadListModel.cpp | 304 ------------ src/client/models/QDeclarativeDownloadListModel.h | 129 ----- .../models/QDeclarativeDownloadListModel_p.h | 30 -- src/client/models/qmldir | 1 - src/client/qml/MainPage.qml | 177 ------- src/client/qml/main.qml | 36 -- src/client/qml/qml.qrc | 9 - src/qml-client/CMakeLists.txt | 102 ++++ src/qml-client/ColumnSelectorDialog.cpp | 130 +++++ src/qml-client/ColumnSelectorDialog.h | 61 +++ src/qml-client/DownloadView.cpp | 244 ++++++++++ src/qml-client/DownloadView.h | 126 +++++ src/qml-client/MainWindow.cpp | 503 ++++++++++++++++++++ src/qml-client/MainWindow.h | 125 +++++ src/qml-client/PreferencesDialog.cpp | 195 ++++++++ src/qml-client/PreferencesDialog.h | 66 +++ src/qml-client/SeedView.cpp | 45 ++ src/qml-client/SeedView.h | 90 ++++ src/qml-client/main.cpp | 121 +++++ src/qml-client/models/Plugin.cpp | 19 + src/qml-client/models/Plugin.h | 18 + .../models/QDeclarativeDownloadListModel.cpp | 304 ++++++++++++ .../models/QDeclarativeDownloadListModel.h | 129 +++++ .../models/QDeclarativeDownloadListModel_p.h | 30 ++ src/qml-client/models/qmldir | 1 + src/qml-client/proxy.cpp | 26 + src/qml-client/proxy.h | 90 ++++ src/qml-client/qml/MainPage.qml | 177 +++++++ src/qml-client/qml/main.qml | 36 ++ src/qml-client/qml/qml.qrc | 9 + 34 files changed, 2667 insertions(+), 765 deletions(-) delete mode 100644 src/client/models/Plugin.cpp delete mode 100644 src/client/models/Plugin.h delete mode 100644 src/client/models/QDeclarativeDownloadListModel.cpp delete mode 100644 src/client/models/QDeclarativeDownloadListModel.h delete mode 100644 src/client/models/QDeclarativeDownloadListModel_p.h delete mode 100644 src/client/models/qmldir delete mode 100644 src/client/qml/DownloadView.qml delete mode 100644 src/client/qml/MainPage.qml delete mode 100644 src/client/qml/SeedView.qml delete mode 100644 src/client/qml/main.qml delete mode 100644 src/client/qml/qml.qrc create mode 100644 src/qml-client/CMakeLists.txt create mode 100644 src/qml-client/ColumnSelectorDialog.cpp create mode 100644 src/qml-client/ColumnSelectorDialog.h create mode 100644 src/qml-client/DownloadView.cpp create mode 100644 src/qml-client/DownloadView.h create mode 100644 src/qml-client/MainWindow.cpp create mode 100644 src/qml-client/MainWindow.h create mode 100644 src/qml-client/PreferencesDialog.cpp create mode 100644 src/qml-client/PreferencesDialog.h create mode 100644 src/qml-client/SeedView.cpp create mode 100644 src/qml-client/SeedView.h create mode 100644 src/qml-client/main.cpp create mode 100644 src/qml-client/models/Plugin.cpp create mode 100644 src/qml-client/models/Plugin.h create mode 100644 src/qml-client/models/QDeclarativeDownloadListModel.cpp create mode 100644 src/qml-client/models/QDeclarativeDownloadListModel.h create mode 100644 src/qml-client/models/QDeclarativeDownloadListModel_p.h create mode 100644 src/qml-client/models/qmldir create mode 100644 src/qml-client/proxy.cpp create mode 100644 src/qml-client/proxy.h create mode 100644 src/qml-client/qml/DownloadView.qml create mode 100644 src/qml-client/qml/MainPage.qml create mode 100644 src/qml-client/qml/SeedView.qml create mode 100644 src/qml-client/qml/main.qml create mode 100644 src/qml-client/qml/qml.qrc diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ac910a..8e9c71e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_VERBOSE_MAKEFILE ON) # Check if we are building under scratchbox and link with QtMaemo5 only in that case. # Thus, we maintain desktop build-ability also -set (SCRATCHBOX_UNAME $ENV{SBOX_UNAME_MACHINE}) +#set (SCRATCHBOX_UNAME $ENV{SBOX_UNAME_MACHINE}) if (SCRATCHBOX_UNAME) MESSAGE("Configuring for building under Scratchbox..") @@ -19,5 +19,6 @@ find_package(Qt4 REQUIRED) add_subdirectory(./dbus) add_subdirectory(./src/client) add_subdirectory(./src/server) +add_subdirectory(./src/qml-client) #add_subdirectory(./src/utest) diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 873b699..da3d8b5 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -1,12 +1,6 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) - -set(QT_USE_QTDECLARATIVE 1) - -FIND_PACKAGE(Qt4 REQUIRED) - INCLUDE(${QT_USE_FILE}) -INCLUDE_DIRECTORIES(${qtrapids_SOURCE_DIR}/src/include ${qtrapids_SOURCE_DIR}/src/plugins) +INCLUDE_DIRECTORIES(../include ../plugins) FIND_LIBRARY(BOOST_SYSTEM boost_system-mt) IF(${BOOST_SYSTEM} STREQUAL BOOST_SYSTEM-NOTFOUND) @@ -18,48 +12,32 @@ INCLUDE_DIRECTORIES( ${QT_QTTEST_INCLUDE_DIR} ${QT_QTDBUS} ${QT_QTGUI} - ${QT_QTDECLARATIVE_INCLUDE_DIR} ) SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/proxy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/proxy.h PROPERTIES GENERATED 1) SET(MOC_HEADERS - ./models/QDeclarativeDownloadListModel.h - ./models/QDeclarativeDownloadListModel_p.h -# ./DownloadView.h -# ./models/Plugin.h -# ./MainWindow.h -# ./PreferencesDialog.h -# ./proxy.h -# ./SeedView.h -# ./ColumnSelectorDialog.h + ./DownloadView.h + ./MainWindow.h + ./PreferencesDialog.h + ./proxy.h + ./SeedView.h + ./ColumnSelectorDialog.h ) SET(SRC -# ./DownloadView.cpp - ./main.cpp - ./models/QDeclarativeDownloadListModel.cpp -# ./MainWindow.cpp -# ./PreferencesDialog.cpp -# ./proxy.cpp -# ./SeedView.cpp -# ./ColumnSelectorDialog.cpp + ./DownloadView.cpp + ./main.cpp + ./MainWindow.cpp + ./PreferencesDialog.cpp + ./proxy.cpp + ./SeedView.cpp + ./ColumnSelectorDialog.cpp ) - -# Set the resource files to be used. -# Add all .qrc files here, that are needed. -SET(RCCS qml/qml.qrc) - -# generate rules for building source files from the resources -QT4_ADD_RESOURCES(RCC_SRC ${RCCS}) -# generate rules for building source files that moc generates -QT4_WRAP_CPP(QtApp_MOC_SRCS ${QtApp_MOCS}) - QT4_WRAP_CPP(SRC ${MOC_HEADERS}) -# Build the executable from these files: -ADD_EXECUTABLE(qml-client ${SRC} ${MOC_HEADERS} ${RCC_SRC}) -INSTALL(TARGETS qml-client DESTINATION bin) +ADD_EXECUTABLE(qtrapids-gui ${SRC} ${MOC_HEADERS}) +INSTALL(TARGETS qtrapids-gui DESTINATION bin) ADD_DEFINITIONS(-DQT_SHARED) @@ -76,18 +54,17 @@ if(NOT QT_QTMAEMO5_LIBRARY) endif(NOT QT_QTMAEMO5_LIBRARY) -TARGET_LINK_LIBRARIES(qml-client +TARGET_LINK_LIBRARIES(qtrapids-gui ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY} ${QT_QTDBUS_LIBRARY} ${QT_QTTEST_LIBRARY} - ${QT_QTDECLARATIVE_LIBRARY} -lboost_system-mt ) # Check if we are building under scratchbox and link with QtMaemo5 only in that case. # Thus, we maintain desktop build-ability also -#set (SCRATCHBOX_UNAME $ENV{SBOX_UNAME_MACHINE}) +set (SCRATCHBOX_UNAME $ENV{SBOX_UNAME_MACHINE}) if (SCRATCHBOX_UNAME) MESSAGE("Configuring for building under Scratchbox..") diff --git a/src/client/models/Plugin.cpp b/src/client/models/Plugin.cpp deleted file mode 100644 index a6c6165..0000000 --- a/src/client/models/Plugin.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include -#include - -// This class is needed to make DownloadListModel class available to QML: -class QmlDownloadListModelPlugin : public QDeclarativeExtensionPlugin -{ - Q_OBJECT -public: - virtual void registerTypes(const char *uri) - { - Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.downloadlistmodel")); - qmlRegisterType(uri, 1, 0, "DownloadListModel"); - } -}; - -#include "moc_Plugin.cxx" - -Q_EXPORT_PLUGIN2(downloadlistmodelplugin, QT_PREPEND_NAMESPACE(QmlDownloadListModelPlugin)); \ No newline at end of file diff --git a/src/client/models/Plugin.h b/src/client/models/Plugin.h deleted file mode 100644 index 129970c..0000000 --- a/src/client/models/Plugin.h +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include - -#include "QDeclarativeDownloadListModel.h" - -// This class is needed to make DownloadListModel class available to QML: -class QmlDownloadListModelPlugin : public QDeclarativeExtensionPlugin -{ - Q_OBJECT -public: - virtual void registerTypes(const char *uri) - { - Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.downloadlistmodel")); - qmlRegisterType(uri, 1, 0, "DownloadListModel"); - } -}; - -Q_EXPORT_PLUGIN2(downloadlistmodelplugin, QT_PREPEND_NAMESPACE(QmlDownloadListModelPlugin)); \ No newline at end of file diff --git a/src/client/models/QDeclarativeDownloadListModel.cpp b/src/client/models/QDeclarativeDownloadListModel.cpp deleted file mode 100644 index e990705..0000000 --- a/src/client/models/QDeclarativeDownloadListModel.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Ixonos Plc * - * * - * 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; version 2 of the License. * - * * - * 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 "QDeclarativeDownloadListModel.h" -#include "QDeclarativeDownloadListModel_p.h" -#include "qtrapids/format.hpp" - -namespace qtrapids -{ - -QDeclarativeDownloadListModel::QDeclarativeDownloadListModel(QObject *parent): - QAbstractListModel(parent) -{ - d = new QDeclarativeDownloadListModelPrivate; - - // These roles are the names that we use to access the model data on QML - // in the string format. So, use the value on the right-hand side of assignment operator in QML. - // The role enum value is passed from QML side to the C++ model for fetching the data. - QHash roles; - roles[DownloadRole] = "download"; - roles[SeedRole] = "seed"; - roles[HashRole] = "hash"; - roles[NameRole] = "name"; - roles[SizeRole] = "size"; - roles[StatusRole] = "status"; - roles[StateRole] = "state"; - roles[ProgressRole] = "progress"; - roles[DownRateRole] = "downRate"; - roles[UpRateRole] = "upRate"; - roles[SeedsRole] = "seeds"; - roles[LeechesRole] = "leeches"; - roles[RatioRole] = "ratio"; - roles[TotaSizeRole] = "totalSize"; - roles[TotalDoneRole] = "totalDone"; - setRoleNames(roles); -} - -QDeclarativeDownloadListModel::~QDeclarativeDownloadListModel() -{ -} - - -void -QDeclarativeDownloadListModel::updateItem(TorrentState const& info, - ParamsMap_t other_info) -{ - qDebug() << Q_FUNC_INFO << " enter"; - - DownloadItems_t::iterator p = d->items_.find(info.hash); - switch (info.action) { - case TorrentState::action_add : - if (p == d->items_.end()) { - addItem_(info, other_info); - } else { - qWarning() << "item with similar info hash marked as added"; - updateItem_(info, other_info); - } - break; - case TorrentState::action_update : - if (p != d->items_.end()) { - updateItem_(info, other_info); - } else { - qWarning() << "item does not exist in list but information update arrived"; - } - break; - case TorrentState::action_remove : - if (p != d->items_.end()) { - removeItem_(info); - } else { - qWarning() << "item removal request arrived but there is no such item"; - } - break; - default: - qWarning() << "unknown action requested: " << info.action; - break; - } -} - - - // Returns the hash of the torrent be removed. -QString QDeclarativeDownloadListModel::prepareRemoveSelected() -{ - return "DUMMY_HASH"; -} - -int QDeclarativeDownloadListModel::rowCount(const QModelIndex &parent) const -{ - return d->items_.count(); -} - -QVariant QDeclarativeDownloadListModel::data(const QModelIndex &index, int role) const -{ - - qDebug() << Q_FUNC_INFO << " enter"; - int rowIndex = index.row(); - QString hash; - TorrentState item; - - // Get the item hash corresponding to row number: - if (d->itemIndexes_.contains(rowIndex)) - hash = d->itemIndexes_[rowIndex]; - else - return QVariant(); - - // Get the torrent info for the hash: - if (d->items_.contains(hash)) - item = d->items_[hash]; - else - return QVariant(); - - switch (role) { -// case DownloadRole: -// // TODO: What to do here?? -// break; -// case SeedRole: -// // TODO: What to do here?? -// break; - case HashRole: - return QVariant(item.hash); - case NameRole: - return QVariant(item.name); -// case SizeRole: -// return QVariant(item.total_size); - case StatusRole: - return QVariant(); - case StateRole: - return QVariant(item.state); - case ProgressRole: - return QVariant(item.progress); - case DownRateRole: - return QVariant(item.down_rate); - case UpRateRole: - return QVariant(item.up_rate); - case SeedsRole: - return QVariant(item.seeds); - case LeechesRole: - return QVariant(item.leeches); - case RatioRole: - return QVariant(item.ratio); - case TotaSizeRole: - return QVariant(item.total_size); - case TotalDoneRole: - return QVariant(item.total_done); - default: - qWarning() << Q_FUNC_INFO << "Unknown role requested from model"; - return QVariant(); - } - return QVariant(); -} - -bool QDeclarativeDownloadListModel::insertRow(int row, const QModelIndex &parent) -{ - qDebug() << "QDeclarativeDownloadListModel::insertRow()"; - return false; -} - -bool QDeclarativeDownloadListModel::setData(const QModelIndex &index, const QVariant &value, int role) -{ - qDebug() << "QDeclarativeDownloadListModel::setData()"; - return false; -} - - -void QDeclarativeDownloadListModel::classBegin() -{ - qDebug() << "QDeclarativeDownloadListModel::classBegin()"; -} - -void QDeclarativeDownloadListModel::componentComplete() -{ - qDebug() << "QDeclarativeDownloadListModel::componentComplete()"; -} - - -void QDeclarativeDownloadListModel::removeItem_(TorrentState const& info) -{ - qDebug() << Q_FUNC_INFO << " enter"; - QString hash = info.hash; - - // TODO: Emit rows remove start - int removed = d->items_.remove(hash); - // TODO: Edit rows insert end - if (!removed) - qDebug() << "Inconsistent download view state on item removal"; - - /* - int index = indexOfTopLevelItem(item); - if (index >= 0) { - takeTopLevelItem(index); - } - */ -} - -void QDeclarativeDownloadListModel::addItem_(TorrentState const& info, - ParamsMap_t) -{ - qDebug() << Q_FUNC_INFO << " enter"; -/* - DownloadViewItem *item = new DownloadViewItem - ( info.hash, - QStringList() - << info.name - << formatSize(info.total_size) - << GetStatusString((TorrentStatus::Id)info.state) - << formatProgress(info.progress) - << formatSize(info.down_rate) - << formatSize(info.up_rate) - << QString::number(info.seeds) + "/" + QString::number(info.leeches) - << QString::number(info.ratio) - << "ETA" ); - - QBrush brushTmp(GetStatusColor((TorrentStatus::Id)info.state)); - item->setForeground(2, brushTmp); - - addTopLevelItem(item); - */ - - int itemsCount = d->items_.count(); - beginInsertRows(QModelIndex(), itemsCount, itemsCount+1); - d->items_[info.hash] = info; - d->itemIndexes_[itemsCount+1] = info.hash; - endInsertRows(); -} - - -void QDeclarativeDownloadListModel::updateItem_(TorrentState const& info, ParamsMap_t) -{ - qDebug() << Q_FUNC_INFO << " enter"; - /* - item->setData(2, Qt::DisplayRole, - QVariant(GetStatusString((TorrentStatus::Id)info.state))); - item->setData(3, Qt::DisplayRole, - QVariant(formatProgress(info.progress))); - item->setData(4, Qt::DisplayRole, - QVariant(formatSize(info.down_rate))); - item->setData(5, Qt::DisplayRole, - 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"); - } -*/ - // TODO: Update items data & Emit data changed. - -/* - // Set color for status text - QBrush brushTmp(GetStatusColor((TorrentStatus::Id)info.state)); - item->setForeground(2, brushTmp); - */ -} - - - -QString QDeclarativeDownloadListModel::GetStatusString(TorrentStatus::Id status) -{ - qDebug() << Q_FUNC_INFO << " enter"; - switch (status) { - case TorrentStatus::QUEUED_FOR_CHECKING : - return tr("Queued"); - case TorrentStatus::CHECKING_FILES : - return tr("Checking"); - case TorrentStatus::DOWNLOADING_METADATA : - return tr("DL meta"); - case TorrentStatus::DOWNLOADING : - return tr("Downloading"); - case TorrentStatus::FINISHED : - return tr("Finished"); - case TorrentStatus::SEEDING : - return tr("Seeding"); - case TorrentStatus::ALLOCATING : - return tr("Allocating"); - case TorrentStatus::CHECKING_RESUME_DATA : - return tr("Checking resume"); - default: - return tr("N/A"); - } -} - -} // namespace qtrapids diff --git a/src/client/models/QDeclarativeDownloadListModel.h b/src/client/models/QDeclarativeDownloadListModel.h deleted file mode 100644 index ee9cadd..0000000 --- a/src/client/models/QDeclarativeDownloadListModel.h +++ /dev/null @@ -1,129 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Ixonos Plc * - * * - * 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; version 2 of the License. * - * * - * 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 QDECLARATIVEDOWNLOADLISTMODEL_H -#define QDECLARATIVEDOWNLOADLISTMODEL_H - - -#include -#include -#include -#include - -#include "qtrapids/dbus.hpp" -#include "qtrapids/info.hpp" - -//#include "../DownloadView.h" - -QT_MODULE(Declarative); - -namespace qtrapids -{ - -typedef QHash DownloadItems_t; -typedef QMap ItemIndex_t; - -class QDeclarativeContext; -class QDeclarativeDownloadListModelPrivate; - -class QDeclarativeDownloadListModel : - public QAbstractListModel, public QDeclarativeParserStatus -{ - Q_OBJECT - Q_INTERFACES(QDeclarativeParserStatus); - - /* - Q_PROPERTY(QString hash READ hash); - Q_PROPERTY(QString name READ name WRITE setName); - Q_PROPERTY(QString size READ size); - Q_PROPERTY(QString status READ status); - Q_PROPERTY(uint state READ state); - Q_PROPERTY(uint progress READ progress); - Q_PROPERTY(uint downRate READ downRate); - Q_PROPERTY(uint upRate READ upRate); - Q_PROPERTY(uint seeds READ seeds); - Q_PROPERTY(uint leeches READ leeches); - Q_PROPERTY(qulonglong ratio READ ratio); - Q_PROPERTY(qulonglong totaSize READ totalDone); - Q_PROPERTY(qulonglong totalDone READ totalDone); -*/ - -public: - QDeclarativeDownloadListModel(QObject *parent = 0); - virtual ~QDeclarativeDownloadListModel(); - - // TODO: Learn to use roles.. - enum Roles { - DownloadRole = Qt::UserRole + 1, - SeedRole, - HashRole, - NameRole, - SizeRole, - StatusRole, - StateRole, - ProgressRole, - DownRateRole, - UpRateRole, - SeedsRole, - LeechesRole, - RatioRole, - TotaSizeRole, - TotalDoneRole - }; - - // Updates the torrent status in the model. - void updateItem(TorrentState const& info, ParamsMap_t other_info); - // Returns the hash of the torrent be removed. - QString prepareRemoveSelected(); - - // -- QAbstractListModel - virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; - virtual QVariant data(const QModelIndex &index, int role) const; - virtual bool insertRow(int row, const QModelIndex &parent); - virtual bool setData (const QModelIndex & index, const QVariant &value, int role = Qt::EditRole); - // -- End QAbstractListModel - - // -- Overrides from QDeclarativeParserStatus - virtual void classBegin(); - virtual void componentComplete(); - // -- End QDeclarativeParserStatus - -Q_SIGNALS: - void downloadItemChanged(QString hash); - -// Private functions. -private: - Q_DISABLE_COPY(QDeclarativeDownloadListModel) - QDeclarativeDownloadListModelPrivate *d; - - void addItem_(TorrentState const& info, ParamsMap_t other_info); - void updateItem_(TorrentState const& info, ParamsMap_t other_info); - void removeItem_(TorrentState const& info); - QString GetStatusString(TorrentStatus::Id status); -private: - -}; - - -} // namespace qtrapids - -// We need to declare the type -QML_DECLARE_TYPE(qtrapids::QDeclarativeDownloadListModel); - - - -#endif diff --git a/src/client/models/QDeclarativeDownloadListModel_p.h b/src/client/models/QDeclarativeDownloadListModel_p.h deleted file mode 100644 index 6c4b699..0000000 --- a/src/client/models/QDeclarativeDownloadListModel_p.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef QDECLARATIVEDOWNLOADLISTMODELPRIVATE_H -#define QDECLARATIVEDOWNLOADLISTMODELPRIVATE_H - -#include - -#include "QDeclarativeDownloadListModel.h" // TODO: For DownloadItems_t, move that to common place.. - -namespace qtrapids -{ - -class QDeclarativeDownloadListModelPrivate : QObject -{ - Q_OBJECT -public: - QDeclarativeDownloadListModelPrivate() - { - } - - DownloadItems_t items_; - ItemIndex_t itemIndexes_; - //QModelIndex downloadIndex_; - -signals: - void itemAdded(QString hash); - void itemRemoved(QString hash); - -}; -} // namespace qtrapids - -#endif diff --git a/src/client/models/qmldir b/src/client/models/qmldir deleted file mode 100644 index 9e05264..0000000 --- a/src/client/models/qmldir +++ /dev/null @@ -1 +0,0 @@ -plugin qmlfolderlistmodelplugin \ No newline at end of file diff --git a/src/client/qml/DownloadView.qml b/src/client/qml/DownloadView.qml deleted file mode 100644 index e69de29..0000000 diff --git a/src/client/qml/MainPage.qml b/src/client/qml/MainPage.qml deleted file mode 100644 index a189bab..0000000 --- a/src/client/qml/MainPage.qml +++ /dev/null @@ -1,177 +0,0 @@ -import QtQuick 1.1 -import Qt.labs.components 1.0 -import com.nokia.meego 1.0 -import com.meego 1.0 -import com.nokia.extras 1.0 - -import QtRapids 1.0 - -Page { - id: tabbarPage - - property bool busy: Boolean(tabGroup.currentTab.busy) - anchors.margins: rootWindow.pageMargin - - tools: ToolBarLayout { - ToolIcon { iconId: "toolbar-back"; onClicked: pageStack.pop(); } - ButtonRow { - platformStyle: TabButtonStyle { } - TabButton { - text: "Downloads" - tab: downloads - } - TabButton { - text: "Seeds" - tab: seeds - } - } - ToolIcon { iconId: "toolbar-view-menu"; onClicked: (myMenu.status == DialogStatus.Closed) ? myMenu.open() : myMenu.close() } - } -// Text { -// text: "Hello World!" -// font.family: "Helvetica" -// font.pointSize: 24 -// color: "red" -// anchors.fill: parent -// } - - ListView { - width: 200; height: 400 -/* - DownloadListModel { - id: downloadModel - // TODO: Does not work like this. Need properties to set from QML? - // Try setting test data from C++ side and view here.. - /* - ListElement { - Hash: "QMLHASH1" - Size: "Size1" - Status: "DONE1" - } - ListElement { - Hash: "QMLHASH2" - Size: "Size2" - Status: "DONE2" - } - ListElement { - Hash: "QMLHASH3" - Size: "Size3" - Status: "DONE3" - } - } -*/ - Component { - id: downloadDelegate - Item { - height: 40 - width: parent.width - Text { - id: hashText - text: hash - } - Text { - id: nameText - anchors.leftMargin: 10 - anchors.left: hashText.right - text: name - } - Text { - id: seedsText - anchors.leftMargin: 10 - anchors.left: nameText.right - text: seeds - } - Text { - id: leechesText - anchors.leftMargin: 10 - anchors.left: seedsText.right - text: leeches - } - } - } - - // downloadModel is from rootContext, set in main.cpp - model: downloadModel - delegate: downloadDelegate - } - - /* - ListModel { - id: pagesModel - ListElement { - page: "CountBubble.qml" - title: "CountBubble" - subtitle: "Indicates current count" - } - ListElement { - page: "NetPromoterScore.qml" - title: "NetPromoterScore" - subtitle: "Shows net promotion query page" - } - ListElement { - page: "PageIndicator.qml" - title: "PageIndicator" - subtitle: "Indicates total & current pages" - } - ListElement { - page: "RatingIndicator.qml" - title: "RatingIndicator" - subtitle: "Indicates ratings" - } - ListElement { - page: "ListDelegates.qml" - title: "List Delegates" - subtitle: "Various List Delegates" - } - ListElement { - page: "MoreIndicator.qml" - title: "MoreIndicator" - subtitle: "Indicates that there are more contents" - } - ListElement { - page: "StyledButtons.qml" - title: "StyledButtons" - subtitle: "Buttons with different styles" - } - } - ListView { - id: listview - anchors.fill: parent - model: pagesModel - - delegate: ListDelegate { - Image { - source: "image://theme/icon-m-common-drilldown-arrow" + (theme.inverted ? "-inverse" : "") - anchors.right: parent.right; - anchors.verticalCenter: parent.verticalCenter - } - - subtitleColor: "#cc6633" - onClicked: { openFile(model.page); } - } - } -*/ - TabGroup { - id: tabGroup - - currentTab: downloads - - PageStack { - id: downloads - } - PageStack { - id: seeds - } - Page { - id: tab3 - Column { - spacing: 10 - - Text { - text: "This is a single page" - } - } - } - } - -} \ No newline at end of file diff --git a/src/client/qml/SeedView.qml b/src/client/qml/SeedView.qml deleted file mode 100644 index e69de29..0000000 diff --git a/src/client/qml/main.qml b/src/client/qml/main.qml deleted file mode 100644 index 67383aa..0000000 --- a/src/client/qml/main.qml +++ /dev/null @@ -1,36 +0,0 @@ - -import QtQuick 1.1 -import com.meego 1.0 - -PageStackWindow { - id: rootWindow - property int pageMargin: 16 - - platformStyle: defaultStyle; - - PageStackWindowStyle { id: defaultStyle } - PageStackWindowStyle { id: customStyle; background: "image://theme/meegotouch-wallpaper-portrait"} - - // ListPage is what we see when the app starts, it links to the component specific pages - initialPage: MainPage { } - - // These tools are shared by most sub-pages by assigning the id to a page's tools property - ToolBarLayout { - id: commonTools - visible: false - ToolIcon { iconId: "toolbar-back"; onClicked: { myMenu.close(); pageStack.pop(); } } - ToolIcon { iconId: "toolbar-view-menu"; onClicked: (myMenu.status == DialogStatus.Closed) ? myMenu.open() : myMenu.close() } - } - - Menu { - id: myMenu - visualParent: pageStack - MenuLayout { - MenuItem {id: b1; text: "Landscape"; onClicked: screen.allowedOrientations = Screen.Landscape} - MenuItem {id: b2; text: "Portrait"; onClicked: screen.allowedOrientations = Screen.Portrait} - MenuItem {id: b3; text: "Item 3"; onClicked: myMenu.accept()} - MenuItem {id: b4; text: "Item 4"; onClicked: myMenu.accept()} - } - } -} - diff --git a/src/client/qml/qml.qrc b/src/client/qml/qml.qrc deleted file mode 100644 index 955eecb..0000000 --- a/src/client/qml/qml.qrc +++ /dev/null @@ -1,9 +0,0 @@ - - - - - main.qml - MainPage.qml - - - \ No newline at end of file diff --git a/src/qml-client/CMakeLists.txt b/src/qml-client/CMakeLists.txt new file mode 100644 index 0000000..873b699 --- /dev/null +++ b/src/qml-client/CMakeLists.txt @@ -0,0 +1,102 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +set(QT_USE_QTDECLARATIVE 1) + +FIND_PACKAGE(Qt4 REQUIRED) + +INCLUDE(${QT_USE_FILE}) + +INCLUDE_DIRECTORIES(${qtrapids_SOURCE_DIR}/src/include ${qtrapids_SOURCE_DIR}/src/plugins) + +FIND_LIBRARY(BOOST_SYSTEM boost_system-mt) +IF(${BOOST_SYSTEM} STREQUAL BOOST_SYSTEM-NOTFOUND) + MESSAGE(SEND_ERROR ${BOOST_SYSTEM}) +ENDIF(${BOOST_SYSTEM} STREQUAL BOOST_SYSTEM-NOTFOUND) + +INCLUDE_DIRECTORIES( + ${QT_INCLUDE_DIR} + ${QT_QTTEST_INCLUDE_DIR} + ${QT_QTDBUS} + ${QT_QTGUI} + ${QT_QTDECLARATIVE_INCLUDE_DIR} +) + +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/proxy.cpp ${CMAKE_CURRENT_SOURCE_DIR}/proxy.h PROPERTIES GENERATED 1) + +SET(MOC_HEADERS + ./models/QDeclarativeDownloadListModel.h + ./models/QDeclarativeDownloadListModel_p.h +# ./DownloadView.h +# ./models/Plugin.h +# ./MainWindow.h +# ./PreferencesDialog.h +# ./proxy.h +# ./SeedView.h +# ./ColumnSelectorDialog.h +) + +SET(SRC +# ./DownloadView.cpp + ./main.cpp + ./models/QDeclarativeDownloadListModel.cpp +# ./MainWindow.cpp +# ./PreferencesDialog.cpp +# ./proxy.cpp +# ./SeedView.cpp +# ./ColumnSelectorDialog.cpp +) + + +# Set the resource files to be used. +# Add all .qrc files here, that are needed. +SET(RCCS qml/qml.qrc) + +# generate rules for building source files from the resources +QT4_ADD_RESOURCES(RCC_SRC ${RCCS}) +# generate rules for building source files that moc generates +QT4_WRAP_CPP(QtApp_MOC_SRCS ${QtApp_MOCS}) + +QT4_WRAP_CPP(SRC ${MOC_HEADERS}) +# Build the executable from these files: +ADD_EXECUTABLE(qml-client ${SRC} ${MOC_HEADERS} ${RCC_SRC}) +INSTALL(TARGETS qml-client DESTINATION bin) + +ADD_DEFINITIONS(-DQT_SHARED) + +set(QT_QTMAEMO5_LIBRARY -lQtMaemo5 -L${QT_LIBRARY_DIR}) + +# QT_QTMAEMO5_* variables are not defined by CMake +if(NOT QT_QTMAEMO5_INCLUDE_DIR) + FIND_PATH(QT_QTMAEMO5_INCLUDE_DIR QtMaemo5 + PATHS ${QT_HEADERS_DIR}/QtMaemo5 NO_DEFAULT_PATH) +endif(NOT QT_QTMAEMO5_INCLUDE_DIR) +if(NOT QT_QTMAEMO5_LIBRARY) + FIND_LIBRARY(QT_QTMAEMO5_LIBRARY QtMaemo5 + PATHS ${QT_LIBRARY_DIR} NO_DEFAULT_PATH) +endif(NOT QT_QTMAEMO5_LIBRARY) + + +TARGET_LINK_LIBRARIES(qml-client + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${QT_QTDBUS_LIBRARY} + ${QT_QTTEST_LIBRARY} + ${QT_QTDECLARATIVE_LIBRARY} + -lboost_system-mt +) + +# Check if we are building under scratchbox and link with QtMaemo5 only in that case. +# Thus, we maintain desktop build-ability also +#set (SCRATCHBOX_UNAME $ENV{SBOX_UNAME_MACHINE}) + +if (SCRATCHBOX_UNAME) + MESSAGE("Configuring for building under Scratchbox..") + TARGET_LINK_LIBRARIES(qtrapids-gui ${QT_QTMAEMO5_LIBRARY}) +endif (SCRATCHBOX_UNAME) + +#MESSAGE(${CMAKE_HOST_SYSTEM_PROCESSOR}) +#CHECK_LIBRARY_EXISTS(QT_QTMAEMO5_LIBRARY) + + + +ADD_DEPENDENCIES(qtrapids-gui dbusapi) diff --git a/src/qml-client/ColumnSelectorDialog.cpp b/src/qml-client/ColumnSelectorDialog.cpp new file mode 100644 index 0000000..4fe9c30 --- /dev/null +++ b/src/qml-client/ColumnSelectorDialog.cpp @@ -0,0 +1,130 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 +#include + +#ifdef Q_WS_MAEMO_5 + #include +#endif + +#include "ColumnSelectorDialog.h" + + +ColumnSelectorDialog::ColumnSelectorDialog(QTreeWidget *treewidget, QWidget* parent, Qt::WindowFlags f) : + QDialog(parent, f), // Superclass construct + dialogButtons_(NULL), + grid_(NULL), + treeWidget_(treewidget), + scroller_(NULL), + checkBoxes_() +{ + QScrollArea *scrollArea = new QScrollArea(this); + +#ifdef Q_WS_MAEMO_5 + /// @todo Kineticscrolling (property "FingerScrollable" does not work in Qt 4.6, only in 4.5) + scroller_ = scrollArea->property("kineticScroller").value(); + + if (!scroller_) + qFatal("This example only works with QMaemo5Style as the default style for all QAbstractScrollAreas"); +#endif + + scrollArea->setWidgetResizable(true); + //scrollArea->setProperty("FingerScrollable", false); + QBoxLayout *verticalBox = new QBoxLayout(QBoxLayout::TopToBottom); + grid_ = new QGridLayout; + QCheckBox *cbox = NULL; + + + + // Create scrollable checkbox dialog to allow proper viewing on Maemo: + verticalBox->addWidget(scrollArea); + // A "temporary" widget for containing QScrollArea stuff + QWidget* scrollAreaWidgetContents = new QWidget(); + scrollAreaWidgetContents->setLayout(grid_); + scrollArea->setWidget(scrollAreaWidgetContents); + setLayout(verticalBox); + + 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/qml-client/ColumnSelectorDialog.h b/src/qml-client/ColumnSelectorDialog.h new file mode 100644 index 0000000..5077aba --- /dev/null +++ b/src/qml-client/ColumnSelectorDialog.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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; +class QAbstractKineticScroller; + + +/** + @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_; + QAbstractKineticScroller *scroller_; + std::vector checkBoxes_; + + private: + void ApplySettings(); + +}; + +#endif diff --git a/src/qml-client/DownloadView.cpp b/src/qml-client/DownloadView.cpp new file mode 100644 index 0000000..cf04e51 --- /dev/null +++ b/src/qml-client/DownloadView.cpp @@ -0,0 +1,244 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 "DownloadView.h" + +#include +#include +#include + +namespace qtrapids +{ + +DownloadView::DownloadView(QWidget* parent) : + QTreeWidget(parent), + items_(), + settings_() +{ + setRootIsDecorated(false); // Hide branch lines, making one-level treeview (similar to list) + setHeaderItem(DownloadViewItem::getHeaderItem()); + + connect(this, SIGNAL(itemPressed(QTreeWidgetItem*, int)), + this, SLOT(on_itemClicked(QTreeWidgetItem*, int))); + +} + + +DownloadView::~DownloadView() +{ +} + +void DownloadView::updateItem(TorrentState const& info, ParamsMap_t other_info) +{ + DownloadItems_t::iterator p = items_.find(info.hash); + switch (info.action) { + case TorrentState::action_add : + if (p == items_.end()) { + addItem_(info, other_info); + } else { + qWarning() << "item with similar info hash marked as added"; + updateItem_(p.value(), info, other_info); + } + break; + case TorrentState::action_update : + if (p != items_.end()) { + updateItem_(p.value(), info, other_info); + } else { + qWarning() << "item does not exist in list but information update arrived"; + } + break; + case TorrentState::action_remove : + if (p != items_.end()) { + removeItem_(p.value(), info); + } else { + qWarning() << "item removal request arrived but there is no such item"; + } + break; + default: + qWarning() << "unknown action requested: " << info.action; + break; + } +} + +void DownloadView::removeItem_(DownloadViewItem *item, TorrentState const& info) +{ + QString hash = item->getHash(); + + int removed = items_.remove(hash); + if (!removed) + qDebug() << "Inconsistent download view state on item removal"; + + int index = indexOfTopLevelItem(item); + if (index >= 0) { + takeTopLevelItem(index); + } +} + +void DownloadView::addItem_(TorrentState const& info, ParamsMap_t) +{ + DownloadViewItem *item = new DownloadViewItem + ( info.hash, + QStringList() + << info.name + << formatSize(info.total_size) + << GetStatusString((TorrentStatus::Id)info.state) + << formatProgress(info.progress) + << formatSize(info.down_rate) + << formatSize(info.up_rate) + << QString::number(info.seeds) + "/" + QString::number(info.leeches) + << QString::number(info.ratio) + << "ETA" ); + + QBrush brushTmp(GetStatusColor((TorrentStatus::Id)info.state)); + item->setForeground(2, brushTmp); + + addTopLevelItem(item); + items_[info.hash] = item; +} + + +void DownloadView::updateItem_(DownloadViewItem *item + , TorrentState const& info, ParamsMap_t) +{ + item->setData(2, Qt::DisplayRole, + QVariant(GetStatusString((TorrentStatus::Id)info.state))); + item->setData(3, Qt::DisplayRole, + QVariant(formatProgress(info.progress))); + item->setData(4, Qt::DisplayRole, + QVariant(formatSize(info.down_rate))); + item->setData(5, Qt::DisplayRole, + 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); +} + + +QString DownloadView::prepareRemoveSelected() +{ + qDebug() << "DownloadView::removeSelected() " << topLevelItemCount() ; + + DownloadViewItem *item = dynamic_cast (currentItem()); + QString hash = item->getHash(); + + item->setDisabled(true); + + qDebug() << "DownloadView::removeSelected() " << topLevelItemCount() ; + + return hash; +} + + +void DownloadView::on_itemClicked(QTreeWidgetItem * , int) +{ + /* + qDebug() << "DownloadView::on_itemClicked(()" << item << "," << column; + qDebug() << "current item" << currentItem(); + + if (item == currentItem() && item->isSelected()) { + item->setSelected(false); + } + */ +} + + +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) { + case TorrentStatus::QUEUED_FOR_CHECKING : + return tr("Queued"); + case TorrentStatus::CHECKING_FILES : + return tr("Checking"); + case TorrentStatus::DOWNLOADING_METADATA : + return tr("DL meta"); + case TorrentStatus::DOWNLOADING : + return tr("Downloading"); + case TorrentStatus::FINISHED : + return tr("Finished"); + case TorrentStatus::SEEDING : + return tr("Seeding"); + case TorrentStatus::ALLOCATING : + return tr("Allocating"); + case TorrentStatus::CHECKING_RESUME_DATA : + return tr("Checking resume"); + default: + return tr("N/A"); + } +} + + +QColor DownloadView::GetStatusColor(TorrentStatus::Id status) +{ + QColor green(40,205,40); + QColor yellow(255,174,0); + + switch (status) { + case TorrentStatus::QUEUED_FOR_CHECKING : + case TorrentStatus::CHECKING_FILES : + case TorrentStatus::DOWNLOADING_METADATA : + case TorrentStatus::ALLOCATING : + case TorrentStatus::CHECKING_RESUME_DATA: + return yellow; + case TorrentStatus::DOWNLOADING : + case TorrentStatus::FINISHED : + case TorrentStatus::SEEDING : + return green; + default: + return QColor(); + } +} + +} // namespace qtrapids diff --git a/src/qml-client/DownloadView.h b/src/qml-client/DownloadView.h new file mode 100644 index 0000000..4bac449 --- /dev/null +++ b/src/qml-client/DownloadView.h @@ -0,0 +1,126 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 DOWNLOADVIEW_H +#define DOWNLOADVIEW_H + +#include +#include +#include + +#include + + +namespace qtrapids +{ + +class DownloadViewItem; + +typedef QHash DownloadItems_t; + +/** + @class DownloadView + @brief A view showing all downloaded torrents + @author Lassi Väätämöinen +*/ +class DownloadView : public QTreeWidget +{ + Q_OBJECT + +public: + DownloadView(QWidget* parent); + + ~DownloadView(); + + 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); + + + static QString GetStatusString(TorrentStatus::Id status); + static QColor GetStatusColor(TorrentStatus::Id status); + +}; + + +/** + @class DownloadViewItem + @brief Represents one item row of DownloadView +*/ +class DownloadViewItem : public QTreeWidgetItem +{ + +public: + DownloadViewItem(QTreeWidget* parent, int type) : + QTreeWidgetItem(parent, type = QTreeWidgetItem::UserType) {}; + + DownloadViewItem(QString hash, const QStringList& strings, + int type = QTreeWidgetItem::UserType) : + QTreeWidgetItem (strings, type = Type), + hash_(hash) {} + + + /// @return An item comprising of string list, suitable for QTableView + /// header. + static DownloadViewItem *getHeaderItem() { + DownloadViewItem *item + = new DownloadViewItem("", QStringList() + << "Name" + << "Size" << "Status" + << "Progress" << "DL speed" + << "UL speed" << "Seeds/Leechers" + << "Ratio" << "ETA"); + + return item; + } + + /// @todo QTorrentHandle as one hidden column + + QString getHash() const { + return hash_; + } + +private: + QString hash_; +}; + +} // namespace qtrapids + +#endif // DOWNLOADVIEW_H + diff --git a/src/qml-client/MainWindow.cpp b/src/qml-client/MainWindow.cpp new file mode 100644 index 0000000..551197a --- /dev/null +++ b/src/qml-client/MainWindow.cpp @@ -0,0 +1,503 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 +#include +//#include +#include +#include + +#include "DownloadView.h" +#include "SeedView.h" +#include "PreferencesDialog.h" +#include "ColumnSelectorDialog.h" + +#include "MainWindow.h" + +namespace qtrapids +{ + +const QString ABOUT_TEXT += QString(QObject::trUtf8("QtRapids, a simple BitTorrent client based on" + "\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@gmail.com" + "\n\nIxonos Plc, Finland\n")); + +const QString PLUGINS_DIR = "plugins"; + +// Consturctor +MainWindow::MainWindow() : + QMainWindow(), // Superclass + tabWidget_(NULL), + dlView_(NULL), + seedView_(NULL), + searchWidget_(NULL), + startDaemonAction_(NULL), + stopDaemonAction_(NULL), + preferencesDialog_(NULL), + settings_(QCoreApplication::organizationName() + , QCoreApplication::applicationName()), + pluginDirs_(), + server_(QtRapidsServer::staticInterfaceName() + , "/qtrapids", QDBusConnection::sessionBus()) + // torrentHandles_(), +{ + + setWindowTitle("QtRapids"); + + // MENUBAR + QMenuBar *menuBar = new QMenuBar(); + QMenu *tempMenu = NULL; + + tempMenu = menuBar->addMenu(tr("&File")); + QAction *openAction = tempMenu->addAction(tr("&Open")); + QAction *removeAction = tempMenu->addAction(tr("&Remove")); + removeAction->setEnabled(false); + + startDaemonAction_ = tempMenu->addAction(tr("S&tart daemon")); + stopDaemonAction_ = tempMenu->addAction(tr("Sto&p daemon")); + startDaemonAction_->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")); + + tempMenu = menuBar->addMenu(tr("&Help")); + QAction *aboutAction = tempMenu->addAction(tr("&About")); + QAction *aboutQtAction = tempMenu->addAction(tr("About &Qt")); + + setMenuBar(menuBar); + connect(openAction, SIGNAL(triggered()), this, SLOT(on_openAction_clicked())); + 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(startDaemonAction_, SIGNAL(triggered()), this, SLOT(on_startDaemonAction_clicked())); + connect(stopDaemonAction_, SIGNAL(triggered()), this, SLOT(on_stopDaemonAction_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())); + + // TABWIDGET (central widget) + tabWidget_ = new QTabWidget(); + tabWidget_->setTabsClosable(true); + + /// @todo Exception handling + dlView_ = new DownloadView(this); + //seedView_ = new SeedView(this); + tabWidget_->addTab(dlView_, tr("Downloads")); + //tabWidget_->addTab(seedView_, tr("Seeds")); + connect(dlView_, SIGNAL(itemSelectionChanged()), this, + SLOT(on_downloadItemSelectionChanged())); + + //connect(seedView_, SIGNAL(itemSelectionChanged()), this, + // SLOT(on_seedItemSelectionChanged())); + + // Tab widget as central widget. + setCentralWidget(tabWidget_); + + // TOOLBAR + QToolBar *toolBar = new QToolBar(); + toolBar->addAction(tr("Open")); + removeAction = toolBar->addAction(tr("Remove")); + removeAction->setEnabled(false); + addToolBar(Qt::BottomToolBarArea, toolBar); + + connect(this, SIGNAL(itemSelected(bool)), removeAction, + SLOT(setEnabled(bool))); + connect(toolBar, SIGNAL(actionTriggered(QAction*)), this, + SLOT(handleToolBarAction(QAction*))); + connect (tabWidget_, SIGNAL(tabCloseRequested(int)), this, SLOT(on_tabWidget_tabCloseRequested(int))); + + connect(&server_, SIGNAL(alert(qtrapids::TorrentState, qtrapids::ParamsMap_t)), + this, SLOT(on_alert(qtrapids::TorrentState, qtrapids::ParamsMap_t))); + + connect(&server_, SIGNAL(sessionTerminated()), this, SLOT(on_serverTerminated())); + +// connect(&btSession_, SIGNAL(alert(std::auto_ptr)), +// this, SLOT(on_alert(std::auto_ptr))); + + + LoadPlugins(); + +} + + +MainWindow::~MainWindow() +{ + settings_.setValue("geometry", saveGeometry()); +} + +// ===================== Implements PluginInterface ========================= +/// @todo add PluginInterface parameter to request plugin name +bool MainWindow::setGui(QWidget* widget, PluginWidgetType type, qtrapids::PluginInterface* plugin) +{ +#ifdef QTRAPIDS_DEBUG + qDebug() << "MainWindow::setGui():" << dlView_->currentItem(); +#endif + + if (plugin && plugin->identifier() == "SearchPlugin") { + searchWidget_ = widget; + } else { + return false; + } + + tabWidget_->addTab(widget, tr("Search")); + return true; +} + +/// @todo Add PluginInterface parameter to check which plugin gives the widget, to handle appropriately +void MainWindow::addPluginWidget(QWidget* widget, PluginWidgetType type) +{ +#ifdef QTRAPIDS_DEBUG + qDebug() << "MainWindow::addPluginWidget():" << dlView_->currentItem(); +#endif + + if (type == qtrapids::PluginHostInterface::TAB_PAGE) { + int index = tabWidget_->addTab(widget, tr("Results")); + tabWidget_->setCurrentIndex(index); + //layout_->addWidget(widget); + } +} +void MainWindow::addToolbar(QWidget* widget, PluginWidgetType type) +{ +} + +void MainWindow::addToolItem(QWidget* widget, PluginWidgetType type) +{ +} + +void MainWindow::addMenu(QWidget* widget, PluginWidgetType type) +{ +} + +void MainWindow::addMenuItem(QWidget* widget, PluginWidgetType type) +{ +} + +bool MainWindow::eventRequest(QVariant param, PluginRequest req) +{ + if (req == qtrapids::PluginHostInterface::OPEN_FILE) { + QString sourceFile = param.toString(); + + // Get the source files name from the full path: + QFileInfo fInfo(sourceFile); + QString targetFile = fInfo.fileName(); + targetFile = settings_.value("download/directory").toString() + "/" + targetFile; + + // Copy temoporary file to Downloads directory... + if (!QFile::copy(sourceFile, targetFile)) { + qDebug() << "File copying failed"; + return false; + } else { + // If copying was successful, remove the original temporary file. + QFile::remove(sourceFile); + } + + /// @todo Torrent bencoding validity should be checked before starting(?) + // ...and start the torrent: + on_torrentFileSelected(targetFile); + + } else if (req == qtrapids::PluginHostInterface::READ_BUFFER) { + // Create torrent information from char* buffer and start. + StartTorrentFromBufferData(param.toByteArray().constData(), param.toByteArray().size()); + } + + return true; +} + + +//=========================== PRIVATE ================================ + +void MainWindow::LoadPlugins() +{ + // Get plugin directories from + QStringList pluginDirsTmp = settings_.value("plugins/path").toStringList(); + QStringList nameFilters("*.so"); + + /// @todo enable "application directory" for plugin search in development/debug mode only. In release version + /// search plugins directory under $HOME/.qtrapids or system library paths + pluginDirsTmp << qApp->applicationDirPath(); + pluginDirsTmp.removeDuplicates(); + + foreach (QString dir, pluginDirsTmp) { + pluginDirs_.append(QDir(dir)); + } + + foreach (QDir dir, pluginDirs_) { + + if (dir.cd(PLUGINS_DIR)) { + + foreach (QString fileName, dir.entryList(nameFilters, QDir::Files)) { + QPluginLoader pluginLoader(dir.absoluteFilePath(fileName)); + + // If plugin not loaded from another directory, then load + if (!pluginFileNames_.contains(fileName) && QLibrary::isLibrary(fileName)) { + + if (pluginLoader.load()) { + qDebug() << "Plugin loaded: " << fileName; + } else { + qWarning() << "Plugin load failed: " << pluginLoader.errorString(); + } + + QObject *baseInstance = pluginLoader.instance(); + if (!baseInstance) { + qDebug() << "Base instance = NULL."; + } + + qtrapids::PluginInterface *plugin = qobject_cast(baseInstance); + + if (!plugin) { + qDebug() << "Cast failed."; + } else { + qtrapids::PluginInterface::Info info; + info.directory = dir.path(); + qDebug() << dir.path(); + plugin->initialize(this, info); + pluginFileNames_ += fileName; + } + } else { + qWarning() << "Plugin " + << fileName + << " already loaded from another directory, or not a valid library file"; + } + } + + } else { + qWarning() << PLUGINS_DIR << "directory not accessible or does not exist in " << dir.path(); + } + } +} + + +void MainWindow::RestoreSettings() +{ + + // Restore previous main window geometry: + QVariant geometry(settings_.value("geometry")); + if (!geometry.isNull()) { + qDebug() << "restoring geometry"; + 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(); + options["net/uploadRate"] = settings_.value("net/uploadRate").toString(); + server_.setOptions(options); +} + + +// Opens torrent information from buffer data and adds torrent to session +void MainWindow::StartTorrentFromBufferData(char const* data, int size) +{ + +} + +// =========================== PRIVATE SLOTS ================================= +void MainWindow::on_openAction_clicked() +{ + QString filename = QFileDialog::getOpenFileName( this, tr("Open torrent file"), QString(), tr("Torrent files (*.torrent)") ); + on_torrentFileSelected(filename); + /* + QFileDialog *dialog = new QFileDialog( this, "Open torrent file", QString(), tr("Torrent files (*.torrent)")); + dialog->setFileMode(QFileDialog::ExistingFile); + connect(dialog, SIGNAL(fileSelected(const QString&)), this, SLOT(on_torrentFileSelected(const QString&))); + dialog->show(); + */ +} + +void MainWindow::on_removeAction_clicked() +{ + QString hash = dlView_->prepareRemoveSelected(); + try { + server_.removeTorrent(hash); + } catch (...) { + qDebug() << "Exception while removing torrent"; + } +} + + +void MainWindow::on_quitAction_clicked() +{ + close(); +} + + +void MainWindow::on_startDaemonAction_clicked() +{ + server_.getState(); + /// @todo create signal that signals server startup and + /// enable controls in the handler slot + stopDaemonAction_->setEnabled(true); + startDaemonAction_->setEnabled(false); +} + + +void MainWindow::on_stopDaemonAction_clicked() +{ + server_.terminateSession(); +} + + +void MainWindow::on_serverTerminated() +{ + stopDaemonAction_->setEnabled(false); + startDaemonAction_->setEnabled(true); +} + +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_) { + preferencesDialog_ = new PreferencesDialog(this, 0, &server_); + } + + preferencesDialog_->show(); + preferencesDialog_->raise(); + preferencesDialog_->activateWindow(); +} + + +void MainWindow::on_aboutAction_clicked() +{ + QMessageBox::about(this, tr("About QtRapids"), ABOUT_TEXT); +} + + +void MainWindow::on_aboutQtAction_clicked() +{ + QMessageBox::aboutQt (this, tr("About Qt")); +} + + +void MainWindow::on_tabWidget_tabCloseRequested(int index) +{ + + int searchWidgetIndex = tabWidget_->indexOf(searchWidget_); + + // Allow closing other tabs than the first two + // TODO The first two may well be closable, just add "show tabs" action for these in the menu + if (index != 0 && index != 1 && index != searchWidgetIndex) { + QWidget *remove = tabWidget_->widget(index); + tabWidget_->removeTab(index); + delete remove; + remove = NULL; + } +} + + +void MainWindow::on_downloadItemSelectionChanged() +{ +#ifdef QTRAPIDS_DEBUG + qDebug() << "MainWindow::on_seedItemSelectionChanged():" << dlView_->currentItem(); +#endif + if (dlView_->currentItem() != NULL) { + emit(itemSelected(true)); + } else { + emit(itemSelected(false)); + } +} + + +void MainWindow::on_seedItemSelectionChanged() +{ +#ifdef QTRAPIDS_DEBUG + qDebug() << "MainWindow::on_seedItemSelectionChanged():" << seedView_->currentItem(); +#endif + if (seedView_->currentItem() != NULL) { + emit(itemSelected(true)); + } else { + emit(itemSelected(false)); + } +} + + +void MainWindow::handleToolBarAction(QAction* action) +{ + if (action->text() == "Open") { + on_openAction_clicked(); + } else if (action->text() == "Remove") { + on_removeAction_clicked(); + } +} + + +void MainWindow::on_torrentFileSelected(QString file) +{ +#ifdef QTRAPIDS_DEBUG + qDebug() << " MainWindow::on_torrentFileSelected(): " << file; +#endif + // Torrent filename empty, do nothing. + if (file == "") { + return; + } + + // Otherwise add torrent + // For params, see: http://www.rasterbar.com/products/libtorrent/manual.html#add-torrent + // save_path is the only mandatory parameter, rest are optional. + //addParams.storage_mode = libtorrent::storage_mode_allocate; + try { + server_.addTorrent(file, settings_.value("download/directory").toString() + , ParamsMap_t()); + } catch (...) { + qDebug() << "Exception adding torrent"; + } +} + + +void MainWindow::on_alert(qtrapids::TorrentState info, qtrapids::ParamsMap_t other_info) +{ +#ifdef QTRAPIDS_DEBUG + qDebug() << "got alert"; +#endif + dlView_->updateItem(info, other_info); +} + +} // namespace qtrapids diff --git a/src/qml-client/MainWindow.h b/src/qml-client/MainWindow.h new file mode 100644 index 0000000..2b017b8 --- /dev/null +++ b/src/qml-client/MainWindow.h @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +#include "PluginInterface.h" +#include "proxy.h" + +class QTabWidget; +class DownloadView; +class PreferencesDialog; + +namespace qtrapids +{ + +class SeedView; + +/** + @author Lassi Väätämöinen +*/ +class MainWindow : public QMainWindow, public PluginHostInterface +{ + + Q_OBJECT; + +public: + + MainWindow(); + virtual ~MainWindow(); + + // Implemented from PluginHostInterface + virtual bool setGui(QWidget* widget, PluginWidgetType type = UNKNOWN_TYPE, qtrapids::PluginInterface* plugin = NULL); + virtual void addPluginWidget(QWidget* widget, PluginWidgetType type = UNKNOWN_TYPE); + virtual void addToolbar(QWidget* widget, PluginWidgetType type = UNKNOWN_TYPE); + virtual void addToolItem(QWidget* widget, PluginWidgetType type = UNKNOWN_TYPE); + virtual void addMenu(QWidget* widget, PluginWidgetType type = UNKNOWN_TYPE); + virtual void addMenuItem(QWidget* widget, PluginWidgetType type = UNKNOWN_TYPE); + virtual bool eventRequest(QVariant param, PluginRequest req = UNKNOWN_REQUEST); + + void RestoreSettings(); + + void connectToServer() { + qDBusRegisterMetaType(); + qDBusRegisterMetaType(); + + connect(&server_ + , SIGNAL(alert(qtrapids::TorrentState + , qtrapids::ParamsMap_t)) + , this + , SLOT(on_alert(qtrapids::TorrentState + , qtrapids::ParamsMap_t))); + // Request server state. + // NOTE: This call starts qtrapids-server automatically with the GUI, + // if the .service file is in /usr/share/dbus-1/services/ + server_.getState(); + } + +signals: + void itemSelected(bool enabled); + +public slots: +private slots: + void on_openAction_clicked(); + void on_removeAction_clicked(); + void on_quitAction_clicked(); + void on_startDaemonAction_clicked(); + void on_stopDaemonAction_clicked(); + void on_serverTerminated(); + void on_columnsAction_clicked(); + void on_preferencesAction_clicked(); + void on_aboutAction_clicked(); + void on_aboutQtAction_clicked(); + void on_tabWidget_tabCloseRequested(int index); + void on_downloadItemSelectionChanged(); + void on_seedItemSelectionChanged(); + void handleToolBarAction(QAction* action); + void on_torrentFileSelected(QString file); + void on_alert(qtrapids::TorrentState, qtrapids::ParamsMap_t); + + +private: + void LoadPlugins(); + void StartTorrentFromBufferData(char const* data, int size); + +private: + QTabWidget *tabWidget_; + DownloadView *dlView_; + SeedView *seedView_; + QWidget *searchWidget_; + QAction *startDaemonAction_, *stopDaemonAction_; + PreferencesDialog *preferencesDialog_; + QSettings settings_; + QList pluginDirs_; + QStringList pluginFileNames_; + + + //std::vector< std::auto_ptr const > torrentHandles_; + + QtRapidsServer server_; + + + //bool IsNewTorrent(std::auto_ptr handlePtr); +}; + +} // namespace qtrapids + +#endif diff --git a/src/qml-client/PreferencesDialog.cpp b/src/qml-client/PreferencesDialog.cpp new file mode 100644 index 0000000..4f6bbf1 --- /dev/null +++ b/src/qml-client/PreferencesDialog.cpp @@ -0,0 +1,195 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 +#include +#include +#include + +#include "qtrapids/dbus.hpp" +#include "proxy.h" +#include "PreferencesDialog.h" + + + +PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags f, QtRapidsServer *server) : + QDialog(parent, f), // Superclass + dirLineEdit_(NULL), + dialogButtons_(NULL), + uploadRateSpinBox_(NULL), + downloadRateSpinBox_(NULL), + server_(server), + settings_() +{ + setWindowTitle("Preferences"); + + QBoxLayout *verticalBox = new QBoxLayout(QBoxLayout::TopToBottom); + //QBoxLayout *horizontalBox1 = new QBoxLayout(QBoxLayout::LeftToRight); + QGridLayout *grid = new QGridLayout; + setLayout(verticalBox); + verticalBox->addLayout(grid); + + QLabel *dirLabel = new QLabel(tr("Download directory: ")); + dirLineEdit_ = new QLineEdit(this); + QPushButton *browseDirButton = new QPushButton(tr("Browse..")); + + QLabel *uploadLabel = new QLabel(tr("Max. upload rate: ")); + QLabel *downloadLabel = new QLabel(tr("Max. download rate: ")); + uploadRateSpinBox_ = new QSpinBox(this); + downloadRateSpinBox_ = new QSpinBox(this); + + grid->addWidget(dirLabel, 0, 0); + grid->addWidget(dirLineEdit_, 0, 1); + grid->addWidget(browseDirButton, 0, 2); + + grid->addWidget(uploadLabel, 1, 0); + grid->addWidget(uploadRateSpinBox_, 1, 1); + grid->addWidget(downloadLabel, 2, 0); + grid->addWidget(downloadRateSpinBox_, 2, 1); + + uploadRateSpinBox_->setRange(0, 1000); + uploadRateSpinBox_->setSuffix(" kB/s"); + downloadRateSpinBox_->setRange(0, 1000); + downloadRateSpinBox_->setSuffix(" kB/s"); + +// horizontalBox1->addWidget(dirLabel); +// horizontalBox1->addWidget(dirLineEdit_); +// horizontalBox1->addWidget(browseDirButton); + + connect(browseDirButton, SIGNAL(clicked()), + this, SLOT(on_browseDirButtonClicked())); + + + dialogButtons_ = new QDialogButtonBox(this); + dialogButtons_->setStandardButtons(QDialogButtonBox::Ok + | QDialogButtonBox::Apply + | QDialogButtonBox::Cancel); + + verticalBox->addWidget(dialogButtons_); + + connect(dialogButtons_, SIGNAL(clicked(QAbstractButton*)), + this, SLOT(on_buttonClicked(QAbstractButton*))); + + // Set saved preference values to fields. + ReadSettings(); + +} + + +PreferencesDialog::~PreferencesDialog() +{ +} + +// ======================== SLOTS ======================== +void PreferencesDialog::on_browseDirButtonClicked() +{ + QString dir = QFileDialog::getExistingDirectory(this, tr("Download directory"), QString(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + on_downloadDirectorySelected(dir); + + /* + QFileDialog *dialog + = new QFileDialog(this, "Download directory", + QString(), tr("Torrent files (*.torrent)")); + + dialog->setFileMode(QFileDialog::Directory); + dialog->setOption(QFileDialog::ShowDirsOnly, true); + + connect(dialog, SIGNAL(fileSelected(const QString&)), + this, SLOT(on_downloadDirectorySelected(const QString&))); + + dialog->show(); + */ +} + +void PreferencesDialog::on_buttonClicked(QAbstractButton* button) +{ + switch (dialogButtons_->buttonRole ( button ) ) { + case QDialogButtonBox::AcceptRole : + qDebug() << "PreferencesDialog: OK"; + WriteSettings(); + done(QDialog::Accepted); + break; + case QDialogButtonBox::ApplyRole : + qDebug() << "PreferencesDialog: APPLY"; + WriteSettings(); + break; + case QDialogButtonBox::RejectRole : + qDebug() << "PreferencesDialog: CANCEL"; + done(QDialog::Rejected); + break; + default: + return; + } +} + +void PreferencesDialog::on_downloadDirectorySelected(QString directory) +{ + qDebug() << "PreferencesDialog::on_downloadDirectorySelected(): " << directory; + // Torrent filename empty, do nothing. + if (directory == "") + return; + + dirLineEdit_->clear(); + dirLineEdit_->insert(directory); + + /// @todo check that user has privileges to write to this directory. +} + + +// ========================= Private functions ========================== +void PreferencesDialog::WriteSettings() +{ + int ulRate = 1000*uploadRateSpinBox_->value(); + int dlRate = 1000*downloadRateSpinBox_->value(); + + settings_.setValue("download/directory", dirLineEdit_->text()); + //settings_.setValue("net/uploadRate", ulRate); + //settings_.setValue("net/downloadRate", dlRate); + + // NOTE: We might need to call QSettigns::sync() here to instantly write settings. + // settings are written also by QSettings() destructor and by event loop at regular interval. + + // If server pointer was given, apply settings immediately. + if (server_) { + /// @todo Use DBus interface + /// @todo Set parameters for server + /// @todo Add speedlimit functionality to Server. + qtrapids::ParamsMap_t options; + options["net/downloadRate"] = QString::number(dlRate); + options["net/uploadRate"] = QString::number(ulRate); + server_->setOptions(options); +// btSession_->setUploadRateLimit(ulRate); +// btSession_->setDownloadRateLimit(dlRate); + } + +} + +void PreferencesDialog::ReadSettings() +{ + dirLineEdit_->insert(settings_.value("download/directory").toString()); + uploadRateSpinBox_->setValue(settings_.value("net/uploadRate").toInt()/1000); + downloadRateSpinBox_->setValue(settings_.value("net/downloadRate").toInt()/1000); + + // NOTE: We might need to call QSettigns::sync() here to instantly write settings. + // settings are written also by QSettings() destructor and by event loop at regular interval. +} + diff --git a/src/qml-client/PreferencesDialog.h b/src/qml-client/PreferencesDialog.h new file mode 100644 index 0000000..c667034 --- /dev/null +++ b/src/qml-client/PreferencesDialog.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include +#include + + +class QAbstractButton; +class QLineEdit; +class QSpinBox; +class QDialogButtonBox; + +class QtRapidsServer; + + +/** + @author Lassi Väätämöinen +*/ +class PreferencesDialog : public QDialog +{ + + Q_OBJECT + +public: + PreferencesDialog(QWidget* parent = 0, Qt::WindowFlags f = 0, QtRapidsServer *server = 0); + + ~PreferencesDialog(); + +private slots: + void on_browseDirButtonClicked(); + void on_buttonClicked(QAbstractButton* button); + void on_downloadDirectorySelected(QString directory); + +private: + QLineEdit *dirLineEdit_; + QDialogButtonBox *dialogButtons_; + QSpinBox *uploadRateSpinBox_, *downloadRateSpinBox_; + + QtRapidsServer *server_; + + QSettings settings_; + +private: + // Private functions: + void WriteSettings(); + void ReadSettings(); +}; + +#endif diff --git a/src/qml-client/SeedView.cpp b/src/qml-client/SeedView.cpp new file mode 100644 index 0000000..2fd3a65 --- /dev/null +++ b/src/qml-client/SeedView.cpp @@ -0,0 +1,45 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 "SeedView.h" + +#include + +namespace qtrapids +{ + +SeedView::SeedView(QWidget* parent): + QTreeWidget(parent) +{ + setRootIsDecorated(false); // Hide branch lines, making one-level treeview (similar to list) + setHeaderItem(SeedViewItem::getHeaderItem()); + + connect(this, SIGNAL(itemPressed(QTreeWidgetItem*, int)), + this, SLOT(on_itemPressed(QTreeWidgetItem*, int))); +} + + +SeedView::~SeedView() +{ +} + +void SeedView::on_itemPressed(QTreeWidgetItem * item, int column) +{ + qDebug() << "SeedView::on_itemPressed() " << item << "," << column; +} + +} // namespace qtrapids diff --git a/src/qml-client/SeedView.h b/src/qml-client/SeedView.h new file mode 100644 index 0000000..bc6988a --- /dev/null +++ b/src/qml-client/SeedView.h @@ -0,0 +1,90 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 SEEDVIEW_H +#define SEEDVIEW_H + +#include + +namespace qtrapids +{ + +class TorrentHandle; +class SeedViewItem; + +/** + @author Lassi Väätämöinen +*/ +class SeedView : public QTreeWidget +{ + Q_OBJECT +public: + SeedView(QWidget* parent); + + ~SeedView(); + +private slots: + void on_itemPressed(QTreeWidgetItem *item, int column); + +private: + + // Name + // Size + // Status + // UP speed + // Seeds/Leechers + // Connected peers + // total uploaded + // ratio +}; + +/** + @class DownloadViewItem + @brief Represents one item row of DownloadView +*/ +class SeedViewItem : public QTreeWidgetItem +{ + +public: + + SeedViewItem(QTreeWidget* parent, int type) : + QTreeWidgetItem(parent, type = QTreeWidgetItem::UserType) {}; + + SeedViewItem(const QStringList& strings, int type = QTreeWidgetItem::UserType ) : + QTreeWidgetItem (strings, type = Type) {}; + + + /// @return An item comprising of string list, suitable for QTableView + /// header. + static SeedViewItem *getHeaderItem() { + SeedViewItem *item + = new SeedViewItem(QStringList() + << "Name" + << "Size" << "Status" + << "Progress" << "UL speed" << "Seeds/Leechers" + << "Conn. peers" + << "Ratio"); + + return item; + } + + /// @todo TorrentHandle as one hidden column +}; + +} // namespace qtrapids + +#endif diff --git a/src/qml-client/main.cpp b/src/qml-client/main.cpp new file mode 100644 index 0000000..9d992b8 --- /dev/null +++ b/src/qml-client/main.cpp @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 +//#include "DownloadView.h" +#include +#include "models/QDeclarativeDownloadListModel.h" + +#include "MainWindow.h" +#include "../include/qtrapids/dbus.hpp" + +using qtrapids::MainWindow; + +int main(int argc, char *argv[]) +{ + + + + QCoreApplication::setOrganizationName("Ixonos"); + QCoreApplication::setOrganizationDomain("ixonos.com"); + QCoreApplication::setApplicationName("QtRapids"); + + // Q_INIT_RESOURCE(application); + QApplication app(argc, argv); + //MainWindow mainWindow; + app.setProperty("NoMStyle", true); + + // Register our types: + qmlRegisterType("QtRapids", 1, 0, "DownloadListModel"); + + QDir::setCurrent(app.applicationDirPath()); + + QDeclarativeView window; + //QDeclarativeEngine engine; + qtrapids::QDeclarativeDownloadListModel downloadModel; + QDeclarativeContext *context = window.rootContext(); + context->setContextProperty("downloadModel", &downloadModel); + window.setSource(QUrl("qrc:/main.qml")); + + window.showFullScreen(); +// window.show(); + + + /* TODO: Enable this once we have the views up & running + QDBusConnection dbus = QDBusConnection::sessionBus(); + dbus.registerObject("/qtrapids_gui", &mainWindow); + dbus.registerService("com.ixonos.qtrapids_gui"); + + mainWindow.connectToServer(); + mainWindow.RestoreSettings(); + + // mainWindow->setGeometry(QApplication::desktop()->screenGeometry()); + + mainWindow.show(); + */ + /* + DownloadView* dlw = new DownloadView(NULL); + //qtrapids * mw = new qtrapids(); + dlw->show(); + DownloadViewItem* dlwItem = new DownloadViewItem(QStringList() << "Name" + << "Size" << "Status" + << "Progress" << "DL speed" + << "UL speed" << "Seeds/Leechers" + << "ratio"); + DownloadViewItem* dlwItem2 = new DownloadViewItem(QStringList() << "Name" + << "1000" << "Downloading" + << "23%" << "11" + << "0.1" << "0/2" + << "1.10"); + //dlwItem->insertChild(0, new DownloadViewItem(QStringList() << "Name")); + dlw->insertTopLevelItem(0,dlwItem); + dlw->insertTopLevelItem(1,dlwItem2); + + for (unsigned i = 0; i < 10; ++i) + { + DownloadViewItem *editItem = dynamic_cast + (dlw->itemAt(QPoint(0,0))); + editItem->setData ( 8, Qt::DisplayRole, QVariant("EDITED" + QString::number(i, 'g', 2))); + QTest::qSleep(2000); + } + */ + + qtrapids::TorrentState editItem; + for (unsigned i = 0; i < 10; ++i) + { + editItem.hash = QString("asdfasdfasdfasdfasfsd-") + QString::number(i); + editItem.name = QString("Lassi-") + QString::number(i); + editItem.action = qtrapids::TorrentState::action_add; + editItem.state = 0; + editItem.progress = 10+i; + editItem.down_rate = 10+i; + editItem.up_rate = 10+i; + editItem.seeds = 10+i; + editItem.leeches = 10+i; + editItem.ratio = 10+i; + editItem.total_size = 100000+i; + editItem.total_done = 10000+i; + downloadModel.updateItem(editItem, qtrapids::ParamsMap_t()); + } + + return app.exec(); +} diff --git a/src/qml-client/models/Plugin.cpp b/src/qml-client/models/Plugin.cpp new file mode 100644 index 0000000..a6c6165 --- /dev/null +++ b/src/qml-client/models/Plugin.cpp @@ -0,0 +1,19 @@ +#include +#include +#include + +// This class is needed to make DownloadListModel class available to QML: +class QmlDownloadListModelPlugin : public QDeclarativeExtensionPlugin +{ + Q_OBJECT +public: + virtual void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.downloadlistmodel")); + qmlRegisterType(uri, 1, 0, "DownloadListModel"); + } +}; + +#include "moc_Plugin.cxx" + +Q_EXPORT_PLUGIN2(downloadlistmodelplugin, QT_PREPEND_NAMESPACE(QmlDownloadListModelPlugin)); \ No newline at end of file diff --git a/src/qml-client/models/Plugin.h b/src/qml-client/models/Plugin.h new file mode 100644 index 0000000..129970c --- /dev/null +++ b/src/qml-client/models/Plugin.h @@ -0,0 +1,18 @@ +#include +#include + +#include "QDeclarativeDownloadListModel.h" + +// This class is needed to make DownloadListModel class available to QML: +class QmlDownloadListModelPlugin : public QDeclarativeExtensionPlugin +{ + Q_OBJECT +public: + virtual void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.downloadlistmodel")); + qmlRegisterType(uri, 1, 0, "DownloadListModel"); + } +}; + +Q_EXPORT_PLUGIN2(downloadlistmodelplugin, QT_PREPEND_NAMESPACE(QmlDownloadListModelPlugin)); \ No newline at end of file diff --git a/src/qml-client/models/QDeclarativeDownloadListModel.cpp b/src/qml-client/models/QDeclarativeDownloadListModel.cpp new file mode 100644 index 0000000..e990705 --- /dev/null +++ b/src/qml-client/models/QDeclarativeDownloadListModel.cpp @@ -0,0 +1,304 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 "QDeclarativeDownloadListModel.h" +#include "QDeclarativeDownloadListModel_p.h" +#include "qtrapids/format.hpp" + +namespace qtrapids +{ + +QDeclarativeDownloadListModel::QDeclarativeDownloadListModel(QObject *parent): + QAbstractListModel(parent) +{ + d = new QDeclarativeDownloadListModelPrivate; + + // These roles are the names that we use to access the model data on QML + // in the string format. So, use the value on the right-hand side of assignment operator in QML. + // The role enum value is passed from QML side to the C++ model for fetching the data. + QHash roles; + roles[DownloadRole] = "download"; + roles[SeedRole] = "seed"; + roles[HashRole] = "hash"; + roles[NameRole] = "name"; + roles[SizeRole] = "size"; + roles[StatusRole] = "status"; + roles[StateRole] = "state"; + roles[ProgressRole] = "progress"; + roles[DownRateRole] = "downRate"; + roles[UpRateRole] = "upRate"; + roles[SeedsRole] = "seeds"; + roles[LeechesRole] = "leeches"; + roles[RatioRole] = "ratio"; + roles[TotaSizeRole] = "totalSize"; + roles[TotalDoneRole] = "totalDone"; + setRoleNames(roles); +} + +QDeclarativeDownloadListModel::~QDeclarativeDownloadListModel() +{ +} + + +void +QDeclarativeDownloadListModel::updateItem(TorrentState const& info, + ParamsMap_t other_info) +{ + qDebug() << Q_FUNC_INFO << " enter"; + + DownloadItems_t::iterator p = d->items_.find(info.hash); + switch (info.action) { + case TorrentState::action_add : + if (p == d->items_.end()) { + addItem_(info, other_info); + } else { + qWarning() << "item with similar info hash marked as added"; + updateItem_(info, other_info); + } + break; + case TorrentState::action_update : + if (p != d->items_.end()) { + updateItem_(info, other_info); + } else { + qWarning() << "item does not exist in list but information update arrived"; + } + break; + case TorrentState::action_remove : + if (p != d->items_.end()) { + removeItem_(info); + } else { + qWarning() << "item removal request arrived but there is no such item"; + } + break; + default: + qWarning() << "unknown action requested: " << info.action; + break; + } +} + + + // Returns the hash of the torrent be removed. +QString QDeclarativeDownloadListModel::prepareRemoveSelected() +{ + return "DUMMY_HASH"; +} + +int QDeclarativeDownloadListModel::rowCount(const QModelIndex &parent) const +{ + return d->items_.count(); +} + +QVariant QDeclarativeDownloadListModel::data(const QModelIndex &index, int role) const +{ + + qDebug() << Q_FUNC_INFO << " enter"; + int rowIndex = index.row(); + QString hash; + TorrentState item; + + // Get the item hash corresponding to row number: + if (d->itemIndexes_.contains(rowIndex)) + hash = d->itemIndexes_[rowIndex]; + else + return QVariant(); + + // Get the torrent info for the hash: + if (d->items_.contains(hash)) + item = d->items_[hash]; + else + return QVariant(); + + switch (role) { +// case DownloadRole: +// // TODO: What to do here?? +// break; +// case SeedRole: +// // TODO: What to do here?? +// break; + case HashRole: + return QVariant(item.hash); + case NameRole: + return QVariant(item.name); +// case SizeRole: +// return QVariant(item.total_size); + case StatusRole: + return QVariant(); + case StateRole: + return QVariant(item.state); + case ProgressRole: + return QVariant(item.progress); + case DownRateRole: + return QVariant(item.down_rate); + case UpRateRole: + return QVariant(item.up_rate); + case SeedsRole: + return QVariant(item.seeds); + case LeechesRole: + return QVariant(item.leeches); + case RatioRole: + return QVariant(item.ratio); + case TotaSizeRole: + return QVariant(item.total_size); + case TotalDoneRole: + return QVariant(item.total_done); + default: + qWarning() << Q_FUNC_INFO << "Unknown role requested from model"; + return QVariant(); + } + return QVariant(); +} + +bool QDeclarativeDownloadListModel::insertRow(int row, const QModelIndex &parent) +{ + qDebug() << "QDeclarativeDownloadListModel::insertRow()"; + return false; +} + +bool QDeclarativeDownloadListModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + qDebug() << "QDeclarativeDownloadListModel::setData()"; + return false; +} + + +void QDeclarativeDownloadListModel::classBegin() +{ + qDebug() << "QDeclarativeDownloadListModel::classBegin()"; +} + +void QDeclarativeDownloadListModel::componentComplete() +{ + qDebug() << "QDeclarativeDownloadListModel::componentComplete()"; +} + + +void QDeclarativeDownloadListModel::removeItem_(TorrentState const& info) +{ + qDebug() << Q_FUNC_INFO << " enter"; + QString hash = info.hash; + + // TODO: Emit rows remove start + int removed = d->items_.remove(hash); + // TODO: Edit rows insert end + if (!removed) + qDebug() << "Inconsistent download view state on item removal"; + + /* + int index = indexOfTopLevelItem(item); + if (index >= 0) { + takeTopLevelItem(index); + } + */ +} + +void QDeclarativeDownloadListModel::addItem_(TorrentState const& info, + ParamsMap_t) +{ + qDebug() << Q_FUNC_INFO << " enter"; +/* + DownloadViewItem *item = new DownloadViewItem + ( info.hash, + QStringList() + << info.name + << formatSize(info.total_size) + << GetStatusString((TorrentStatus::Id)info.state) + << formatProgress(info.progress) + << formatSize(info.down_rate) + << formatSize(info.up_rate) + << QString::number(info.seeds) + "/" + QString::number(info.leeches) + << QString::number(info.ratio) + << "ETA" ); + + QBrush brushTmp(GetStatusColor((TorrentStatus::Id)info.state)); + item->setForeground(2, brushTmp); + + addTopLevelItem(item); + */ + + int itemsCount = d->items_.count(); + beginInsertRows(QModelIndex(), itemsCount, itemsCount+1); + d->items_[info.hash] = info; + d->itemIndexes_[itemsCount+1] = info.hash; + endInsertRows(); +} + + +void QDeclarativeDownloadListModel::updateItem_(TorrentState const& info, ParamsMap_t) +{ + qDebug() << Q_FUNC_INFO << " enter"; + /* + item->setData(2, Qt::DisplayRole, + QVariant(GetStatusString((TorrentStatus::Id)info.state))); + item->setData(3, Qt::DisplayRole, + QVariant(formatProgress(info.progress))); + item->setData(4, Qt::DisplayRole, + QVariant(formatSize(info.down_rate))); + item->setData(5, Qt::DisplayRole, + 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"); + } +*/ + // TODO: Update items data & Emit data changed. + +/* + // Set color for status text + QBrush brushTmp(GetStatusColor((TorrentStatus::Id)info.state)); + item->setForeground(2, brushTmp); + */ +} + + + +QString QDeclarativeDownloadListModel::GetStatusString(TorrentStatus::Id status) +{ + qDebug() << Q_FUNC_INFO << " enter"; + switch (status) { + case TorrentStatus::QUEUED_FOR_CHECKING : + return tr("Queued"); + case TorrentStatus::CHECKING_FILES : + return tr("Checking"); + case TorrentStatus::DOWNLOADING_METADATA : + return tr("DL meta"); + case TorrentStatus::DOWNLOADING : + return tr("Downloading"); + case TorrentStatus::FINISHED : + return tr("Finished"); + case TorrentStatus::SEEDING : + return tr("Seeding"); + case TorrentStatus::ALLOCATING : + return tr("Allocating"); + case TorrentStatus::CHECKING_RESUME_DATA : + return tr("Checking resume"); + default: + return tr("N/A"); + } +} + +} // namespace qtrapids diff --git a/src/qml-client/models/QDeclarativeDownloadListModel.h b/src/qml-client/models/QDeclarativeDownloadListModel.h new file mode 100644 index 0000000..ee9cadd --- /dev/null +++ b/src/qml-client/models/QDeclarativeDownloadListModel.h @@ -0,0 +1,129 @@ +/*************************************************************************** + * Copyright (C) 2010 by Ixonos Plc * + * * + * 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; version 2 of the License. * + * * + * 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 QDECLARATIVEDOWNLOADLISTMODEL_H +#define QDECLARATIVEDOWNLOADLISTMODEL_H + + +#include +#include +#include +#include + +#include "qtrapids/dbus.hpp" +#include "qtrapids/info.hpp" + +//#include "../DownloadView.h" + +QT_MODULE(Declarative); + +namespace qtrapids +{ + +typedef QHash DownloadItems_t; +typedef QMap ItemIndex_t; + +class QDeclarativeContext; +class QDeclarativeDownloadListModelPrivate; + +class QDeclarativeDownloadListModel : + public QAbstractListModel, public QDeclarativeParserStatus +{ + Q_OBJECT + Q_INTERFACES(QDeclarativeParserStatus); + + /* + Q_PROPERTY(QString hash READ hash); + Q_PROPERTY(QString name READ name WRITE setName); + Q_PROPERTY(QString size READ size); + Q_PROPERTY(QString status READ status); + Q_PROPERTY(uint state READ state); + Q_PROPERTY(uint progress READ progress); + Q_PROPERTY(uint downRate READ downRate); + Q_PROPERTY(uint upRate READ upRate); + Q_PROPERTY(uint seeds READ seeds); + Q_PROPERTY(uint leeches READ leeches); + Q_PROPERTY(qulonglong ratio READ ratio); + Q_PROPERTY(qulonglong totaSize READ totalDone); + Q_PROPERTY(qulonglong totalDone READ totalDone); +*/ + +public: + QDeclarativeDownloadListModel(QObject *parent = 0); + virtual ~QDeclarativeDownloadListModel(); + + // TODO: Learn to use roles.. + enum Roles { + DownloadRole = Qt::UserRole + 1, + SeedRole, + HashRole, + NameRole, + SizeRole, + StatusRole, + StateRole, + ProgressRole, + DownRateRole, + UpRateRole, + SeedsRole, + LeechesRole, + RatioRole, + TotaSizeRole, + TotalDoneRole + }; + + // Updates the torrent status in the model. + void updateItem(TorrentState const& info, ParamsMap_t other_info); + // Returns the hash of the torrent be removed. + QString prepareRemoveSelected(); + + // -- QAbstractListModel + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual bool insertRow(int row, const QModelIndex &parent); + virtual bool setData (const QModelIndex & index, const QVariant &value, int role = Qt::EditRole); + // -- End QAbstractListModel + + // -- Overrides from QDeclarativeParserStatus + virtual void classBegin(); + virtual void componentComplete(); + // -- End QDeclarativeParserStatus + +Q_SIGNALS: + void downloadItemChanged(QString hash); + +// Private functions. +private: + Q_DISABLE_COPY(QDeclarativeDownloadListModel) + QDeclarativeDownloadListModelPrivate *d; + + void addItem_(TorrentState const& info, ParamsMap_t other_info); + void updateItem_(TorrentState const& info, ParamsMap_t other_info); + void removeItem_(TorrentState const& info); + QString GetStatusString(TorrentStatus::Id status); +private: + +}; + + +} // namespace qtrapids + +// We need to declare the type +QML_DECLARE_TYPE(qtrapids::QDeclarativeDownloadListModel); + + + +#endif diff --git a/src/qml-client/models/QDeclarativeDownloadListModel_p.h b/src/qml-client/models/QDeclarativeDownloadListModel_p.h new file mode 100644 index 0000000..6c4b699 --- /dev/null +++ b/src/qml-client/models/QDeclarativeDownloadListModel_p.h @@ -0,0 +1,30 @@ +#ifndef QDECLARATIVEDOWNLOADLISTMODELPRIVATE_H +#define QDECLARATIVEDOWNLOADLISTMODELPRIVATE_H + +#include + +#include "QDeclarativeDownloadListModel.h" // TODO: For DownloadItems_t, move that to common place.. + +namespace qtrapids +{ + +class QDeclarativeDownloadListModelPrivate : QObject +{ + Q_OBJECT +public: + QDeclarativeDownloadListModelPrivate() + { + } + + DownloadItems_t items_; + ItemIndex_t itemIndexes_; + //QModelIndex downloadIndex_; + +signals: + void itemAdded(QString hash); + void itemRemoved(QString hash); + +}; +} // namespace qtrapids + +#endif diff --git a/src/qml-client/models/qmldir b/src/qml-client/models/qmldir new file mode 100644 index 0000000..9e05264 --- /dev/null +++ b/src/qml-client/models/qmldir @@ -0,0 +1 @@ +plugin qmlfolderlistmodelplugin \ No newline at end of file diff --git a/src/qml-client/proxy.cpp b/src/qml-client/proxy.cpp new file mode 100644 index 0000000..2c0c20c --- /dev/null +++ b/src/qml-client/proxy.cpp @@ -0,0 +1,26 @@ +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -a server -c QtRapidsServer -i qtrapids/dbus.hpp -p proxy /home/lassi/Projects/qtrapids/trunk/dbus/com.ixonos.qtrapids.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * This file may have been hand-edited. Look for HAND-EDIT comments + * before re-generating it. + */ + +#include "proxy.h" + +/* + * Implementation of interface class QtRapidsServer + */ + +QtRapidsServer::QtRapidsServer(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) + : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) +{ +} + +QtRapidsServer::~QtRapidsServer() +{ +} + diff --git a/src/qml-client/proxy.h b/src/qml-client/proxy.h new file mode 100644 index 0000000..6690149 --- /dev/null +++ b/src/qml-client/proxy.h @@ -0,0 +1,90 @@ +/* + * This file was generated by qdbusxml2cpp version 0.7 + * Command line was: qdbusxml2cpp -a server -c QtRapidsServer -i qtrapids/dbus.hpp -p proxy /home/lassi/Projects/qtrapids/trunk/dbus/com.ixonos.qtrapids.xml + * + * qdbusxml2cpp is Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + * + * This is an auto-generated file. + * Do not edit! All changes made to it will be lost. + */ + +#ifndef PROXY_H_1327258740 +#define PROXY_H_1327258740 + +#include +#include +#include +#include +#include +#include +#include +#include +#include "qtrapids/dbus.hpp" + +/* + * Proxy class for interface com.ixonos.qtrapids + */ +class QtRapidsServer: public QDBusAbstractInterface +{ + Q_OBJECT +public: + static inline const char *staticInterfaceName() + { return "com.ixonos.qtrapids"; } + +public: + QtRapidsServer(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = 0); + + ~QtRapidsServer(); + +public Q_SLOTS: // METHODS + inline QDBusPendingReply<> addTorrent(const QString &path, const QString &save_path, qtrapids::ParamsMap_t other_params) + { + QList argumentList; + argumentList << qVariantFromValue(path) << qVariantFromValue(save_path) << qVariantFromValue(other_params); + return asyncCallWithArgumentList(QLatin1String("addTorrent"), argumentList); + } + + inline QDBusPendingReply getOptions() + { + QList argumentList; + return asyncCallWithArgumentList(QLatin1String("getOptions"), argumentList); + } + + inline QDBusPendingReply<> getState() + { + QList argumentList; + return asyncCallWithArgumentList(QLatin1String("getState"), argumentList); + } + + inline QDBusPendingReply<> removeTorrent(const QString &hash) + { + QList argumentList; + argumentList << qVariantFromValue(hash); + return asyncCallWithArgumentList(QLatin1String("removeTorrent"), argumentList); + } + + inline QDBusPendingReply<> setOptions(qtrapids::ParamsMap_t options) + { + QList argumentList; + argumentList << qVariantFromValue(options); + return asyncCallWithArgumentList(QLatin1String("setOptions"), argumentList); + } + + inline QDBusPendingReply<> terminateSession() + { + QList argumentList; + return asyncCallWithArgumentList(QLatin1String("terminateSession"), argumentList); + } + +Q_SIGNALS: // SIGNALS + void alert(qtrapids::TorrentState info, qtrapids::ParamsMap_t other_info); + void sessionTerminated(); + void terminate(); +}; + +namespace com { + namespace ixonos { + typedef ::QtRapidsServer qtrapids; + } +} +#endif diff --git a/src/qml-client/qml/DownloadView.qml b/src/qml-client/qml/DownloadView.qml new file mode 100644 index 0000000..e69de29 diff --git a/src/qml-client/qml/MainPage.qml b/src/qml-client/qml/MainPage.qml new file mode 100644 index 0000000..a189bab --- /dev/null +++ b/src/qml-client/qml/MainPage.qml @@ -0,0 +1,177 @@ +import QtQuick 1.1 +import Qt.labs.components 1.0 +import com.nokia.meego 1.0 +import com.meego 1.0 +import com.nokia.extras 1.0 + +import QtRapids 1.0 + +Page { + id: tabbarPage + + property bool busy: Boolean(tabGroup.currentTab.busy) + anchors.margins: rootWindow.pageMargin + + tools: ToolBarLayout { + ToolIcon { iconId: "toolbar-back"; onClicked: pageStack.pop(); } + ButtonRow { + platformStyle: TabButtonStyle { } + TabButton { + text: "Downloads" + tab: downloads + } + TabButton { + text: "Seeds" + tab: seeds + } + } + ToolIcon { iconId: "toolbar-view-menu"; onClicked: (myMenu.status == DialogStatus.Closed) ? myMenu.open() : myMenu.close() } + } +// Text { +// text: "Hello World!" +// font.family: "Helvetica" +// font.pointSize: 24 +// color: "red" +// anchors.fill: parent +// } + + ListView { + width: 200; height: 400 +/* + DownloadListModel { + id: downloadModel + // TODO: Does not work like this. Need properties to set from QML? + // Try setting test data from C++ side and view here.. + /* + ListElement { + Hash: "QMLHASH1" + Size: "Size1" + Status: "DONE1" + } + ListElement { + Hash: "QMLHASH2" + Size: "Size2" + Status: "DONE2" + } + ListElement { + Hash: "QMLHASH3" + Size: "Size3" + Status: "DONE3" + } + } +*/ + Component { + id: downloadDelegate + Item { + height: 40 + width: parent.width + Text { + id: hashText + text: hash + } + Text { + id: nameText + anchors.leftMargin: 10 + anchors.left: hashText.right + text: name + } + Text { + id: seedsText + anchors.leftMargin: 10 + anchors.left: nameText.right + text: seeds + } + Text { + id: leechesText + anchors.leftMargin: 10 + anchors.left: seedsText.right + text: leeches + } + } + } + + // downloadModel is from rootContext, set in main.cpp + model: downloadModel + delegate: downloadDelegate + } + + /* + ListModel { + id: pagesModel + ListElement { + page: "CountBubble.qml" + title: "CountBubble" + subtitle: "Indicates current count" + } + ListElement { + page: "NetPromoterScore.qml" + title: "NetPromoterScore" + subtitle: "Shows net promotion query page" + } + ListElement { + page: "PageIndicator.qml" + title: "PageIndicator" + subtitle: "Indicates total & current pages" + } + ListElement { + page: "RatingIndicator.qml" + title: "RatingIndicator" + subtitle: "Indicates ratings" + } + ListElement { + page: "ListDelegates.qml" + title: "List Delegates" + subtitle: "Various List Delegates" + } + ListElement { + page: "MoreIndicator.qml" + title: "MoreIndicator" + subtitle: "Indicates that there are more contents" + } + ListElement { + page: "StyledButtons.qml" + title: "StyledButtons" + subtitle: "Buttons with different styles" + } + } + ListView { + id: listview + anchors.fill: parent + model: pagesModel + + delegate: ListDelegate { + Image { + source: "image://theme/icon-m-common-drilldown-arrow" + (theme.inverted ? "-inverse" : "") + anchors.right: parent.right; + anchors.verticalCenter: parent.verticalCenter + } + + subtitleColor: "#cc6633" + onClicked: { openFile(model.page); } + } + } +*/ + TabGroup { + id: tabGroup + + currentTab: downloads + + PageStack { + id: downloads + } + PageStack { + id: seeds + } + Page { + id: tab3 + Column { + spacing: 10 + + Text { + text: "This is a single page" + } + } + } + } + +} \ No newline at end of file diff --git a/src/qml-client/qml/SeedView.qml b/src/qml-client/qml/SeedView.qml new file mode 100644 index 0000000..e69de29 diff --git a/src/qml-client/qml/main.qml b/src/qml-client/qml/main.qml new file mode 100644 index 0000000..67383aa --- /dev/null +++ b/src/qml-client/qml/main.qml @@ -0,0 +1,36 @@ + +import QtQuick 1.1 +import com.meego 1.0 + +PageStackWindow { + id: rootWindow + property int pageMargin: 16 + + platformStyle: defaultStyle; + + PageStackWindowStyle { id: defaultStyle } + PageStackWindowStyle { id: customStyle; background: "image://theme/meegotouch-wallpaper-portrait"} + + // ListPage is what we see when the app starts, it links to the component specific pages + initialPage: MainPage { } + + // These tools are shared by most sub-pages by assigning the id to a page's tools property + ToolBarLayout { + id: commonTools + visible: false + ToolIcon { iconId: "toolbar-back"; onClicked: { myMenu.close(); pageStack.pop(); } } + ToolIcon { iconId: "toolbar-view-menu"; onClicked: (myMenu.status == DialogStatus.Closed) ? myMenu.open() : myMenu.close() } + } + + Menu { + id: myMenu + visualParent: pageStack + MenuLayout { + MenuItem {id: b1; text: "Landscape"; onClicked: screen.allowedOrientations = Screen.Landscape} + MenuItem {id: b2; text: "Portrait"; onClicked: screen.allowedOrientations = Screen.Portrait} + MenuItem {id: b3; text: "Item 3"; onClicked: myMenu.accept()} + MenuItem {id: b4; text: "Item 4"; onClicked: myMenu.accept()} + } + } +} + diff --git a/src/qml-client/qml/qml.qrc b/src/qml-client/qml/qml.qrc new file mode 100644 index 0000000..955eecb --- /dev/null +++ b/src/qml-client/qml/qml.qrc @@ -0,0 +1,9 @@ + + + + + main.qml + MainPage.qml + + + \ No newline at end of file -- 1.7.9.5