From 77b839748f9058e649513742a173eb73a72c104a Mon Sep 17 00:00:00 2001 From: Philip Date: Mon, 23 Jan 2017 17:41:30 +0100 Subject: [PATCH] [netinstall] add new files --- src/modules/netinstall/PackageModel.cpp | 260 +++++++++++++++++++++ src/modules/netinstall/PackageModel.h | 64 +++++ src/modules/netinstall/PackageTreeItem.cpp | 203 ++++++++++++++++ src/modules/netinstall/PackageTreeItem.h | 80 +++++++ 4 files changed, 607 insertions(+) create mode 100644 src/modules/netinstall/PackageModel.cpp create mode 100644 src/modules/netinstall/PackageModel.h create mode 100644 src/modules/netinstall/PackageTreeItem.cpp create mode 100644 src/modules/netinstall/PackageTreeItem.h diff --git a/src/modules/netinstall/PackageModel.cpp b/src/modules/netinstall/PackageModel.cpp new file mode 100644 index 000000000..e35f21d9d --- /dev/null +++ b/src/modules/netinstall/PackageModel.cpp @@ -0,0 +1,260 @@ +/* === This file is part of Calamares - === + * + * Copyright (c) 2017, Kyle Robbertze + * + * 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 "PackageModel.h" + +#include "utils/Logger.h" +#include "utils/YamlUtils.h" + +#include + +PackageModel::PackageModel( const YAML::Node& data, const QVariantList& columnHeadings, + QObject* parent ) : + QAbstractItemModel( parent ), + m_columnHeadings( columnHeadings ) +{ + QVariantList rootData; + m_rootItem = new PackageTreeItem( ); + setupModelData( data, m_rootItem ); +} + +PackageModel::~PackageModel() +{ + delete m_rootItem; +} + +QModelIndex +PackageModel::index( int row, int column, const QModelIndex& parent ) const +{ + if ( !hasIndex( row, column, parent ) ) + return QModelIndex(); + + PackageTreeItem* parentItem; + + if ( !parent.isValid() ) + parentItem = m_rootItem; + else + parentItem = static_cast( parent.internalPointer() ); + + PackageTreeItem* childItem = parentItem->child( row ); + if ( childItem ) + return createIndex( row, column, childItem ); + else + return QModelIndex(); +} + +QModelIndex +PackageModel::parent( const QModelIndex& index ) const +{ + if ( !index.isValid() ) + return QModelIndex(); + + PackageTreeItem* child = static_cast( index.internalPointer() ); + PackageTreeItem* parent = child->parentItem(); + + if ( parent == m_rootItem ) + return QModelIndex(); + return createIndex( parent->row(), 0, parent ); +} + +int +PackageModel::rowCount( const QModelIndex& parent ) const +{ + if ( parent.column() > 0 ) + return 0; + + PackageTreeItem* parentItem; + if ( !parent.isValid() ) + parentItem = m_rootItem; + else + parentItem = static_cast( parent.internalPointer() ); + + return parentItem->childCount(); +} + +int +PackageModel::columnCount( const QModelIndex& parent ) const +{ + if ( parent.isValid() ) + return static_cast( parent.internalPointer() )->columnCount(); + return m_rootItem->columnCount(); +} + +QVariant +PackageModel::data( const QModelIndex& index, int role ) const +{ + if ( !index.isValid() ) + return QVariant(); + PackageTreeItem* item = static_cast( index.internalPointer() ); + if ( index.column() == 0 && role == Qt::CheckStateRole ) + return item->isSelected(); + + if ( !item->childCount() ) // package + { + if ( !item->parentItem()->isHidden() && role == Qt::DisplayRole && + index.column() == 0 ) + return QVariant( item->packageName() ); + else if ( role == PackageTreeItem::PackageNameRole ) + return QVariant( item->packageName() ); + else + return QVariant(); + } + + if ( item->isHidden() && role == Qt::DisplayRole ) // Hidden group + return QVariant(); + + switch ( role ) + { + case Qt::DisplayRole: + return item->data( index.column() ); + case PackageTreeItem::PreScriptRole: + return QVariant( item->preScript() ); + case PackageTreeItem::PackageNameRole: + return QVariant( item->packageName() ); + case PackageTreeItem::PostScriptRole: + return QVariant( item->postScript() ); + default: + return QVariant(); + } +} + +bool +PackageModel::setData( const QModelIndex& index, const QVariant& value, int role ) +{ + if ( role == Qt::CheckStateRole && index.isValid() ) + { + PackageTreeItem* item = static_cast( index.internalPointer() ); + item->setSelected( static_cast( value.toInt() ) ); + + emit dataChanged( this->index( 0, 0 ), index.sibling( index.column(), index.row() + 1 ), + QVector( Qt::CheckStateRole ) ); + } + return true; +} + +Qt::ItemFlags +PackageModel::flags( const QModelIndex& index ) const +{ + if ( !index.isValid() ) + return 0; + if ( index.column() == 0 ) + return Qt::ItemIsUserCheckable | QAbstractItemModel::flags( index ); + return QAbstractItemModel::flags( index ); +} + +QVariant +PackageModel::headerData( int section, Qt::Orientation orientation, int role ) const +{ + if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) + return m_columnHeadings.value( section ); + return QVariant(); +} + +QList +PackageModel::getPackages( bool isCritical ) const +{ + QList items = getItemPackages( m_rootItem, isCritical ); + for ( auto package : m_hiddenItems ) + items.append( getItemPackages( package, isCritical ) ); + QList packages; + for ( auto item : items ) + { + QMap itemMap; + itemMap.insert( "pre-script", item->parentItem()->preScript() ); // Only groups have hooks + itemMap.insert( "package", item->packageName() ); + itemMap.insert( "post-script", item->parentItem()->postScript() ); + packages.append( QVariant( itemMap ) ); + } + return packages; +} + +QList +PackageModel::getItemPackages( PackageTreeItem* item, bool isCritical ) const +{ + QList selectedPackages; + for ( int i = 0; i < item->childCount(); i++ ) + { + if ( item->child( i )->isSelected() == Qt::Unchecked || + item->child( i )->isCritical() != isCritical ) + continue; + + if ( !item->child( i )->childCount() ) // package + selectedPackages.append( item->child( i ) ); + else + selectedPackages.append( getItemPackages( item->child( i ), isCritical ) ); + } + return selectedPackages; + +} + +void +PackageModel::setupModelData( const YAML::Node& data, PackageTreeItem* parent ) +{ + for ( YAML::const_iterator it = data.begin(); it != data.end(); ++it ) + { + const YAML::Node itemDefinition = *it; + + QString name( + tr( CalamaresUtils::yamlToVariant( itemDefinition["name"] ).toByteArray() ) ); + QString description( + tr( CalamaresUtils::yamlToVariant( itemDefinition["description"] ).toByteArray() ) ); + + PackageTreeItem::ItemData itemData; + itemData.name = name; + itemData.description = description; + + if ( itemDefinition["pre-install"] ) + itemData.preScript = + CalamaresUtils::yamlToVariant( itemDefinition["pre-install"] ).toString(); + if ( itemDefinition["post-install"] ) + itemData.postScript = + CalamaresUtils::yamlToVariant( itemDefinition["post-install"] ).toString(); + PackageTreeItem* item = new PackageTreeItem( itemData, parent ); + + if ( itemDefinition["selected"] ) + item->setSelected( + CalamaresUtils::yamlToVariant( itemDefinition["selected"] ).toBool() ? + Qt::Checked : Qt::Unchecked ); + else + item->setSelected( parent->isSelected() ); // Inherit from it's parent + + if ( itemDefinition["hidden"] ) + item->setHidden( + CalamaresUtils::yamlToVariant( itemDefinition["hidden"] ).toBool() ); + + if ( itemDefinition["critical"] ) + item->setCritical( + CalamaresUtils::yamlToVariant( itemDefinition["critical"] ).toBool() ); + + for ( YAML::const_iterator packageIt = itemDefinition["packages"].begin(); + packageIt != itemDefinition["packages"].end(); ++packageIt ) + item->appendChild( + new PackageTreeItem( CalamaresUtils::yamlToVariant( *packageIt ).toString(), item ) ); + + if ( itemDefinition["subgroups"] ) + setupModelData( itemDefinition["subgroups"], item ); + + if ( item->isHidden() ) + m_hiddenItems.append( item ); + else + { + item->setCheckable( true ); + parent->appendChild( item ); + } + } +} diff --git a/src/modules/netinstall/PackageModel.h b/src/modules/netinstall/PackageModel.h new file mode 100644 index 000000000..174a3ae80 --- /dev/null +++ b/src/modules/netinstall/PackageModel.h @@ -0,0 +1,64 @@ +/* === This file is part of Calamares - === + * + * Copyright (c) 2017, Kyle Robbertze + * + * 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 PACKAGEMODEL_H +#define PACKAGEMODEL_H + +#include "PackageTreeItem.h" + +#include +#include +#include + +#include + +// Required forward declarations +class PackageTreeItem; + +class PackageModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + explicit PackageModel( const YAML::Node& data, const QVariantList& columnHeadings, + QObject* parent = 0 ); + ~PackageModel(); + + QVariant data( const QModelIndex& index, int role ) const Q_DECL_OVERRIDE; + bool setData( const QModelIndex& index, const QVariant& value, + int role = Qt::EditRole ) Q_DECL_OVERRIDE; + Qt::ItemFlags flags( const QModelIndex& index ) const Q_DECL_OVERRIDE; + QVariant headerData( int section, Qt::Orientation orientation, + int role = Qt::DisplayRole ) const Q_DECL_OVERRIDE; + QModelIndex index( int row, int column, + const QModelIndex& parent = QModelIndex() ) const Q_DECL_OVERRIDE; + QModelIndex parent( const QModelIndex& index ) const Q_DECL_OVERRIDE; + int rowCount( const QModelIndex& parent = QModelIndex() ) const Q_DECL_OVERRIDE; + int columnCount( const QModelIndex& parent = QModelIndex() ) const Q_DECL_OVERRIDE; + QList getPackages( bool isCritical ) const; + QList getItemPackages( PackageTreeItem* item, bool isCritical ) const; + +private: + void setupModelData( const YAML::Node& data, PackageTreeItem* parent ); + + PackageTreeItem* m_rootItem; + QList m_hiddenItems; + QVariantList m_columnHeadings; +}; + +#endif // PACKAGEMODEL_H diff --git a/src/modules/netinstall/PackageTreeItem.cpp b/src/modules/netinstall/PackageTreeItem.cpp new file mode 100644 index 000000000..93e1d317c --- /dev/null +++ b/src/modules/netinstall/PackageTreeItem.cpp @@ -0,0 +1,203 @@ +/* === This file is part of Calamares - === + * + * Copyright (c) 2017, Kyle Robbertze + * + * 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 "PackageTreeItem.h" + +#include "utils/Logger.h" // TODO:Remove + +PackageTreeItem::PackageTreeItem( const ItemData& data, PackageTreeItem* parent ) : + m_data( data ), + m_parentItem( parent ) +{ } + +PackageTreeItem::PackageTreeItem( const QString packageName, PackageTreeItem* parent ) : + m_packageName( packageName ), + m_parentItem( parent ), + m_selected( parent->isSelected() ) +{ } + +PackageTreeItem::PackageTreeItem( PackageTreeItem* parent ) : + m_parentItem( parent ) +{ } + +PackageTreeItem::~PackageTreeItem() +{ + qDeleteAll( m_childItems ); +} + +void +PackageTreeItem::appendChild( PackageTreeItem* child ) +{ + m_childItems.append( child ); +} + +PackageTreeItem* +PackageTreeItem::child( int row ) +{ + return m_childItems.value( row ); +} + +int +PackageTreeItem::childCount() const +{ + return m_childItems.count(); +} + +int +PackageTreeItem::row() const +{ + if ( m_parentItem ) + return m_parentItem->m_childItems.indexOf( const_cast( this ) ); + return 0; +} + +int +PackageTreeItem::columnCount() const +{ + return m_columns; +} + +QVariant +PackageTreeItem::data( int column ) const +{ + if ( m_packageName != nullptr ) // package + { + if ( column == 1 ) + return QVariant( packageName() ); + return QVariant(); + } + switch ( column ) // group + { + case 0: + return QVariant( prettyName() ); + case 1: + return QVariant( description() ); + default: + return QVariant(); + } +} + +PackageTreeItem* +PackageTreeItem::parentItem() +{ + return m_parentItem; +} + +QString +PackageTreeItem::prettyName() const +{ + return m_data.name; +} + +QString +PackageTreeItem::description() const +{ + return m_data.description; +} + +QString +PackageTreeItem::preScript() const +{ + return m_data.preScript; +} + +QString +PackageTreeItem::packageName() const +{ + return m_packageName; +} + +QString +PackageTreeItem::postScript() const +{ + return m_data.postScript; +} + +bool +PackageTreeItem::isHidden() const +{ + return m_hidden; +} + +void +PackageTreeItem::setHidden( bool isHidden ) +{ + m_hidden = isHidden; +} + +bool +PackageTreeItem::isCritical() const +{ + return m_critical; +} + +void +PackageTreeItem::setCritical( bool isCritical ) +{ + m_critical = isCritical; +} + +Qt::CheckState +PackageTreeItem::isSelected() const +{ + return m_selected; +} + +void +PackageTreeItem::setSelected( Qt::CheckState isSelected ) +{ + m_selected = isSelected; + setChildrenSelected( isSelected ); + PackageTreeItem* currentItem = parentItem(); + while ( currentItem != nullptr ) + { + int childrenSelected = 0; + bool isChildPartiallySelected = false; + for ( int i = 0; i < currentItem->childCount(); i++ ) + { + if ( currentItem->child( i )->isSelected() == Qt::Checked ) + childrenSelected++; + if ( currentItem->child( i )->isSelected() == Qt::PartiallyChecked ) + isChildPartiallySelected = true; + } + if ( !childrenSelected && !isChildPartiallySelected ) + currentItem->m_selected = Qt::Unchecked; + else if ( childrenSelected == currentItem->childCount() ) + currentItem->m_selected = Qt::Checked; + else + currentItem->m_selected = Qt::PartiallyChecked; + currentItem = currentItem->parentItem(); + } +} + +void +PackageTreeItem::setChildrenSelected( Qt::CheckState isSelected ) +{ + if ( isSelected != Qt::PartiallyChecked ) + for ( auto child : m_childItems ) + { + child->m_selected = isSelected; + child->setChildrenSelected( isSelected ); + } +} + +int +PackageTreeItem::type() const +{ + return QStandardItem::UserType; +} diff --git a/src/modules/netinstall/PackageTreeItem.h b/src/modules/netinstall/PackageTreeItem.h new file mode 100644 index 000000000..d4480ec20 --- /dev/null +++ b/src/modules/netinstall/PackageTreeItem.h @@ -0,0 +1,80 @@ +/* === This file is part of Calamares - === + * + * Copyright (c) 2017, Kyle Robbertze + * + * 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 PACKAGETREEITEM_H +#define PACKAGETREEITEM_H + +#include "NetInstallPage.h" + +#include +#include +#include + +class PackageTreeItem : public QStandardItem +{ +public: + struct ItemData + { + QString name; + QString description; + QString preScript; + QString postScript; + }; + explicit PackageTreeItem( const ItemData& data, PackageTreeItem* parent = 0 ); + explicit PackageTreeItem( const QString packageName, PackageTreeItem* parent = 0 ); + explicit PackageTreeItem( PackageTreeItem* parent = 0 ); + ~PackageTreeItem(); + + void appendChild( PackageTreeItem* child ); + PackageTreeItem* child( int row ); + int childCount() const; + int columnCount() const; + QVariant data( int column ) const Q_DECL_OVERRIDE; + int row() const; + PackageTreeItem* parentItem(); + QString prettyName() const; + QString description() const; + QString preScript() const; + QString packageName() const; + QString postScript() const; + bool isHidden() const; + void setHidden( bool isHidden ); + bool isCritical() const; + void setCritical( bool isCritical ); + Qt::CheckState isSelected() const; + void setSelected( Qt::CheckState isSelected ); + void setChildrenSelected( Qt::CheckState isSelected ); + int type() const Q_DECL_OVERRIDE; + + static const int PreScriptRole = Qt::UserRole; + static const int PackageNameRole = Qt::UserRole + 1; + static const int PostScriptRole = Qt::UserRole + 2; +private: + QList m_childItems; + ItemData m_data; + QString m_packageName; + + // See README.md for a description of these two fields. + Qt::CheckState m_selected = Qt::Unchecked; + bool m_hidden = false; + bool m_critical = false; + const int m_columns = 2; // Name, description + PackageTreeItem* m_parentItem; +}; + +#endif // PACKAGETREEITEM_H