[calamares] Add a model for viewing QVariants directly

main
Adriaan de Groot 6 years ago
parent e31a498c9b
commit 2a3ab4dbe7

@ -6,6 +6,7 @@ set( calamaresSources
CalamaresWindow.cpp
DebugWindow.cpp
VariantModel.cpp
progresstree/ProgressTreeDelegate.cpp
progresstree/ProgressTreeItem.cpp

@ -0,0 +1,234 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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();
}

@ -0,0 +1,74 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef VARIANTMODEL_H
#define VARIANTMODEL_H
#include <QAbstractItemModel>
#include <QVariantMap>
#include <QVector>
/** @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
Loading…
Cancel
Save