--- /dev/null
+#include "Options.hpp"
+
+#include <QVariant>
+
+#include <algorithm>
+
+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<OptionsGroup*>(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<OptionsGroup*>(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<OptionsGroup*>(index.internalPointer());
+ if (!group) {
+ thrown std::exception();
+ }
+ return QVariant(group->name());
+ }
+
+ Option *option = reinterpret_cast<Option*>(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<Option*>(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