diff --git a/CHANGES b/CHANGES index ad1aa55e8..e219bf3d3 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,9 @@ This release contains contributions from (alphabetically by first name): ## Modules ## - *packages* now reports more details in the installation progress-bar. + - *netinstall* module supports and `expanded` key, which will pre-expand + a group (as if the user had pressed the arrow-button in the tree-view). + This only affects the UI. # 3.2.20 (2020-02-27) # diff --git a/src/calamares/progresstree/ViewStepItem.cpp b/src/calamares/progresstree/ViewStepItem.cpp index 885b81dfc..bbb2846ce 100644 --- a/src/calamares/progresstree/ViewStepItem.cpp +++ b/src/calamares/progresstree/ViewStepItem.cpp @@ -65,9 +65,9 @@ ViewStepItem::data( int role ) const toolTip.append( "
Type:\tViewStep" ); toolTip.append( QString( "
Pretty:\t%1" ).arg( m_step->prettyName() ) ); toolTip.append( QString( "
Status:\t%1" ).arg( m_step->prettyStatus() ) ); - toolTip.append( - QString( "
Source:\t%1" ) - .arg( m_step->moduleInstanceKey().isValid() ? m_step->moduleInstanceKey().toString() : QStringLiteral("built-in") ) ); + toolTip.append( QString( "
Source:\t%1" ) + .arg( m_step->moduleInstanceKey().isValid() ? m_step->moduleInstanceKey().toString() + : QStringLiteral( "built-in" ) ) ); } else { @@ -77,7 +77,9 @@ ViewStepItem::data( int role ) const return toolTip; } if ( role == ProgressTreeModel::ProgressTreeItemCurrentRole ) + { return m_step ? ( Calamares::ViewManager::instance()->currentStep() == m_step ) : ( Calamares::ViewManager::instance()->currentStep() == m_accessor() ); + } return QVariant(); } diff --git a/src/modules/netinstall/NetInstallPage.cpp b/src/modules/netinstall/NetInstallPage.cpp index 735610c3d..352eb9f3e 100644 --- a/src/modules/netinstall/NetInstallPage.cpp +++ b/src/modules/netinstall/NetInstallPage.cpp @@ -154,6 +154,16 @@ NetInstallPage::dataIsHere() ui->groupswidget->header()->setSectionResizeMode( 0, QHeaderView::ResizeToContents ); ui->groupswidget->header()->setSectionResizeMode( 1, QHeaderView::Stretch ); + // Go backwards because expanding a group may cause rows to appear below it + for ( int i = m_groups->rowCount() - 1; i >= 0; --i ) + { + auto index = m_groups->index(i,0); + if ( m_groups->data(index, PackageModel::MetaExpandRole).toBool() ) + { + ui->groupswidget->setExpanded(index, true); + } + } + emit checkReady( true ); } diff --git a/src/modules/netinstall/PackageModel.cpp b/src/modules/netinstall/PackageModel.cpp index 0805a8135..215ac2912 100644 --- a/src/modules/netinstall/PackageModel.cpp +++ b/src/modules/netinstall/PackageModel.cpp @@ -21,9 +21,6 @@ #include "utils/Yaml.h" -// TODO: see headerData(), remove after 3.2.19 -#include - PackageModel::PackageModel( const YAML::Node& data, QObject* parent ) : QAbstractItemModel( parent ) { @@ -120,21 +117,17 @@ PackageModel::data( const QModelIndex& index, int role ) const } PackageTreeItem* item = static_cast< PackageTreeItem* >( index.internalPointer() ); - if ( index.column() == 0 && role == Qt::CheckStateRole ) - { - return item->isSelected(); - } - - if ( item->isHidden() && role == Qt::DisplayRole ) // Hidden group + switch ( role ) { + case Qt::CheckStateRole: + return index.column() == NameColumn ? item->isSelected() : QVariant(); + case Qt::DisplayRole: + return item->isHidden() ? QVariant() : item->data( index.column() ); + case MetaExpandRole: + return item->isHidden() ? false : item->expandOnStart(); + default: return QVariant(); } - - if ( role == Qt::DisplayRole ) - { - return item->data( index.column() ); - } - return QVariant(); } bool @@ -159,7 +152,7 @@ PackageModel::flags( const QModelIndex& index ) const { return Qt::ItemFlags(); } - if ( index.column() == 0 ) + if ( index.column() == NameColumn ) { return Qt::ItemIsUserCheckable | QAbstractItemModel::flags( index ); } @@ -171,12 +164,7 @@ PackageModel::headerData( int section, Qt::Orientation orientation, int role ) c { if ( orientation == Qt::Horizontal && role == Qt::DisplayRole ) { - // Unusual translation call uses the existing translation from the NetInstallPage - // class (now removed). - // - // TODO: after 3.2.19, change this to just tr() and push TX - return ( section == 0 ) ? QCoreApplication::translate( "NetInstallPage", "Name" ) - : QCoreApplication::translate( "NetInstallPage", "Description" ); + return ( section == NameColumn ) ? tr( "Name" ) : tr( "Description" ); } return QVariant(); } @@ -226,6 +214,18 @@ PackageModel::getItemPackages( PackageTreeItem* item ) const return selectedPackages; } +static QString +getString( const YAML::Node& itemDefinition, const char* key ) +{ + return itemDefinition[ key ] ? CalamaresUtils::yamlToVariant( itemDefinition[ key ] ).toString() : QString(); +} + +static bool +getBool( const YAML::Node& itemDefinition, const char* key ) +{ + return itemDefinition[ key ] ? CalamaresUtils::yamlToVariant( itemDefinition[ key ] ).toBool() : false; +} + void PackageModel::setupModelData( const YAML::Node& data, PackageTreeItem* parent ) { @@ -240,41 +240,33 @@ PackageModel::setupModelData( const YAML::Node& data, PackageTreeItem* parent ) 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(); - } + itemData.preScript = getString( itemDefinition, "pre-install" ); + itemData.postScript = getString( itemDefinition, "post-install" ); + itemData.isCritical = getBool( itemDefinition, "critical" ); + itemData.isHidden = getBool( itemDefinition, "hidden" ); + itemData.startExpanded = getBool( itemDefinition, "expanded" ); + PackageTreeItem* item = new PackageTreeItem( itemData, parent ); if ( itemDefinition[ "selected" ] ) - item->setSelected( CalamaresUtils::yamlToVariant( itemDefinition[ "selected" ] ).toBool() ? Qt::Checked - : Qt::Unchecked ); + { + item->setSelected( getBool( itemDefinition, "selected" ) ? 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() ); - } - if ( itemDefinition[ "packages" ] ) + { 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 ); diff --git a/src/modules/netinstall/PackageModel.h b/src/modules/netinstall/PackageModel.h index 25965cb7f..b76a58a42 100644 --- a/src/modules/netinstall/PackageModel.h +++ b/src/modules/netinstall/PackageModel.h @@ -39,6 +39,16 @@ class PackageModel : public QAbstractItemModel public: using PackageItemDataList = QList< PackageTreeItem::ItemData >; + // Names for columns (unused in the code) + static constexpr const int NameColumn = 0; + static constexpr const int DescriptionColumn = 1; + + /* The only interesting roles are DisplayRole (with text depending + * on the column, and MetaExpandRole which tells if an index + * should be initially expanded. + */ + static constexpr const int MetaExpandRole = Qt::UserRole + 1; + explicit PackageModel( const YAML::Node& data, QObject* parent = nullptr ); ~PackageModel() override; diff --git a/src/modules/netinstall/PackageTreeItem.cpp b/src/modules/netinstall/PackageTreeItem.cpp index 59e82a659..7e20d63e1 100644 --- a/src/modules/netinstall/PackageTreeItem.cpp +++ b/src/modules/netinstall/PackageTreeItem.cpp @@ -108,22 +108,27 @@ PackageTreeItem::row() const QVariant PackageTreeItem::data( int column ) const { - if ( packageName() != nullptr ) // package + if ( !packageName().isEmpty() ) // packages have a packagename, groups don't { - if ( !column ) + switch ( column ) { + case 0: return QVariant( packageName() ); + default: + return QVariant(); } - return QVariant(); } - switch ( column ) // group + else { - case 0: - return QVariant( prettyName() ); - case 1: - return QVariant( description() ); - default: - return QVariant(); + switch ( column ) // group + { + case 0: + return QVariant( prettyName() ); + case 1: + return QVariant( description() ); + default: + return QVariant(); + } } } @@ -176,12 +181,6 @@ PackageTreeItem::isHidden() const return m_data.isHidden; } -void -PackageTreeItem::setHidden( bool isHidden ) -{ - m_data.isHidden = isHidden; -} - bool PackageTreeItem::hiddenSelected() const { @@ -212,12 +211,6 @@ PackageTreeItem::isCritical() const return m_data.isCritical; } -void -PackageTreeItem::setCritical( bool isCritical ) -{ - m_data.isCritical = isCritical; -} - Qt::CheckState PackageTreeItem::isSelected() const { diff --git a/src/modules/netinstall/PackageTreeItem.h b/src/modules/netinstall/PackageTreeItem.h index 18a509861..d9c1f9ec2 100644 --- a/src/modules/netinstall/PackageTreeItem.h +++ b/src/modules/netinstall/PackageTreeItem.h @@ -36,6 +36,7 @@ public: QString postScript; bool isCritical = false; bool isHidden = false; + bool startExpanded = false; // Only for groups Qt::CheckState selected = Qt::Unchecked; /** @brief Turns this item into a variant for PackageOperations use @@ -66,10 +67,14 @@ public: QString packageName() const; QString postScript() const; + /** @brief Is this item hidden? + * + * Hidden items (generally only groups) are maintained separately, + * not shown to the user, but do enter into the package-installation process. + */ bool isHidden() const; - void setHidden( bool isHidden ); - /** - * @brief Is this hidden item, considered "selected"? + + /** @brief Is this hidden item, considered "selected"? * * This asserts when called on a non-hidden item. * A hidden item has its own selected state, but really @@ -77,8 +82,20 @@ public: */ bool hiddenSelected() const; + /** @brief Is this group critical? + * + * A critical group must be successfully installed, for the Calamares + * installation to continue. + */ bool isCritical() const; - void setCritical( bool isCritical ); + + /** @brief Is this group expanded on start? + * + * This does not affect installation, only the UI. A group + * that expands on start is shown expanded (not collapsed) + * in the treeview when the page is loaded. + */ + bool expandOnStart() const { return m_data.startExpanded; } Qt::CheckState isSelected() const; void setSelected( Qt::CheckState isSelected ); diff --git a/src/modules/netinstall/README.md b/src/modules/netinstall/README.md index 855754822..a8803edd5 100644 --- a/src/modules/netinstall/README.md +++ b/src/modules/netinstall/README.md @@ -1,16 +1,16 @@ # Netinstall module The netinstall module allows distribution maintainers to ship minimal ISOs with -only a basic set of preinstall packages. At installation time, the user is +only a basic set of preinstalled packages. At installation time, the user is presented with the choice to install groups of packages from a predefined list. -Calamares will then invoke the correct backend to install the packages. +Calamares will then use the *packages* module to install the packages. ## Module Configuration The `netinstall.conf` file is self-describing, and at the very -lease should contain a *groupsUrl* key: +least should contain a *groupsUrl* key: ``` ---- @@ -18,13 +18,13 @@ lease should contain a *groupsUrl* key: ``` The URL must point to a YAML file, the *groups* file. See below for -the format of that groups file. The URL may be a local file. +the format of that groups file. The URL may be a local file (e.g. +scheme `file:///`) or a regular HTTP(s) URL. ## Groups Configuration - Here is a short example -of how the YAML file should look. +Here is a short example of how the YAML file should look. ``` - name: "Group name" @@ -45,9 +45,11 @@ More keys (per group) are supported: - *hidden*: if true, do not show the group on the page. Defaults to false. - *selected*: if true, display the group as selected. Defaults to false. - - critical*: if true, make the installation process fail if installing + - *critical*: if true, make the installation process fail if installing any of the packages in the group fails. Otherwise, just log a warning. Defaults to false. + - *expanded*: if true, the group is shown in an expanded form (that is, + not-collapsed) in the treeview on start. - *subgroups*: if present this follows the same structure as the top level of the YAML file, allowing there to be sub-groups of packages to an arbitary depth