From 17dfe02d2826e7bb8154f672599978af66844db4 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 9 Aug 2019 05:53:18 -0400 Subject: [PATCH 1/9] [3rdparty] Remove QJsonModel and support --- 3rdparty/qjsonitem.cpp | 140 ---------------------------- 3rdparty/qjsonitem.h | 46 --------- 3rdparty/qjsonmodel.cpp | 186 ------------------------------------- 3rdparty/qjsonmodel.h | 42 --------- LICENSES/GPLv3+-QJsonModel | 18 ---- 5 files changed, 432 deletions(-) delete mode 100644 3rdparty/qjsonitem.cpp delete mode 100644 3rdparty/qjsonitem.h delete mode 100644 3rdparty/qjsonmodel.cpp delete mode 100644 3rdparty/qjsonmodel.h delete mode 100644 LICENSES/GPLv3+-QJsonModel diff --git a/3rdparty/qjsonitem.cpp b/3rdparty/qjsonitem.cpp deleted file mode 100644 index 6bb1fa4c7..000000000 --- a/3rdparty/qjsonitem.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0+ - * License-Filename: LICENSES/GPLv3+-QJsonModel - */ - -/*********************************************** - Copyright (C) 2014 Schutz Sacha - This file is part of QJsonModel (https://github.com/dridk/QJsonmodel). - - QJsonModel is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - QJsonModel 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 QJsonModel. If not, see . - -**********************************************/ - -#include "qjsonitem.h" - -QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent) - : mParent( parent ) - , mType( QJsonValue::Type::Null ) -{ -} - -QJsonTreeItem::~QJsonTreeItem() -{ - qDeleteAll(mChilds); - -} - -void QJsonTreeItem::appendChild(QJsonTreeItem *item) -{ - mChilds.append(item); -} - -QJsonTreeItem *QJsonTreeItem::child(int row) -{ - return mChilds.value(row); -} - -QJsonTreeItem *QJsonTreeItem::parent() -{ - return mParent; -} - -int QJsonTreeItem::childCount() const -{ - return mChilds.count(); -} - -int QJsonTreeItem::row() const -{ - if (mParent) - return mParent->mChilds.indexOf(const_cast(this)); - - return 0; -} - -void QJsonTreeItem::setKey(const QString &key) -{ - mKey = key; -} - -void QJsonTreeItem::setValue(const QString &value) -{ - mValue = value; -} - -void QJsonTreeItem::setType(const QJsonValue::Type &type) -{ - mType = type; -} - -QString QJsonTreeItem::key() const -{ - return mKey; -} - -QString QJsonTreeItem::value() const -{ - return mValue; -} - -QJsonValue::Type QJsonTreeItem::type() const -{ - return mType; -} - -QJsonTreeItem* QJsonTreeItem::load(const QJsonValue& value, QJsonTreeItem* parent) -{ - - - QJsonTreeItem * rootItem = new QJsonTreeItem(parent); - rootItem->setKey("root"); - - if ( value.isObject()) - { - - //Get all QJsonValue childs - foreach (QString key , value.toObject().keys()){ - QJsonValue v = value.toObject().value(key); - QJsonTreeItem * child = load(v,rootItem); - child->setKey(key); - child->setType(v.type()); - rootItem->appendChild(child); - - } - - } - - else if ( value.isArray()) - { - //Get all QJsonValue childs - int index = 0; - foreach (QJsonValue v , value.toArray()){ - - QJsonTreeItem * child = load(v,rootItem); - child->setKey(QString::number(index)); - child->setType(v.type()); - rootItem->appendChild(child); - ++index; - } - } - else - { - rootItem->setValue(value.toVariant().toString()); - rootItem->setType(value.type()); - } - - return rootItem; -} - diff --git a/3rdparty/qjsonitem.h b/3rdparty/qjsonitem.h deleted file mode 100644 index 137c59000..000000000 --- a/3rdparty/qjsonitem.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0+ - * License-Filename: LICENSES/GPLv3+-QJsonModel - */ - -#ifndef JSONITEM_H -#define JSONITEM_H -#include -#include -#include -#include -class QJsonTreeItem -{ -public: - QJsonTreeItem(QJsonTreeItem * parent = nullptr); - ~QJsonTreeItem(); - void appendChild(QJsonTreeItem * item); - QJsonTreeItem *child(int row); - QJsonTreeItem *parent(); - int childCount() const; - int row() const; - void setKey(const QString& key); - void setValue(const QString& value); - void setType(const QJsonValue::Type& type); - QString key() const; - QString value() const; - QJsonValue::Type type() const; - - - static QJsonTreeItem* load(const QJsonValue& value, QJsonTreeItem * parent = nullptr); - -protected: - - -private: - QString mKey; - QString mValue; - QJsonValue::Type mType; - - QList mChilds; - QJsonTreeItem * mParent; - - -}; - -#endif // JSONITEM_H diff --git a/3rdparty/qjsonmodel.cpp b/3rdparty/qjsonmodel.cpp deleted file mode 100644 index 020d27e42..000000000 --- a/3rdparty/qjsonmodel.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0+ - * License-Filename: LICENSES/GPLv3+-QJsonModel - */ - -/*********************************************** - Copyright (C) 2014 Schutz Sacha - This file is part of QJsonModel (https://github.com/dridk/QJsonmodel). - - QJsonModel is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - QJsonModel 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 QJsonModel. If not, see . - -**********************************************/ - -#include "qjsonmodel.h" -#include -#include -#include -#include -#include -#include - -QJsonModel::QJsonModel(QObject *parent) : - QAbstractItemModel(parent) - , mRootItem( new QJsonTreeItem ) -{ - mHeaders.append("key"); - mHeaders.append("value"); - - -} - -QJsonModel::~QJsonModel() -{ - delete mRootItem; -} - -bool QJsonModel::load(const QString &fileName) -{ - QFile file(fileName); - bool success = false; - if (file.open(QIODevice::ReadOnly)) { - success = load(&file); - file.close(); - } - else success = false; - - return success; -} - -bool QJsonModel::load(QIODevice *device) -{ - return loadJson(device->readAll()); -} - -bool QJsonModel::loadJson(const QByteArray &json) -{ - mDocument = QJsonDocument::fromJson(json); - - if (!mDocument.isNull()) - { - beginResetModel(); - delete mRootItem; - if (mDocument.isArray()) { - mRootItem = QJsonTreeItem::load(QJsonValue(mDocument.array())); - } else { - mRootItem = QJsonTreeItem::load(QJsonValue(mDocument.object())); - } - endResetModel(); - return true; - } - return false; -} - - -QVariant QJsonModel::data(const QModelIndex &index, int role) const -{ - - if (!index.isValid()) - return QVariant(); - - - QJsonTreeItem *item = static_cast(index.internalPointer()); - - - if ((role == Qt::DecorationRole) && (index.column() == 0)){ - - return mTypeIcons.value(item->type()); - } - - - if (role == Qt::DisplayRole) { - - if (index.column() == 0) - return QString("%1").arg(item->key()); - - if (index.column() == 1) - return QString("%1").arg(item->value()); - } - - - - return QVariant(); - -} - -QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (role != Qt::DisplayRole) - return QVariant(); - - if (orientation == Qt::Horizontal) { - - return mHeaders.value(section); - } - else - return QVariant(); -} - -QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) const -{ - if (!hasIndex(row, column, parent)) - return QModelIndex(); - - QJsonTreeItem *parentItem; - - if (!parent.isValid()) - parentItem = mRootItem; - else - parentItem = static_cast(parent.internalPointer()); - - QJsonTreeItem *childItem = parentItem->child(row); - if (childItem) - return createIndex(row, column, childItem); - else - return QModelIndex(); -} - -QModelIndex QJsonModel::parent(const QModelIndex &index) const -{ - if (!index.isValid()) - return QModelIndex(); - - QJsonTreeItem *childItem = static_cast(index.internalPointer()); - QJsonTreeItem *parentItem = childItem->parent(); - - if (parentItem == mRootItem) - return QModelIndex(); - - return createIndex(parentItem->row(), 0, parentItem); -} - -int QJsonModel::rowCount(const QModelIndex &parent) const -{ - QJsonTreeItem *parentItem; - if (parent.column() > 0) - return 0; - - if (!parent.isValid()) - parentItem = mRootItem; - else - parentItem = static_cast(parent.internalPointer()); - - return parentItem->childCount(); -} - -int QJsonModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent) - return 2; -} - -void QJsonModel::setIcon(const QJsonValue::Type &type, const QIcon &icon) -{ - mTypeIcons.insert(type,icon); -} diff --git a/3rdparty/qjsonmodel.h b/3rdparty/qjsonmodel.h deleted file mode 100644 index 32c062ba8..000000000 --- a/3rdparty/qjsonmodel.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0+ - * License-Filename: LICENSES/GPLv3+-QJsonModel - */ - -#ifndef QJSONMODEL_H -#define QJSONMODEL_H - -#include -#include "qjsonitem.h" -#include -#include -#include -class QJsonModel : public QAbstractItemModel -{ - Q_OBJECT -public: - explicit QJsonModel(QObject *parent = nullptr); - ~QJsonModel(); - bool load(const QString& fileName); - bool load(QIODevice * device); - bool loadJson(const QByteArray& json); - QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - QModelIndex index(int row, int column,const QModelIndex &parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex &index) const; - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - void setIcon(const QJsonValue::Type& type, const QIcon& icon); - - - -private: - QJsonTreeItem * mRootItem; - QJsonDocument mDocument; - QStringList mHeaders; - QHash mTypeIcons; - - -}; - -#endif // QJSONMODEL_H diff --git a/LICENSES/GPLv3+-QJsonModel b/LICENSES/GPLv3+-QJsonModel deleted file mode 100644 index 8a8e272c0..000000000 --- a/LICENSES/GPLv3+-QJsonModel +++ /dev/null @@ -1,18 +0,0 @@ -/*********************************************** - Copyright (C) 2014 Schutz Sacha - This file is part of QJsonModel (https://github.com/dridk/QJsonmodel). - - QJsonModel is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - QJsonModel 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 QJsonModel. If not, see . - -**********************************************/ From 695e16bb87ae95313ceed206be98df2fd2b25f00 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 9 Aug 2019 06:21:07 -0400 Subject: [PATCH 2/9] [libcalamaresui] Drop QJsonModel from the library --- src/libcalamaresui/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libcalamaresui/CMakeLists.txt b/src/libcalamaresui/CMakeLists.txt index 04565206e..89a50e2ec 100644 --- a/src/libcalamaresui/CMakeLists.txt +++ b/src/libcalamaresui/CMakeLists.txt @@ -18,9 +18,6 @@ set( calamaresui_SOURCES utils/ImageRegistry.cpp utils/Paste.cpp - ${CMAKE_SOURCE_DIR}/3rdparty/qjsonmodel.cpp - ${CMAKE_SOURCE_DIR}/3rdparty/qjsonitem.cpp - viewpages/BlankViewStep.cpp viewpages/ViewStep.cpp From 419329ee494faeeff16d6ba08baca4ce75d3bc00 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 9 Aug 2019 06:27:13 -0400 Subject: [PATCH 3/9] [libcalamares] Remove friend, add accessor, make includes explicit --- src/libcalamares/GlobalStorage.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libcalamares/GlobalStorage.h b/src/libcalamares/GlobalStorage.h index 6fdb43fa0..b070e23f6 100644 --- a/src/libcalamares/GlobalStorage.h +++ b/src/libcalamares/GlobalStorage.h @@ -22,6 +22,8 @@ #include "CalamaresConfig.h" +#include +#include #include #ifdef WITH_PYTHON @@ -87,13 +89,19 @@ public: /// @brief reads settings from the given filename bool loadYaml( const QString& filename ); + /** @brief Get internal mapping as a constant object + * + * Note that the VariantMap underneath may change, because + * it's not constant in itself. Connect to the changed() + * signal for notifications. + */ + const QVariantMap& data() const { return m; } + signals: void changed(); private: QVariantMap m; - - friend DebugWindow; }; } // namespace Calamares From 85d28af1e20768c8dd99cfa8acd424f6d7bcc3d2 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 9 Aug 2019 06:34:38 -0400 Subject: [PATCH 4/9] [libcalamaresui] Don't include QJsonModel --- src/libcalamaresui/utils/DebugWindow.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libcalamaresui/utils/DebugWindow.cpp b/src/libcalamaresui/utils/DebugWindow.cpp index 094511be4..237b8a7ed 100644 --- a/src/libcalamaresui/utils/DebugWindow.cpp +++ b/src/libcalamaresui/utils/DebugWindow.cpp @@ -30,8 +30,6 @@ #include "utils/Logger.h" #include "utils/Retranslator.h" -#include "3rdparty/qjsonmodel.h" - #ifdef WITH_PYTHONQT #include "ViewManager.h" #include "viewpages/PythonQtViewStep.h" @@ -39,10 +37,10 @@ #include #endif -#include #include #include #include +#include /** * @brief crash makes Calamares crash immediately. From e31a498c9b70abebe50bdeaeec661545eab4bc40 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 9 Aug 2019 06:35:40 -0400 Subject: [PATCH 5/9] [calamares] Move DebugWindow - This is a fairly specialized class, for use only in the whole-application where it ties in with the module system. Move it to the application directory and slim down the UI library. - Include it from the new location. - Add UIC to Calamares (the application) because there's now a designer-based widget in it. --- src/calamares/CMakeLists.txt | 3 +++ src/calamares/CalamaresWindow.cpp | 2 +- src/{libcalamaresui/utils => calamares}/DebugWindow.cpp | 0 src/{libcalamaresui/utils => calamares}/DebugWindow.h | 0 src/{libcalamaresui/utils => calamares}/DebugWindow.ui | 0 src/libcalamaresui/CMakeLists.txt | 6 ------ 6 files changed, 4 insertions(+), 7 deletions(-) rename src/{libcalamaresui/utils => calamares}/DebugWindow.cpp (100%) rename src/{libcalamaresui/utils => calamares}/DebugWindow.h (100%) rename src/{libcalamaresui/utils => calamares}/DebugWindow.ui (100%) diff --git a/src/calamares/CMakeLists.txt b/src/calamares/CMakeLists.txt index 5dbf137bb..92521f17a 100644 --- a/src/calamares/CMakeLists.txt +++ b/src/calamares/CMakeLists.txt @@ -5,6 +5,8 @@ set( calamaresSources CalamaresApplication.cpp CalamaresWindow.cpp + DebugWindow.cpp + progresstree/ProgressTreeDelegate.cpp progresstree/ProgressTreeItem.cpp progresstree/ProgressTreeModel.cpp @@ -35,6 +37,7 @@ set_target_properties(calamares_bin RUNTIME_OUTPUT_NAME calamares ) calamares_automoc( calamares_bin ) +calamares_autouic( calamares_bin ) target_link_libraries( calamares_bin PRIVATE diff --git a/src/calamares/CalamaresWindow.cpp b/src/calamares/CalamaresWindow.cpp index d80b6cb67..68f29ef18 100644 --- a/src/calamares/CalamaresWindow.cpp +++ b/src/calamares/CalamaresWindow.cpp @@ -26,7 +26,7 @@ #include "ViewManager.h" #include "progresstree/ProgressTreeView.h" #include "utils/CalamaresUtilsGui.h" -#include "utils/DebugWindow.h" +#include "DebugWindow.h" #include "utils/Logger.h" #include "utils/Retranslator.h" diff --git a/src/libcalamaresui/utils/DebugWindow.cpp b/src/calamares/DebugWindow.cpp similarity index 100% rename from src/libcalamaresui/utils/DebugWindow.cpp rename to src/calamares/DebugWindow.cpp diff --git a/src/libcalamaresui/utils/DebugWindow.h b/src/calamares/DebugWindow.h similarity index 100% rename from src/libcalamaresui/utils/DebugWindow.h rename to src/calamares/DebugWindow.h diff --git a/src/libcalamaresui/utils/DebugWindow.ui b/src/calamares/DebugWindow.ui similarity index 100% rename from src/libcalamaresui/utils/DebugWindow.ui rename to src/calamares/DebugWindow.ui diff --git a/src/libcalamaresui/CMakeLists.txt b/src/libcalamaresui/CMakeLists.txt index 89a50e2ec..111113a47 100644 --- a/src/libcalamaresui/CMakeLists.txt +++ b/src/libcalamaresui/CMakeLists.txt @@ -14,7 +14,6 @@ set( calamaresui_SOURCES modulesystem/ViewModule.cpp utils/CalamaresUtilsGui.cpp - utils/DebugWindow.cpp utils/ImageRegistry.cpp utils/Paste.cpp @@ -38,10 +37,6 @@ mark_thirdparty_code( ${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp ) -set( calamaresui_UI - utils/DebugWindow.ui -) - if( WITH_PYTHON ) list( APPEND calamaresui_SOURCES modulesystem/PythonJobModule.cpp @@ -69,7 +64,6 @@ endif() calamares_add_library( calamaresui SOURCES ${calamaresui_SOURCES} - UI ${calamaresui_UI} EXPORT_MACRO UIDLLEXPORT_PRO LINK_PRIVATE_LIBRARIES ${OPTIONAL_PYTHON_LIBRARIES} From 2a3ab4dbe768792ac87ec637ffdcfad21cf5ff69 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 9 Aug 2019 07:21:48 -0400 Subject: [PATCH 6/9] [calamares] Add a model for viewing QVariants directly --- src/calamares/CMakeLists.txt | 1 + src/calamares/VariantModel.cpp | 234 +++++++++++++++++++++++++++++++++ src/calamares/VariantModel.h | 74 +++++++++++ 3 files changed, 309 insertions(+) create mode 100644 src/calamares/VariantModel.cpp create mode 100644 src/calamares/VariantModel.h diff --git a/src/calamares/CMakeLists.txt b/src/calamares/CMakeLists.txt index 92521f17a..259e3bf56 100644 --- a/src/calamares/CMakeLists.txt +++ b/src/calamares/CMakeLists.txt @@ -6,6 +6,7 @@ set( calamaresSources CalamaresWindow.cpp DebugWindow.cpp + VariantModel.cpp progresstree/ProgressTreeDelegate.cpp progresstree/ProgressTreeItem.cpp diff --git a/src/calamares/VariantModel.cpp b/src/calamares/VariantModel.cpp new file mode 100644 index 000000000..bdcf8f75c --- /dev/null +++ b/src/calamares/VariantModel.cpp @@ -0,0 +1,234 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares 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 Calamares. If not, see . + */ + +#include "VariantModel.h" + +static void +overallLength( const QVariant& item, int& c, int parent, VariantModel::IndexVector* skiplist ) +{ + if ( skiplist ) + { + skiplist->append( parent ); + } + + parent = c++; + if ( item.canConvert< QVariantList >() ) + { + for ( const auto& subitem : item.toList() ) + { + overallLength( subitem, c, parent, skiplist ); + } + } + else if ( item.canConvert< QVariantMap >() ) + { + for ( const auto& subitem : item.toMap() ) + { + overallLength( subitem, c, parent, skiplist ); + } + } +} + +static quintptr +findNth( const VariantModel::IndexVector& skiplist, quintptr value, int n ) +{ + if ( n < 0 ) + { + return -1; + } + + int index = 0; + while ( ( n >= 0 ) && ( index < skiplist.count() ) ) + { + if ( skiplist[ index ] == value ) + { + if ( --n < 0 ) + { + return index; + } + } + index++; + } + return -1; +} + + +VariantModel::VariantModel( const QVariant* p ) + : m_p( p ) +{ + int x = 0; + overallLength( *p, x, -1, nullptr ); + m_rows.reserve( x ); + x = 0; + overallLength( *p, x, -1, &m_rows ); +} + +VariantModel::~VariantModel() {} + +int +VariantModel::columnCount( const QModelIndex& index ) const +{ + return 2; +} + +int +VariantModel::rowCount( const QModelIndex& index ) const +{ + quintptr p = index.isValid() ? index.internalId() : 0; + return m_rows.count( p ); +} + +QModelIndex +VariantModel::index( int row, int column, const QModelIndex& parent ) const +{ + quintptr p = 0; + + if ( parent.isValid() ) + { + if ( !( parent.internalId() >= m_rows.count() ) ) + { + p = parent.internalId(); + } + } + + return createIndex( row, column, findNth( m_rows, p, row ) ); +} + +QModelIndex +VariantModel::parent( const QModelIndex& index ) const +{ + if ( !index.isValid() || ( index.internalId() > m_rows.count() ) ) + { + return QModelIndex(); + } + + quintptr p = m_rows[ index.internalId() ]; + if ( p == 0 ) + { + return QModelIndex(); + } + + if ( p >= m_rows.count() ) + { + return QModelIndex(); + } + quintptr p_pid = m_rows[ p ]; + int row = 0; + for ( int i = 0; i < p; ++i ) + { + if ( m_rows[ i ] == p_pid ) + { + row++; + } + } + + return createIndex( row, index.column(), p ); +} + +QVariant +VariantModel::data( const QModelIndex& index, int role ) const +{ + if ( role != Qt::DisplayRole ) + { + return QVariant(); + } + + if ( !index.isValid() ) + { + return QVariant(); + } + + if ( ( index.column() < 0 ) || ( index.column() > 1 ) ) + { + return QVariant(); + } + + if ( index.internalId() >= m_rows.count() ) + { + return QVariant(); + } + + const QVariant thing = underlying( parent( index ) ); + + if ( !thing.isValid() ) + { + return QVariant(); + } + + if ( thing.canConvert< QVariantMap >() ) + { + QVariantMap the_map = thing.toMap(); + const auto key = the_map.keys().at( index.row() ); + if ( index.column() == 0 ) + { + return key; + } + else + { + return the_map[ key ]; + } + } + else if ( thing.canConvert< QVariantList >() ) + { + if ( index.column() == 0 ) + { + return index.row(); + } + else + { + QVariantList the_list = thing.toList(); + return the_list.at( index.row() ); + } + } + else + { + if ( index.column() == 0 ) + { + return QVariant(); + } + else + { + return thing; + } + } +} + +const QVariant +VariantModel::underlying( const QModelIndex& index ) const +{ + if ( !index.isValid() ) + { + return *m_p; + } + + const auto& thing = underlying( parent( index ) ); + if ( thing.canConvert< QVariantMap >() ) + { + const auto& the_map = thing.toMap(); + return the_map[ the_map.keys()[ index.row() ] ]; + } + else if ( thing.canConvert< QVariantList >() ) + { + return thing.toList()[ index.row() ]; + } + else + { + return thing; + } + + return QVariant(); +} diff --git a/src/calamares/VariantModel.h b/src/calamares/VariantModel.h new file mode 100644 index 000000000..9ea6f6737 --- /dev/null +++ b/src/calamares/VariantModel.h @@ -0,0 +1,74 @@ +/* === This file is part of Calamares - === + * + * Copyright 2019, Adriaan de Groot + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares 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 Calamares. If not, see . + */ + +#ifndef VARIANTMODEL_H +#define VARIANTMODEL_H + +#include +#include +#include + +/** @brief A model that operates directly on a QVariant + * + * A VariantModel operates directly on an underlying + * QVariant, treating QVariantMap and QVariantList as + * nodes with multiple children. In general, putting + * a QVariantMap into a QVariant and passing that into + * the model will get you a tree-like model of the + * VariantMap's data structure. + * + * Take care of object lifetimes and that the underlying + * QVariant does not change during use. + */ +class VariantModel : public QAbstractItemModel +{ +public: + /** @brief Auxiliary data + * + * The nodes of the tree are enumerated into a vector + * (of length equal to the number of nodes in the tree + 1) + * which are used to do index and parent calculations. + */ + using IndexVector = QVector< quintptr >; + + /** @brief Constructor + * + * The QVariant's lifetime is **not** affected by the model, + * so take care that the QVariant lives at least as long as + * the model). Also, don't change the QVariant underneath the model. + */ + VariantModel( const QVariant* p ); + + ~VariantModel() override; + + int columnCount( const QModelIndex& index ) const override; + int rowCount( const QModelIndex& index ) const override; + + QModelIndex index( int row, int column, const QModelIndex& parent ) const override; + QModelIndex parent( const QModelIndex& index ) const override; + QVariant data( const QModelIndex& index, int role ) const override; + +private: + const QVariant* const m_p; + IndexVector m_rows; + + /// @brief Implementation of walking an index through the variant-tree + const QVariant underlying( const QModelIndex& index ) const; +}; + +#endif From 2bd03ad3c09129c7b078e73193c10d20cddfa891 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 9 Aug 2019 07:40:23 -0400 Subject: [PATCH 7/9] [calamares] Add reload() to update model after underlying data --- src/calamares/VariantModel.cpp | 16 +++++++++++----- src/calamares/VariantModel.h | 11 ++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/calamares/VariantModel.cpp b/src/calamares/VariantModel.cpp index bdcf8f75c..fc11794bc 100644 --- a/src/calamares/VariantModel.cpp +++ b/src/calamares/VariantModel.cpp @@ -70,15 +70,21 @@ findNth( const VariantModel::IndexVector& skiplist, quintptr value, int n ) VariantModel::VariantModel( const QVariant* p ) : m_p( p ) { - int x = 0; - overallLength( *p, x, -1, nullptr ); - m_rows.reserve( x ); - x = 0; - overallLength( *p, x, -1, &m_rows ); + reload(); } VariantModel::~VariantModel() {} +void VariantModel::reload() +{ + int x = 0; + overallLength( *m_p, x, -1, nullptr ); + m_rows.clear(); // Start over + m_rows.reserve( x ); // We'll need this much + x = 0; + overallLength( *m_p, x, -1, &m_rows ); +} + int VariantModel::columnCount( const QModelIndex& index ) const { diff --git a/src/calamares/VariantModel.h b/src/calamares/VariantModel.h index 9ea6f6737..b0c93e91c 100644 --- a/src/calamares/VariantModel.h +++ b/src/calamares/VariantModel.h @@ -33,7 +33,9 @@ * VariantMap's data structure. * * Take care of object lifetimes and that the underlying - * QVariant does not change during use. + * QVariant does not change during use. If the QVariant + * **does** change, call reload() to re-build the internal + * representation of the tree. */ class VariantModel : public QAbstractItemModel { @@ -56,6 +58,13 @@ public: ~VariantModel() override; + /** @brief Re-build the internal tree + * + * Call this when the underlying variant is changed, which + * might impact how the tree is laid out. + */ + void reload(); + int columnCount( const QModelIndex& index ) const override; int rowCount( const QModelIndex& index ) const override; From eba4dc8df131d247c05395d56ceb5081ddcf3f0e Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 9 Aug 2019 07:48:52 -0400 Subject: [PATCH 8/9] [calamares] Use VariantModel instead of QJsonModel - Drop the round-trip of forming a JSON document from a QVariant, then parsing the document into JSON objects and building a model out of that. View the Variant directly. --- src/calamares/DebugWindow.cpp | 30 +++++++++++++++++------------- src/calamares/DebugWindow.h | 8 ++++++++ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/calamares/DebugWindow.cpp b/src/calamares/DebugWindow.cpp index 237b8a7ed..1680fb7de 100644 --- a/src/calamares/DebugWindow.cpp +++ b/src/calamares/DebugWindow.cpp @@ -20,6 +20,8 @@ #include "DebugWindow.h" #include "ui_DebugWindow.h" +#include "VariantModel.h" + #include "Branding.h" #include "modulesystem/Module.h" #include "modulesystem/ModuleManager.h" @@ -72,23 +74,25 @@ namespace Calamares { DebugWindow::DebugWindow() : QWidget( nullptr ) , m_ui( new Ui::DebugWindow ) + , m_globals( JobQueue::instance()->globalStorage()->data() ) + , m_globals_model( std::make_unique< VariantModel >( &m_globals ) ) + , m_module_model( std::make_unique< VariantModel >( &m_module ) ) { - m_ui->setupUi( this ); - - // GlobalStorage page - QJsonModel* jsonModel = new QJsonModel( this ); - - m_ui->globalStorageView->setModel( jsonModel ); GlobalStorage* gs = JobQueue::instance()->globalStorage(); + m_ui->setupUi( this ); + + m_ui->globalStorageView->setModel( m_globals_model.get() ); + m_ui->globalStorageView->expandAll(); + + // Do above when the GS changes, too connect( gs, &GlobalStorage::changed, this, [ = ] { - jsonModel->loadJson( QJsonDocument::fromVariant( gs->m ).toJson() ); + m_globals = JobQueue::instance()->globalStorage()->data(); + m_globals_model->reload(); m_ui->globalStorageView->expandAll(); } ); - jsonModel->loadJson( QJsonDocument::fromVariant( gs->m ).toJson() ); - m_ui->globalStorageView->expandAll(); // JobQueue page m_ui->jobQueueText->setReadOnly( true ); @@ -109,8 +113,7 @@ DebugWindow::DebugWindow() m_ui->modulesListView->setModel( modulesModel ); m_ui->modulesListView->setSelectionMode( QAbstractItemView::SingleSelection ); - QJsonModel* moduleConfigModel = new QJsonModel( this ); - m_ui->moduleConfigView->setModel( moduleConfigModel ); + m_ui->moduleConfigView->setModel( m_module_model.get() ); #ifdef WITH_PYTHONQT QPushButton* pythonConsoleButton = new QPushButton; @@ -181,7 +184,7 @@ DebugWindow::DebugWindow() #endif connect( m_ui->modulesListView->selectionModel(), &QItemSelectionModel::selectionChanged, - this, [ this, moduleConfigModel + this, [ this #ifdef WITH_PYTHONQT , pythonConsoleButton #endif @@ -191,7 +194,8 @@ DebugWindow::DebugWindow() Module* module = ModuleManager::instance()->moduleInstance( moduleName ); if ( module ) { - moduleConfigModel->loadJson( QJsonDocument::fromVariant( module->configurationMap() ).toJson() ); + m_module = module->configurationMap(); + m_module_model->reload(); m_ui->moduleConfigView->expandAll(); m_ui->moduleTypeLabel->setText( module->typeString() ); m_ui->moduleInterfaceLabel->setText( module->interfaceString() ); diff --git a/src/calamares/DebugWindow.h b/src/calamares/DebugWindow.h index e97f5727b..1a121455e 100644 --- a/src/calamares/DebugWindow.h +++ b/src/calamares/DebugWindow.h @@ -20,8 +20,12 @@ #ifndef CALAMARES_DEBUGWINDOW_H #define CALAMARES_DEBUGWINDOW_H +#include "VariantModel.h" + +#include #include +#include namespace Calamares { @@ -46,6 +50,10 @@ protected: private: Ui::DebugWindow *m_ui; + QVariant m_globals; + QVariant m_module; + std::unique_ptr< VariantModel> m_globals_model; + std::unique_ptr< VariantModel> m_module_model; }; From ab7a559e03476ff98b4bbd61a8a96d1dbd3bdeeb Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 9 Aug 2019 07:58:20 -0400 Subject: [PATCH 9/9] [calamares] Add headerData to model (Key, Value columns) --- src/calamares/VariantModel.cpp | 32 +++++++++++++++++++++++++++++++- src/calamares/VariantModel.h | 1 + 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/calamares/VariantModel.cpp b/src/calamares/VariantModel.cpp index fc11794bc..965f0f3e0 100644 --- a/src/calamares/VariantModel.cpp +++ b/src/calamares/VariantModel.cpp @@ -75,7 +75,8 @@ VariantModel::VariantModel( const QVariant* p ) VariantModel::~VariantModel() {} -void VariantModel::reload() +void +VariantModel::reload() { int x = 0; overallLength( *m_p, x, -1, nullptr ); @@ -213,6 +214,35 @@ VariantModel::data( const QModelIndex& index, int role ) const } } +QVariant +VariantModel::headerData( int section, Qt::Orientation orientation, int role ) const +{ + if ( role != Qt::DisplayRole ) + { + return QVariant(); + } + + if ( orientation == Qt::Horizontal ) + { + if ( section == 0 ) + { + return tr( "Key" ); + } + else if ( section == 1 ) + { + return tr( "Value" ); + } + else + { + return QVariant(); + } + } + else + { + return QVariant(); + } +} + const QVariant VariantModel::underlying( const QModelIndex& index ) const { diff --git a/src/calamares/VariantModel.h b/src/calamares/VariantModel.h index b0c93e91c..9c4256f6a 100644 --- a/src/calamares/VariantModel.h +++ b/src/calamares/VariantModel.h @@ -71,6 +71,7 @@ public: QModelIndex index( int row, int column, const QModelIndex& parent ) const override; QModelIndex parent( const QModelIndex& index ) const override; QVariant data( const QModelIndex& index, int role ) const override; + QVariant headerData( int section, Qt::Orientation orientation, int role ) const override; private: const QVariant* const m_p;