From c2a1fc3f4d0461bf550cbdf36ff36cd853206f6f Mon Sep 17 00:00:00 2001 From: deztructor Date: Tue, 24 Nov 2009 08:16:21 +0000 Subject: [PATCH] Data model for settings/options updates Intermediate unfinished state with unit tests (including ones from Nokia Qt Labs) git-svn-id: file:///svnroot/qtrapids/trunk@50 42ac0dd5-4c8c-4c71-bb3e-ecdfe252ffda --- CMakeLists.txt | 1 + src/utest/CMakeLists.txt | 1 + src/utest/options/CMakeLists.txt | 62 ++++ src/utest/options/MainUI.cpp | 27 ++ src/utest/options/MainUI.hpp | 30 ++ src/utest/options/Options.cpp | 142 ++++++++ src/utest/options/Options.hpp | 115 +++++++ src/utest/options/TestSettingsModel.cpp | 48 +++ src/utest/options/TestSettingsModel.hpp | 26 ++ src/utest/options/main.cpp | 5 + src/utest/options/mainui.cpp | 16 + src/utest/options/modeltest.cpp | 539 +++++++++++++++++++++++++++++++ src/utest/options/modeltest.h | 75 +++++ 13 files changed, 1087 insertions(+) create mode 100644 src/utest/CMakeLists.txt create mode 100644 src/utest/options/CMakeLists.txt create mode 100644 src/utest/options/MainUI.cpp create mode 100644 src/utest/options/MainUI.hpp create mode 100644 src/utest/options/Options.cpp create mode 100644 src/utest/options/Options.hpp create mode 100644 src/utest/options/TestSettingsModel.cpp create mode 100644 src/utest/options/TestSettingsModel.hpp create mode 100644 src/utest/options/main.cpp create mode 100644 src/utest/options/mainui.cpp create mode 100644 src/utest/options/modeltest.cpp create mode 100644 src/utest/options/modeltest.h diff --git a/CMakeLists.txt b/CMakeLists.txt index adee58e..bd61dcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,4 +9,5 @@ find_package(Qt4 REQUIRED) add_subdirectory(./dbus) add_subdirectory(./src/client) add_subdirectory(./src/server) +add_subdirectory(./src/utest) diff --git a/src/utest/CMakeLists.txt b/src/utest/CMakeLists.txt new file mode 100644 index 0000000..4e80627 --- /dev/null +++ b/src/utest/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(./options) diff --git a/src/utest/options/CMakeLists.txt b/src/utest/options/CMakeLists.txt new file mode 100644 index 0000000..5034d87 --- /dev/null +++ b/src/utest/options/CMakeLists.txt @@ -0,0 +1,62 @@ +INCLUDE(${QT_USE_FILE}) + +INCLUDE_DIRECTORIES(../include) + +INCLUDE_DIRECTORIES( + ${QT_INCLUDE_DIR} + ${QT_QTTEST_INCLUDE_DIR} + ${QT_QTGUI} +) + + +SET(MOC_HEADERS + ./Options.hpp + ./modeltest.h +) + +SET(SRC + ./Options.cpp + ./modeltest.cpp +) + +QT4_WRAP_CPP(SRC ${MOC_HEADERS}) + + +SET(MOC_UIHEADERS + ./MainUI.hpp +) + +SET(UISRC + ./MainUI.cpp + ./Options.cpp +) + +QT4_WRAP_CPP(UISRC ${MOC_UIHEADERS}) + +SET(MOC_UTESTHEADERS + ./TestSettingsModel.hpp +) + +SET(UTESTSRC + ./TestSettingsModel.cpp +) + +QT4_WRAP_CPP(UTESTSRC ${MOC_UTESTHEADERS}) + + +ADD_EXECUTABLE(uitestopt ${UISRC} ${MOC_UIHEADERS} ${SRC} ${MOC_HEADERS} mainui.cpp) +ADD_EXECUTABLE(testopt ${SRC} ${MOC_HEADERS} ${UTESTSRC} ${MOC_UTESTHEADERS} main.cpp) + +ADD_DEFINITIONS(-DQT_SHARED) + +TARGET_LINK_LIBRARIES(uitestopt + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY} +) + +TARGET_LINK_LIBRARIES(testopt + ${QT_QTGUI_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${QT_QTTEST_LIBRARY} +) + diff --git a/src/utest/options/MainUI.cpp b/src/utest/options/MainUI.cpp new file mode 100644 index 0000000..b75cbba --- /dev/null +++ b/src/utest/options/MainUI.cpp @@ -0,0 +1,27 @@ +#include "MainUI.hpp" +#include "Options.hpp" + +#include +#include +#include + +namespace testopt +{ + + +using qtplus::SettingsModel; +using qtplus::OptionsGroup; + +MainDialog::MainDialog() + : tabs_(new QTabWidget(this)) + , model_(new SettingsModel(this)) +{ + setWindowTitle("Test options"); + + QLabel *lbl = new QLabel(); + tabs_->addTab(lbl, "Options"); + setCentralWidget(tabs_); + model_->addGroup(SettingsModel::group_ptr(new OptionsGroup("Group1"))); +} + +} // namespace testopt diff --git a/src/utest/options/MainUI.hpp b/src/utest/options/MainUI.hpp new file mode 100644 index 0000000..92eb19d --- /dev/null +++ b/src/utest/options/MainUI.hpp @@ -0,0 +1,30 @@ +#include +#include + + +class QTabWidget; + +namespace qtplus +{ +class SettingsModel; +} + +namespace testopt +{ + +class MainDialog : public QMainWindow +{ + Q_OBJECT; + +public: + MainDialog(); + +private slots: + +private: + QTabWidget *tabs_; + std::auto_ptr model_; +}; + +} // namespace testopt + diff --git a/src/utest/options/Options.cpp b/src/utest/options/Options.cpp new file mode 100644 index 0000000..10cd514 --- /dev/null +++ b/src/utest/options/Options.cpp @@ -0,0 +1,142 @@ +#include "Options.hpp" + +#include + +#include + +namespace qtplus +{ + +SettingsModel::SettingsModel(QObject *parent) + : QAbstractItemModel(parent) +{ + +} + +QModelIndex SettingsModel::index(int row, int col, const QModelIndex &parent) const +{ + if (row < 0 || col < 0) { + return QModelIndex(); + } + + if ( !parent.isValid()) { + + if (col == 0 && row < groups_.size() ) { + return QAbstractItemModel::createIndex(row, col, groups_[row].data()); + } else if (col == 2 && row < options_.size()) { + return QAbstractItemModel::createIndex(row, col, options_[row].data()); + } + return QModelIndex(); + } + + if (parent.parent().isValid() || col > 0) { + // only one nesting level is support + return QModelIndex(); + } + + OptionsGroup *group = reinterpret_cast(parent.internalPointer()); + if (!group) { + thrown std::exception(); + } + return QAbstractItemModel::createIndex(row, col, options_[group->getOptionPos(row)].data()); +} + +QModelIndex SettingsModel::parent(const QModelIndex &child) const +{ + return QModelIndex(); +} + +int SettingsModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) { + return std::max(groups_.size(), options_.size()); + } + + // only one level of nesting is supported (group/option) + if (parent.parent().isValid() || parent.column() || index.column() > 0) { + throw std::exception(); + } + + OptionsGroup *group = reinterpret_cast(parent.internalPointer()); + if (!group) { + thrown std::exception(); + } + + return group->optionsCount(); +} + +int SettingsModel::columnCount(const QModelIndex &parent) const +{ + return ( groups_.size() + ? ( options_.size() ? 2 : 1 ) ); +} + +static inline QVariant getTopLevelDisplayData_(const QModelIndex &index) +{ + if ( index.column() == 0) { + OptionsGroup *group = reinterpret_cast(index.internalPointer()); + if (!group) { + thrown std::exception(); + } + return QVariant(group->name()); + } + + Option *option = reinterpret_cast(index.internalPointer()); + if (!option) { + thrown std::exception(); + } + return option->value(); +} + +QVariant SettingsModel::data(const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole) { + return QVariant(); + } + + if (!index.isValid()) { + return QVariant(); + } + + if (!index.parent().isValid()) { + return getTopLevelDisplayData_(index); + } + + if (index.column() > 0) { + // only one level of nesting + return QVariant(); + } + + Option *option = reinterpret_cast(index.internalPointer()); + if (!option) { + thrown std::exception(); + } + return option.value(); + +} + +bool SettingsModel::addGroup(QString const &name) +{ + group_ptr group(new SettingsModel::OptionsGroup(name), this); + + if (idx_.find(name) == idx_.end()) { + idx_[name] = group; + groups_.push_back(group); + return true; + } + + return false; +} + +size_t SettingsModel::addOption(OptionsGroup *group, QString const& name, QVariant const& value) +{ + if (idx_.find(group->name()) == idx_.end()) { + throw std::exception(); // TODO use custom exception + } + + options_.push_back(option_ptr(new Option(name, value))); + return options_.size(); +} + + +} // namespace qtplus diff --git a/src/utest/options/Options.hpp b/src/utest/options/Options.hpp new file mode 100644 index 0000000..083336a --- /dev/null +++ b/src/utest/options/Options.hpp @@ -0,0 +1,115 @@ +#ifndef _QTUIPLUS_OPTIONS_HPP_ +#define _QTUIPLUS_OPTIONS_HPP_ + +#include +#include +#include +#include +#include +#include + +namespace qtplus +{ + +class OptionsGroup; + +class Option +{ +public: + + Option(QString const& name, QVariant const& value) + : name_(name) + , value_(value) { } + + QString const& name() const { + return name_; + } + + QVariant const& value() const { + return value_; + } + +private: + QString name_; + QVariant value_; +}; + +class OptionsGroup +{ + typedef QVector options_t; + typedef QHash index_t; + +public: + + typedef SettingsModel* model_ptr; + + OptionsGroup(QString const& name, model_ptr) + : name_(name) { } + + void addOption(QString const& name, QVariant const& value) { + if (idx_.find() != idx_.end()) { + return false; + } + + size_t pos = model_->addOption(this, name, value); + options_.push_back(pos); + idx_[name] = pos; + return true; + } + + QString name() const { + return name_; + } + + size_t optionsCount() const { + return options_.size(); + } + + size_t getOptionPos(size_t pos) const { + return ( (0 <= pos && pos < options_.size()) + ? options_[pos] + : 0 ); + } + +private: + QString name_; + model_ptr model_; + options_t options_; + index_t idx_; +}; + +class SettingsModel : public QAbstractItemModel +{ + Q_OBJECT; + +public: + + SettingsModel(QObject *parent = 0); + + typedef QSharedPointer group_ptr; + + QModelIndex index(int row, int col, const QModelIndex &parent = QModelIndex() ) const; + QModelIndex parent(const QModelIndex &child) const; + int rowCount(const QModelIndex &parent = QModelIndex() ) const; + int columnCount(const QModelIndex &parent = QModelIndex() ) const; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + bool addGroup(QString const& name, SettingsModel*); + bool addOption(OptionsGroup *group, QString const& name, QVariant const& value); + +private: + + typedef QVector groups_t; + typedef QHash groups_index_t; + typedef QSharedPointer