commit
bac1108781
@ -174,6 +174,22 @@ struct NamedEnumTable
|
||||
return table.begin()->second;
|
||||
}
|
||||
|
||||
/** @brief Find a name @p s in the table.
|
||||
*
|
||||
* Searches case-insensitively.
|
||||
*
|
||||
* If the name @p s is not found, the value @p d is returned as
|
||||
* a default. Otherwise the value corresponding to @p s is returned.
|
||||
* This is a shortcut over find() using a bool to distinguish
|
||||
* successful and unsuccesful lookups.
|
||||
*/
|
||||
enum_t find( const string_t& s, enum_t d ) const
|
||||
{
|
||||
bool ok = false;
|
||||
enum_t e = find( s, ok );
|
||||
return ok ? e : d;
|
||||
}
|
||||
|
||||
/** @brief Find a value @p s in the table and return its name.
|
||||
*
|
||||
* If @p s is an enum value in the table, return the corresponding
|
||||
|
@ -45,6 +45,7 @@ calamares_add_plugin( packagechooser
|
||||
TYPE viewmodule
|
||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||
SOURCES
|
||||
Config.cpp
|
||||
PackageChooserPage.cpp
|
||||
PackageChooserViewStep.cpp
|
||||
PackageModel.cpp
|
||||
|
224
src/modules/packagechooser/Config.cpp
Normal file
224
src/modules/packagechooser/Config.cpp
Normal file
@ -0,0 +1,224 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#ifdef HAVE_XML
|
||||
#include "ItemAppData.h"
|
||||
#endif
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "packages/Globals.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
const NamedEnumTable< PackageChooserMode >&
|
||||
packageChooserModeNames()
|
||||
{
|
||||
static const NamedEnumTable< PackageChooserMode > names {
|
||||
{ "optional", PackageChooserMode::Optional },
|
||||
{ "required", PackageChooserMode::Required },
|
||||
{ "optionalmultiple", PackageChooserMode::OptionalMultiple },
|
||||
{ "requiredmultiple", PackageChooserMode::RequiredMultiple },
|
||||
// and a bunch of aliases
|
||||
{ "zero-or-one", PackageChooserMode::Optional },
|
||||
{ "radio", PackageChooserMode::Required },
|
||||
{ "one", PackageChooserMode::Required },
|
||||
{ "set", PackageChooserMode::OptionalMultiple },
|
||||
{ "zero-or-more", PackageChooserMode::OptionalMultiple },
|
||||
{ "multiple", PackageChooserMode::RequiredMultiple },
|
||||
{ "one-or-more", PackageChooserMode::RequiredMultiple }
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
const NamedEnumTable< PackageChooserMethod >&
|
||||
PackageChooserMethodNames()
|
||||
{
|
||||
static const NamedEnumTable< PackageChooserMethod > names {
|
||||
{ "legacy", PackageChooserMethod::Legacy },
|
||||
{ "custom", PackageChooserMethod::Legacy },
|
||||
{ "contextualprocess", PackageChooserMethod::Legacy },
|
||||
{ "packages", PackageChooserMethod::Packages },
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
Config::Config( QObject* parent )
|
||||
: Calamares::ModuleSystem::Config( parent )
|
||||
, m_model( new PackageListModel( this ) )
|
||||
, m_mode( PackageChooserMode::Required )
|
||||
{
|
||||
}
|
||||
|
||||
Config::~Config() {}
|
||||
|
||||
const PackageItem&
|
||||
Config::introductionPackage() const
|
||||
{
|
||||
for ( int i = 0; i < m_model->packageCount(); ++i )
|
||||
{
|
||||
const auto& package = m_model->packageData( i );
|
||||
if ( package.isNonePackage() )
|
||||
{
|
||||
return package;
|
||||
}
|
||||
}
|
||||
|
||||
static PackageItem* defaultIntroduction = nullptr;
|
||||
if ( !defaultIntroduction )
|
||||
{
|
||||
const auto name = QT_TR_NOOP( "Package Selection" );
|
||||
const auto description
|
||||
= QT_TR_NOOP( "Please pick a product from the list. The selected product will be installed." );
|
||||
defaultIntroduction = new PackageItem( QString(), name, description );
|
||||
defaultIntroduction->screenshot = QPixmap( QStringLiteral( ":/images/no-selection.png" ) );
|
||||
defaultIntroduction->name = CalamaresUtils::Locale::TranslatedString( name, metaObject()->className() );
|
||||
defaultIntroduction->description
|
||||
= CalamaresUtils::Locale::TranslatedString( description, metaObject()->className() );
|
||||
}
|
||||
return *defaultIntroduction;
|
||||
}
|
||||
|
||||
void
|
||||
Config::updateGlobalStorage( const QStringList& selected ) const
|
||||
{
|
||||
if ( m_method == PackageChooserMethod::Legacy )
|
||||
{
|
||||
QString value = selected.join( ',' );
|
||||
Calamares::JobQueue::instance()->globalStorage()->insert( m_id, value );
|
||||
cDebug() << m_id<< "selected" << value;
|
||||
}
|
||||
else if ( m_method == PackageChooserMethod::Packages )
|
||||
{
|
||||
QStringList packageNames = m_model->getInstallPackagesForNames( selected );
|
||||
cDebug() << m_defaultId << "packages to install" << packageNames;
|
||||
CalamaresUtils::Packages::setGSPackageAdditions(
|
||||
Calamares::JobQueue::instance()->globalStorage(), m_defaultId, packageNames );
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Unknown packagechooser method" << smash( m_method );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fillModel( PackageListModel* model, const QVariantList& items )
|
||||
{
|
||||
if ( items.isEmpty() )
|
||||
{
|
||||
cWarning() << "No *items* for PackageChooser module.";
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_APPSTREAM
|
||||
std::unique_ptr< AppStream::Pool > pool;
|
||||
bool poolOk = false;
|
||||
#endif
|
||||
|
||||
cDebug() << "Loading PackageChooser model items from config";
|
||||
int item_index = 0;
|
||||
for ( const auto& item_it : items )
|
||||
{
|
||||
++item_index;
|
||||
QVariantMap item_map = item_it.toMap();
|
||||
if ( item_map.isEmpty() )
|
||||
{
|
||||
cWarning() << "PackageChooser entry" << item_index << "is not valid.";
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( item_map.contains( "appdata" ) )
|
||||
{
|
||||
#ifdef HAVE_XML
|
||||
model->addPackage( fromAppData( item_map ) );
|
||||
#else
|
||||
cWarning() << "Loading AppData XML is not supported.";
|
||||
#endif
|
||||
}
|
||||
else if ( item_map.contains( "appstream" ) )
|
||||
{
|
||||
#ifdef HAVE_APPSTREAM
|
||||
if ( !pool )
|
||||
{
|
||||
pool = std::make_unique< AppStream::Pool >();
|
||||
pool->setLocale( QStringLiteral( "ALL" ) );
|
||||
poolOk = pool->load();
|
||||
}
|
||||
if ( pool && poolOk )
|
||||
{
|
||||
model->addPackage( fromAppStream( *pool, item_map ) );
|
||||
}
|
||||
#else
|
||||
cWarning() << "Loading AppStream data is not supported.";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
model->addPackage( PackageItem( item_map ) );
|
||||
}
|
||||
}
|
||||
cDebug() << Logger::SubEntry << "Loaded PackageChooser with" << model->packageCount() << "entries.";
|
||||
}
|
||||
|
||||
void
|
||||
Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
m_mode = packageChooserModeNames().find( CalamaresUtils::getString( configurationMap, "mode" ),
|
||||
PackageChooserMode::Required );
|
||||
m_method = PackageChooserMethodNames().find( CalamaresUtils::getString( configurationMap, "method" ),
|
||||
PackageChooserMethod::Legacy );
|
||||
|
||||
if ( m_method == PackageChooserMethod::Legacy )
|
||||
{
|
||||
const QString configId = CalamaresUtils::getString( configurationMap, "id" );
|
||||
const QString base = QStringLiteral( "packagechooser_" );
|
||||
if ( configId.isEmpty() )
|
||||
{
|
||||
if ( m_defaultId.id().isEmpty() )
|
||||
{
|
||||
// We got nothing to work with
|
||||
m_id = base;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_id = base + m_defaultId.id();
|
||||
}
|
||||
cDebug() << "Using default ID" << m_id << "from" << m_defaultId.toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_id = base + configId;
|
||||
cDebug() << "Using configured ID" << m_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ( configurationMap.contains( "items" ) )
|
||||
{
|
||||
fillModel( m_model, configurationMap.value( "items" ).toList() );
|
||||
}
|
||||
|
||||
QString default_item_id = CalamaresUtils::getString( configurationMap, "default" );
|
||||
if ( !default_item_id.isEmpty() )
|
||||
{
|
||||
for ( int item_n = 0; item_n < m_model->packageCount(); ++item_n )
|
||||
{
|
||||
QModelIndex item_idx = m_model->index( item_n, 0 );
|
||||
QVariant item_id = m_model->data( item_idx, PackageListModel::IdRole );
|
||||
|
||||
if ( item_id.toString() == default_item_id )
|
||||
{
|
||||
m_defaultModelIndex = item_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
92
src/modules/packagechooser/Config.h
Normal file
92
src/modules/packagechooser/Config.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PACKAGECHOOSER_CONFIG_H
|
||||
#define PACKAGECHOOSER_CONFIG_H
|
||||
|
||||
#include "PackageModel.h"
|
||||
|
||||
#include "modulesystem/Config.h"
|
||||
#include "modulesystem/InstanceKey.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
enum class PackageChooserMode
|
||||
{
|
||||
Optional, // zero or one
|
||||
Required, // exactly one
|
||||
OptionalMultiple, // zero or more
|
||||
RequiredMultiple // one or more
|
||||
};
|
||||
|
||||
const NamedEnumTable< PackageChooserMode >& packageChooserModeNames();
|
||||
|
||||
enum class PackageChooserMethod
|
||||
{
|
||||
Legacy, // use contextualprocess or other custom
|
||||
Packages, // use the packages module
|
||||
};
|
||||
|
||||
const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames();
|
||||
|
||||
class Config : public Calamares::ModuleSystem::Config
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Config( QObject* parent = nullptr );
|
||||
~Config() override;
|
||||
|
||||
/** @brief Sets the default Id for this Config
|
||||
*
|
||||
* The default Id is the (owning) module identifier for the config,
|
||||
* and it is used when the Id read from the config file is empty.
|
||||
* The **usual** configuration when using method *packages* is
|
||||
* to rely on the default Id.
|
||||
*/
|
||||
void setDefaultId( const Calamares::ModuleSystem::InstanceKey& defaultId ) { m_defaultId = defaultId; }
|
||||
void setConfigurationMap( const QVariantMap& ) override;
|
||||
|
||||
PackageChooserMode mode() const { return m_mode; }
|
||||
PackageListModel* model() const { return m_model; }
|
||||
QModelIndex defaultSelectionIndex() const { return m_defaultModelIndex; }
|
||||
|
||||
/** @brief Returns an "introductory package" which describes packagechooser
|
||||
*
|
||||
* If the model contains a "none" package, returns that one on
|
||||
* the assumption that it is one to describe the whole; otherwise
|
||||
* returns a totally generic description.
|
||||
*/
|
||||
const PackageItem& introductionPackage() const;
|
||||
|
||||
/** @brief Write selection to global storage
|
||||
*
|
||||
* Updates the GS keys for this packagechooser, marking all
|
||||
* (and only) the packages in @p selected as selected.
|
||||
*/
|
||||
void updateGlobalStorage( const QStringList& selected ) const;
|
||||
/// As updateGlobalStorage() with an empty selection list
|
||||
void updateGlobalStorage() const { updateGlobalStorage( QStringList() ); }
|
||||
|
||||
private:
|
||||
PackageListModel* m_model = nullptr;
|
||||
QModelIndex m_defaultModelIndex;
|
||||
|
||||
/// Selection mode for this module
|
||||
PackageChooserMode m_mode = PackageChooserMode::Optional;
|
||||
/// How this module stores to GS
|
||||
PackageChooserMethod m_method = PackageChooserMethod::Legacy;
|
||||
/// Id (used to identify settings from this module in GS)
|
||||
QString m_id;
|
||||
/// Value to use for id if none is set in the config file
|
||||
Calamares::ModuleSystem::InstanceKey m_defaultId;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -10,6 +10,7 @@
|
||||
#ifndef PACKAGECHOOSERPAGE_H
|
||||
#define PACKAGECHOOSERPAGE_H
|
||||
|
||||
#include "Config.h"
|
||||
#include "PackageModel.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
@ -9,20 +9,22 @@
|
||||
|
||||
#include "PackageChooserViewStep.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "PackageChooserPage.h"
|
||||
#include "PackageModel.h"
|
||||
|
||||
#ifdef HAVE_XML
|
||||
#include "ItemAppData.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_APPSTREAM
|
||||
#include "ItemAppStream.h"
|
||||
#include <AppStreamQt/pool.h>
|
||||
#include <memory>
|
||||
#endif
|
||||
#include "PackageChooserPage.h"
|
||||
#include "PackageModel.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include "locale/TranslatableConfiguration.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
@ -35,9 +37,8 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( PackageChooserViewStepFactory, registerPlug
|
||||
|
||||
PackageChooserViewStep::PackageChooserViewStep( QObject* parent )
|
||||
: Calamares::ViewStep( parent )
|
||||
, m_config( new Config( this ) )
|
||||
, m_widget( nullptr )
|
||||
, m_model( nullptr )
|
||||
, m_mode( PackageChooserMode::Required )
|
||||
, m_stepName( nullptr )
|
||||
{
|
||||
emit nextStatusChanged( false );
|
||||
@ -50,7 +51,6 @@ PackageChooserViewStep::~PackageChooserViewStep()
|
||||
{
|
||||
m_widget->deleteLater();
|
||||
}
|
||||
delete m_model;
|
||||
delete m_stepName;
|
||||
}
|
||||
|
||||
@ -67,19 +67,11 @@ PackageChooserViewStep::widget()
|
||||
{
|
||||
if ( !m_widget )
|
||||
{
|
||||
m_widget = new PackageChooserPage( m_mode, nullptr );
|
||||
m_widget = new PackageChooserPage( m_config->mode(), nullptr );
|
||||
connect( m_widget, &PackageChooserPage::selectionChanged, [=]() {
|
||||
emit nextStatusChanged( this->isNextEnabled() );
|
||||
} );
|
||||
|
||||
if ( m_model )
|
||||
{
|
||||
hookupModel();
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "PackageChooser Widget created before model.";
|
||||
}
|
||||
hookupModel();
|
||||
}
|
||||
return m_widget;
|
||||
}
|
||||
@ -88,18 +80,13 @@ PackageChooserViewStep::widget()
|
||||
bool
|
||||
PackageChooserViewStep::isNextEnabled() const
|
||||
{
|
||||
if ( !m_model )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !m_widget )
|
||||
{
|
||||
// No way to have changed anything
|
||||
return true;
|
||||
}
|
||||
|
||||
switch ( m_mode )
|
||||
switch ( m_config->mode() )
|
||||
{
|
||||
case PackageChooserMode::Optional:
|
||||
case PackageChooserMode::OptionalMultiple:
|
||||
@ -139,22 +126,14 @@ PackageChooserViewStep::onActivate()
|
||||
{
|
||||
if ( !m_widget->hasSelection() )
|
||||
{
|
||||
m_widget->setSelection( m_defaultIdx );
|
||||
m_widget->setSelection( m_config->defaultSelectionIndex() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PackageChooserViewStep::onLeave()
|
||||
{
|
||||
QString key = QStringLiteral( "packagechooser_%1" ).arg( m_id );
|
||||
QString value;
|
||||
if ( m_widget->hasSelection() )
|
||||
{
|
||||
value = m_widget->selectedPackageIds().join( ',' );
|
||||
}
|
||||
Calamares::JobQueue::instance()->globalStorage()->insert( key, value );
|
||||
|
||||
cDebug() << "PackageChooser" << key << "selected" << value;
|
||||
m_config->updateGlobalStorage( m_widget->selectedPackageIds() );
|
||||
}
|
||||
|
||||
Calamares::JobList
|
||||
@ -167,23 +146,8 @@ PackageChooserViewStep::jobs() const
|
||||
void
|
||||
PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
QString mode = CalamaresUtils::getString( configurationMap, "mode" );
|
||||
bool mode_ok = false;
|
||||
if ( !mode.isEmpty() )
|
||||
{
|
||||
m_mode = roleNames().find( mode, mode_ok );
|
||||
}
|
||||
if ( !mode_ok )
|
||||
{
|
||||
m_mode = PackageChooserMode::Required;
|
||||
}
|
||||
|
||||
m_id = CalamaresUtils::getString( configurationMap, "id" );
|
||||
if ( m_id.isEmpty() )
|
||||
{
|
||||
// Not set, so use the instance id
|
||||
m_id = moduleInstanceKey().id();
|
||||
}
|
||||
m_config->setDefaultId( moduleInstanceKey() );
|
||||
m_config->setConfigurationMap( configurationMap );
|
||||
|
||||
bool labels_ok = false;
|
||||
auto labels = CalamaresUtils::getSubMap( configurationMap, "labels", labels_ok );
|
||||
@ -195,117 +159,22 @@ PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap
|
||||
}
|
||||
}
|
||||
|
||||
QString default_item_id = CalamaresUtils::getString( configurationMap, "default" );
|
||||
m_defaultIdx = QModelIndex();
|
||||
|
||||
bool first_time = !m_model;
|
||||
if ( configurationMap.contains( "items" ) )
|
||||
{
|
||||
fillModel( configurationMap.value( "items" ).toList() );
|
||||
}
|
||||
|
||||
if ( first_time && m_widget && m_model )
|
||||
if ( m_widget )
|
||||
{
|
||||
hookupModel();
|
||||
}
|
||||
|
||||
// find default item
|
||||
if ( first_time && m_model && !default_item_id.isEmpty() )
|
||||
{
|
||||
for ( int item_n = 0; item_n < m_model->packageCount(); ++item_n )
|
||||
{
|
||||
QModelIndex item_idx = m_model->index( item_n, 0 );
|
||||
QVariant item_id = m_model->data( item_idx, PackageListModel::IdRole );
|
||||
|
||||
if ( item_id.toString() == default_item_id )
|
||||
{
|
||||
m_defaultIdx = item_idx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PackageChooserViewStep::fillModel( const QVariantList& items )
|
||||
{
|
||||
if ( !m_model )
|
||||
{
|
||||
m_model = new PackageListModel( nullptr );
|
||||
}
|
||||
|
||||
if ( items.isEmpty() )
|
||||
{
|
||||
cWarning() << "No *items* for PackageChooser module.";
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_APPSTREAM
|
||||
std::unique_ptr< AppStream::Pool > pool;
|
||||
bool poolOk = false;
|
||||
#endif
|
||||
|
||||
cDebug() << "Loading PackageChooser model items from config";
|
||||
int item_index = 0;
|
||||
for ( const auto& item_it : items )
|
||||
{
|
||||
++item_index;
|
||||
QVariantMap item_map = item_it.toMap();
|
||||
if ( item_map.isEmpty() )
|
||||
{
|
||||
cWarning() << "PackageChooser entry" << item_index << "is not valid.";
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( item_map.contains( "appdata" ) )
|
||||
{
|
||||
#ifdef HAVE_XML
|
||||
m_model->addPackage( fromAppData( item_map ) );
|
||||
#else
|
||||
cWarning() << "Loading AppData XML is not supported.";
|
||||
#endif
|
||||
}
|
||||
else if ( item_map.contains( "appstream" ) )
|
||||
{
|
||||
#ifdef HAVE_APPSTREAM
|
||||
if ( !pool )
|
||||
{
|
||||
pool = std::make_unique< AppStream::Pool >();
|
||||
pool->setLocale( QStringLiteral( "ALL" ) );
|
||||
poolOk = pool->load();
|
||||
}
|
||||
if ( pool && poolOk )
|
||||
{
|
||||
m_model->addPackage( fromAppStream( *pool, item_map ) );
|
||||
}
|
||||
#else
|
||||
cWarning() << "Loading AppStream data is not supported.";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
m_model->addPackage( PackageItem( item_map ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PackageChooserViewStep::hookupModel()
|
||||
{
|
||||
if ( !m_model || !m_widget )
|
||||
if ( !m_config->model() || !m_widget )
|
||||
{
|
||||
cError() << "Can't hook up model until widget and model both exist.";
|
||||
return;
|
||||
}
|
||||
|
||||
m_widget->setModel( m_model );
|
||||
for ( int i = 0; i < m_model->packageCount(); ++i )
|
||||
{
|
||||
const auto& package = m_model->packageData( i );
|
||||
if ( package.id.isEmpty() )
|
||||
{
|
||||
m_widget->setIntroduction( package );
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_widget->setModel( m_config->model() );
|
||||
m_widget->setIntroduction( m_config->introductionPackage() );
|
||||
}
|
||||
|
@ -15,12 +15,9 @@
|
||||
#include "utils/PluginFactory.h"
|
||||
#include "viewpages/ViewStep.h"
|
||||
|
||||
#include "PackageModel.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QUrl>
|
||||
#include <QVariantMap>
|
||||
|
||||
class Config;
|
||||
class PackageChooserPage;
|
||||
|
||||
class PLUGINDLLEXPORT PackageChooserViewStep : public Calamares::ViewStep
|
||||
@ -49,17 +46,11 @@ public:
|
||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||
|
||||
private:
|
||||
void fillModel( const QVariantList& items );
|
||||
void hookupModel();
|
||||
|
||||
Config* m_config;
|
||||
PackageChooserPage* m_widget;
|
||||
PackageListModel* m_model;
|
||||
|
||||
// Configuration
|
||||
PackageChooserMode m_mode;
|
||||
QString m_id;
|
||||
CalamaresUtils::Locale::TranslatedString* m_stepName; // As it appears in the sidebar
|
||||
QModelIndex m_defaultIdx;
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( PackageChooserViewStepFactory )
|
||||
|
@ -12,46 +12,20 @@
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
const NamedEnumTable< PackageChooserMode >&
|
||||
roleNames()
|
||||
{
|
||||
static const NamedEnumTable< PackageChooserMode > names {
|
||||
{ "optional", PackageChooserMode::Optional },
|
||||
{ "required", PackageChooserMode::Required },
|
||||
{ "optionalmultiple", PackageChooserMode::OptionalMultiple },
|
||||
{ "requiredmultiple", PackageChooserMode::RequiredMultiple },
|
||||
// and a bunch of aliases
|
||||
{ "zero-or-one", PackageChooserMode::Optional },
|
||||
{ "radio", PackageChooserMode::Required },
|
||||
{ "one", PackageChooserMode::Required },
|
||||
{ "set", PackageChooserMode::OptionalMultiple },
|
||||
{ "zero-or-more", PackageChooserMode::OptionalMultiple },
|
||||
{ "multiple", PackageChooserMode::RequiredMultiple },
|
||||
{ "one-or-more", PackageChooserMode::RequiredMultiple }
|
||||
};
|
||||
return names;
|
||||
}
|
||||
|
||||
PackageItem::PackageItem() {}
|
||||
|
||||
PackageItem::PackageItem( const QString& a_id,
|
||||
const QString& a_package,
|
||||
const QString& a_name,
|
||||
const QString& a_description )
|
||||
PackageItem::PackageItem( const QString& a_id, const QString& a_name, const QString& a_description )
|
||||
: id( a_id )
|
||||
, package( a_package )
|
||||
, name( a_name )
|
||||
, description( a_description )
|
||||
{
|
||||
}
|
||||
|
||||
PackageItem::PackageItem( const QString& a_id,
|
||||
const QString& a_package,
|
||||
const QString& a_name,
|
||||
const QString& a_description,
|
||||
const QString& screenshotPath )
|
||||
: id( a_id )
|
||||
, package( a_package )
|
||||
, name( a_name )
|
||||
, description( a_description )
|
||||
, screenshot( screenshotPath )
|
||||
@ -60,10 +34,10 @@ PackageItem::PackageItem( const QString& a_id,
|
||||
|
||||
PackageItem::PackageItem::PackageItem( const QVariantMap& item_map )
|
||||
: id( CalamaresUtils::getString( item_map, "id" ) )
|
||||
, package( CalamaresUtils::getString( item_map, "package" ) )
|
||||
, name( CalamaresUtils::Locale::TranslatedString( item_map, "name" ) )
|
||||
, description( CalamaresUtils::Locale::TranslatedString( item_map, "description" ) )
|
||||
, screenshot( CalamaresUtils::getString( item_map, "screenshot" ) )
|
||||
, packageNames( CalamaresUtils::getStringList( item_map, "packages" ) )
|
||||
{
|
||||
if ( name.isEmpty() && id.isEmpty() )
|
||||
{
|
||||
@ -105,6 +79,33 @@ PackageListModel::addPackage( PackageItem&& p )
|
||||
}
|
||||
}
|
||||
|
||||
QStringList
|
||||
PackageListModel::getInstallPackagesForName( const QString& id ) const
|
||||
{
|
||||
for ( const auto& p : qAsConst( m_packages ) )
|
||||
{
|
||||
if ( p.id == id )
|
||||
{
|
||||
return p.packageNames;
|
||||
}
|
||||
}
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
QStringList
|
||||
PackageListModel::getInstallPackagesForNames( const QStringList& ids ) const
|
||||
{
|
||||
QStringList l;
|
||||
for ( const auto& p : qAsConst( m_packages ) )
|
||||
{
|
||||
if ( ids.contains( p.id ) )
|
||||
{
|
||||
l.append( p.packageNames );
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
int
|
||||
PackageListModel::rowCount( const QModelIndex& index ) const
|
||||
{
|
||||
|
@ -18,24 +18,14 @@
|
||||
#include <QPixmap>
|
||||
#include <QVector>
|
||||
|
||||
enum class PackageChooserMode
|
||||
{
|
||||
Optional, // zero or one
|
||||
Required, // exactly one
|
||||
OptionalMultiple, // zero or more
|
||||
RequiredMultiple // one or more
|
||||
};
|
||||
|
||||
const NamedEnumTable< PackageChooserMode >& roleNames();
|
||||
|
||||
struct PackageItem
|
||||
{
|
||||
QString id;
|
||||
// FIXME: unused
|
||||
QString package;
|
||||
CalamaresUtils::Locale::TranslatedString name;
|
||||
CalamaresUtils::Locale::TranslatedString description;
|
||||
QPixmap screenshot;
|
||||
QStringList packageNames;
|
||||
|
||||
/// @brief Create blank PackageItem
|
||||
PackageItem();
|
||||
@ -44,7 +34,7 @@ struct PackageItem
|
||||
* This constructor sets all the text members,
|
||||
* but leaves the screenshot blank. Set that separately.
|
||||
*/
|
||||
PackageItem( const QString& id, const QString& package, const QString& name, const QString& description );
|
||||
PackageItem( const QString& id, const QString& name, const QString& description );
|
||||
|
||||
/** @brief Creates a PackageItem from given strings.
|
||||
*
|
||||
@ -52,17 +42,21 @@ struct PackageItem
|
||||
* @p screenshotPath, which may be a QRC path (:/path/in/qrc) or
|
||||
* a filesystem path, whatever QPixmap understands.
|
||||
*/
|
||||
PackageItem( const QString& id,
|
||||
const QString& package,
|
||||
const QString& name,
|
||||
const QString& description,
|
||||
const QString& screenshotPath );
|
||||
PackageItem( const QString& id, const QString& name, const QString& description, const QString& screenshotPath );
|
||||
|
||||
/** @brief Creates a PackageItem from a QVariantMap
|
||||
*
|
||||
* This is intended for use when loading PackageItems from a
|
||||
* configuration map. It will look up the various keys in the map
|
||||
* and handle translation strings as well.
|
||||
*
|
||||
* The following keys are used:
|
||||
* - *id*: the identifier for this item; if it is the empty string
|
||||
* then this is the special "no-package".
|
||||
* - *name* (and *name[lang]*): for the name and its translations
|
||||
* - *description* (and *description[lang]*)
|
||||
* - *screenshot*: a path to a screenshot for this package
|
||||
* - *packages*: a list of package names
|
||||
*/
|
||||
PackageItem( const QVariantMap& map );
|
||||
|
||||
@ -104,6 +98,19 @@ public:
|
||||
/// @brief Direct (non-abstract) count of package data
|
||||
int packageCount() const { return m_packages.count(); }
|
||||
|
||||
/** @brief Does a name lookup (based on id) and returns the packages member
|
||||
*
|
||||
* If there is a package with the given @p id, returns its packages
|
||||
* (e.g. the names of underlying packages to install for it); returns
|
||||
* an empty list if the id is not found.
|
||||
*/
|
||||
QStringList getInstallPackagesForName( const QString& id ) const;
|
||||
/** @brief Name-lookup all the @p ids and returns the packages members
|
||||
*
|
||||
* Concatenates installPackagesForName() for each id in @p ids.
|
||||
*/
|
||||
QStringList getInstallPackagesForNames( const QStringList& ids ) const;
|
||||
|
||||
enum Roles : int
|
||||
{
|
||||
NameRole = Qt::DisplayRole,
|
||||
|
@ -3,26 +3,47 @@
|
||||
#
|
||||
# Configuration for the low-density software chooser
|
||||
---
|
||||
# The packagechooser writes a GlobalStorage value for the choice that
|
||||
# has been made. The key is *packagechooser_<id>*. If *id* is set here,
|
||||
# it is substituted into the key name. If it is not set, the module's
|
||||
# instance name is used; see the *instances* section of `settings.conf`.
|
||||
# If there is just one packagechooser module, and no *id* is set,
|
||||
# resulting GS key is probably *packagechooser_packagechooser*.
|
||||
#
|
||||
# The GS value is a comma-separated list of the IDs of the selected
|
||||
# packages, or an empty string if none is selected.
|
||||
#
|
||||
# id: ""
|
||||
|
||||
# Software selection mode, to set whether the software packages
|
||||
# can be chosen singly, or multiply.
|
||||
#
|
||||
# Possible modes are "optional", "required" (for zero or one)
|
||||
# Possible modes are "optional", "required" (for zero-or-one or exactly-one)
|
||||
# or "optionalmultiple", "requiredmultiple" (for zero-or-more
|
||||
# or one-or-more).
|
||||
mode: required
|
||||
|
||||
# Software installation method:
|
||||
#
|
||||
# - "legacy" or "custom" or "contextualprocess"
|
||||
# When set to "legacy", writes a GlobalStorage value for the choice that
|
||||
# has been made. The key is *packagechooser_<id>*. Normally, the module's
|
||||
# instance name is used; see the *instances* section of `settings.conf`.
|
||||
# If there is just one packagechooser module, and no special instance is set,
|
||||
# resulting GS key is probably *packagechooser@packagechooser*.
|
||||
# You can set *id* to change that, but it is not recommended.
|
||||
#
|
||||
# The GS value is a comma-separated list of the IDs of the selected
|
||||
# packages, or an empty string if none is selected.
|
||||
#
|
||||
# With "legacy" installation, you should have a contextualprocess or similar
|
||||
# module somewhere in the `exec` phase to process the GlobalStorage key
|
||||
# and actually **do** something for the packages.
|
||||
#
|
||||
# - "packages"
|
||||
# When set to "packages", writes GlobalStorage values suitable for
|
||||
# consumption by the *packages* module (which should appear later
|
||||
# in the `exec` section. These package settings will then be handed
|
||||
# off to whatever package manager is configured there.
|
||||
# The *id* key is not used.
|
||||
#
|
||||
# There is no need to put this module in the `exec` section. There
|
||||
# are no jobs that this module provides. You should put **other**
|
||||
# modules, either *contextualprocess* or *packages* or some custom
|
||||
# module, in the `exec` section to do the actual work.
|
||||
method: legacy
|
||||
# The *id* key is used only in "legacy" mode
|
||||
# id: ""
|
||||
|
||||
|
||||
# Human-visible strings in this module. These are all optional.
|
||||
# The following translated keys are used:
|
||||
# - *step*, used in the overall progress view (left-hand pane)
|
||||
@ -49,27 +70,45 @@ labels:
|
||||
# as a source for the data.
|
||||
#
|
||||
# For data provided by the list: the item has an id, which is used in
|
||||
# setting the value of *packagechooser_<module-id>*. The following fields
|
||||
# are mandatory:
|
||||
# setting the value of *packagechooser_<module-id>*. The following field
|
||||
# is mandatory:
|
||||
#
|
||||
# - *id* : ID for the product. The ID "" is special, and is used for
|
||||
# "no package selected". Only include this if the mode allows
|
||||
# selecting none.
|
||||
# - *package* : Package name for the product. While mandatory, this is
|
||||
# not actually used anywhere.
|
||||
# - *name* : Human-readable name of the product. To provide translations,
|
||||
# add a *[lang]* decoration as part of the key name,
|
||||
# e.g. `name[nl]` for Dutch.
|
||||
# The list of usable languages can be found in
|
||||
# `CMakeLists.txt` or as part of the debug output of Calamares.
|
||||
# - *description* : Human-readable description. These can be translated
|
||||
# as well.
|
||||
# - *screenshot* : Path to a single screenshot of the product. May be
|
||||
# a filesystem path or a QRC path,
|
||||
# e.g. ":/images/no-selection.png".
|
||||
# - *id*
|
||||
# ID for the product. The ID "" is special, and is used for
|
||||
# "no package selected". Only include this if the mode allows
|
||||
# selecting none. The name and description given for the "no package
|
||||
# selected" item are displayed when the module starts.
|
||||
#
|
||||
# Use the empty string "" as ID / key for the "no selection" item if
|
||||
# you want to customize the display of that item as well.
|
||||
# Each item must adhere to one of three "styles" of item. Which styles
|
||||
# are supported depends on compile-time dependencies of Calamares.
|
||||
# Both AppData and AppStream may **optionally** be available.
|
||||
#
|
||||
# # Generic Items #
|
||||
#
|
||||
# These items are always supported. They require the most configuration
|
||||
# **in this file** and duplicate information that may be available elsewhere
|
||||
# (e.g. in AppData or AppStream), but do not require any additional
|
||||
# dependencies. These items have the following **mandatory** fields:
|
||||
#
|
||||
# - *name*
|
||||
# Human-readable name of the product. To provide translations,
|
||||
# add a *[lang]* decoration as part of the key name, e.g. `name[nl]`
|
||||
# for Dutch. The list of usable languages can be found in
|
||||
# `CMakeLists.txt` or as part of the debug output of Calamares.
|
||||
# - *description*
|
||||
# Human-readable description. These can be translated as well.
|
||||
# - *screenshot*
|
||||
# Path to a single screenshot of the product. May be a filesystem
|
||||
# path or a QRC path, e.g. ":/images/no-selection.png".
|
||||
#
|
||||
# The following field is **optional** for an item:
|
||||
#
|
||||
# - *packages* :
|
||||
# List of package names for the product. If using the *method*
|
||||
# "packages", consider this item mandatory (because otherwise
|
||||
# selecting the item would install no packages).
|
||||
#
|
||||
# # AppData Items #
|
||||
#
|
||||
# For data provided by AppData XML: the item has an *appdata*
|
||||
# key which points to an AppData XML file in the local filesystem.
|
||||
@ -84,6 +123,8 @@ labels:
|
||||
# **may** specify an ID or screenshot path, as above. This will override
|
||||
# the settings from AppData.
|
||||
#
|
||||
# # AppStream Items #
|
||||
#
|
||||
# For data provided by AppStream cache: the item has an *appstream*
|
||||
# key which matches the AppStream identifier in the cache (e.g.
|
||||
# *org.kde.kwrite.desktop*). Data is retrieved from the AppStream
|
||||
@ -93,19 +134,19 @@ labels:
|
||||
# key which will override the data from AppStream.
|
||||
items:
|
||||
- id: ""
|
||||
package: ""
|
||||
# packages: [] # This item installs no packages
|
||||
name: "No Desktop"
|
||||
name[nl]: "Geen desktop"
|
||||
description: "Please pick a desktop environment from the list. If you don't want to install a desktop, that's fine, your system will start up in text-only mode and you can install a desktop environment later."
|
||||
description[nl]: "Kies eventueel een desktop-omgeving uit deze lijst. Als u geen desktop-omgeving wenst te gebruiken, kies er dan geen. In dat geval start het systeem straks op in tekst-modus en kunt u later alsnog een desktop-omgeving installeren."
|
||||
screenshot: ":/images/no-selection.png"
|
||||
- id: kde
|
||||
package: kde
|
||||
packages: [ kde-frameworks, kde-plasma, kde-gear ]
|
||||
name: Plasma Desktop
|
||||
description: "KDE Plasma Desktop, simple by default, a clean work area for real-world usage which intends to stay out of your way. Plasma is powerful when needed, enabling the user to create the workflow that makes them more effective to complete their tasks."
|
||||
screenshot: ":/images/kde.png"
|
||||
- id: gnome
|
||||
package: gnome
|
||||
packages: [ gnome-all ]
|
||||
name: GNOME
|
||||
description: GNU Networked Object Modeling Environment Desktop
|
||||
screenshot: ":/images/gnome.png"
|
||||
|
Loading…
Reference in New Issue
Block a user