Merge branch 'issue-1573' into calamares
This commit is contained in:
commit
ff66eacd0d
@ -139,8 +139,9 @@ public:
|
||||
RunInTarget
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs the specified command in the chroot of the target system.
|
||||
/** @brief Runs a command in the host or the target (select explicitly)
|
||||
*
|
||||
* @param location whether to run in the host or the target
|
||||
* @param args the command with arguments, as a string list.
|
||||
* @param workingPath the current working directory for the QProcess
|
||||
* call (optional).
|
||||
@ -162,9 +163,9 @@ public:
|
||||
const QString& stdInput = QString(),
|
||||
std::chrono::seconds timeoutSec = std::chrono::seconds( 0 ) );
|
||||
|
||||
/** @brief Convenience wrapper for runCommand()
|
||||
/** @brief Convenience wrapper for runCommand() in the host
|
||||
*
|
||||
* Runs the given command-line @p args in the host in the current direcory
|
||||
* Runs the given command-line @p args in the **host** in the current direcory
|
||||
* with no input, and the given @p timeoutSec for completion.
|
||||
*/
|
||||
static inline ProcessResult runCommand( const QStringList& args, std::chrono::seconds timeoutSec )
|
||||
@ -173,6 +174,7 @@ public:
|
||||
}
|
||||
|
||||
/** @brief Convenience wrapper for runCommand().
|
||||
*
|
||||
* Runs the command in the location specified through the boolean
|
||||
* doChroot(), which is what you usually want for running commands
|
||||
* during installation.
|
||||
|
@ -10,16 +10,18 @@ find_package(ECM ${ECM_VERSION} REQUIRED NO_MODULE)
|
||||
set( lnf_ver 5.41 )
|
||||
|
||||
find_package( KF5Config ${lnf_ver} )
|
||||
find_package( KF5Plasma ${lnf_ver} )
|
||||
find_package( KF5Package ${lnf_ver} )
|
||||
set_package_properties(
|
||||
KF5Config PROPERTIES
|
||||
PURPOSE "For finding default Plasma Look-and-Feel"
|
||||
)
|
||||
|
||||
find_package( KF5Plasma ${lnf_ver} )
|
||||
set_package_properties(
|
||||
KF5Plasma PROPERTIES
|
||||
PURPOSE "For Plasma Look-and-Feel selection"
|
||||
)
|
||||
|
||||
find_package( KF5Package ${lnf_ver} )
|
||||
set_package_properties(
|
||||
KF5Package PROPERTIES
|
||||
PURPOSE "For Plasma Look-and-Feel selection"
|
||||
@ -32,10 +34,11 @@ if ( KF5Plasma_FOUND AND KF5Package_FOUND )
|
||||
COMPILE_DEFINITIONS
|
||||
${option_defs}
|
||||
SOURCES
|
||||
Config.cpp
|
||||
PlasmaLnfViewStep.cpp
|
||||
PlasmaLnfPage.cpp
|
||||
PlasmaLnfJob.cpp
|
||||
ThemeWidget.cpp
|
||||
ThemeInfo.cpp
|
||||
RESOURCES
|
||||
page_plasmalnf.qrc
|
||||
UI
|
||||
|
164
src/modules/plasmalnf/Config.cpp
Normal file
164
src/modules/plasmalnf/Config.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2020 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"
|
||||
|
||||
#include "PlasmaLnfJob.h"
|
||||
#include "ThemeInfo.h"
|
||||
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
#ifdef WITH_KCONFIG
|
||||
#include <KConfigGroup>
|
||||
#include <KSharedConfig>
|
||||
#endif
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
static QString
|
||||
currentPlasmaTheme()
|
||||
{
|
||||
#ifdef WITH_KCONFIG
|
||||
KConfigGroup cg( KSharedConfig::openConfig( QStringLiteral( "kdeglobals" ) ), "KDE" );
|
||||
return cg.readEntry( "LookAndFeelPackage", QString() );
|
||||
#else
|
||||
cWarning() << "No KConfig support, cannot determine Plasma theme.";
|
||||
return QString();
|
||||
#endif
|
||||
}
|
||||
|
||||
Config::Config( QObject* parent )
|
||||
: QObject( parent )
|
||||
, m_themeModel( new ThemesModel( this ) )
|
||||
{
|
||||
auto* filter = new QSortFilterProxyModel( m_themeModel );
|
||||
filter->setFilterRole( ThemesModel::ShownRole );
|
||||
filter->setFilterFixedString( QStringLiteral( "true" ) );
|
||||
filter->setSourceModel( m_themeModel );
|
||||
filter->setSortRole( ThemesModel::LabelRole );
|
||||
filter->sort( 0 );
|
||||
|
||||
m_filteredModel = filter;
|
||||
}
|
||||
|
||||
void
|
||||
Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
m_lnfPath = CalamaresUtils::getString( configurationMap, "lnftool" );
|
||||
|
||||
if ( m_lnfPath.isEmpty() )
|
||||
{
|
||||
cWarning() << "no lnftool given for plasmalnf module.";
|
||||
}
|
||||
|
||||
m_liveUser = CalamaresUtils::getString( configurationMap, "liveuser" );
|
||||
|
||||
QString preselect = CalamaresUtils::getString( configurationMap, "preselect" );
|
||||
if ( preselect == QStringLiteral( "*" ) )
|
||||
{
|
||||
preselect = currentPlasmaTheme();
|
||||
}
|
||||
m_preselectThemeId = preselect;
|
||||
|
||||
if ( configurationMap.contains( "themes" ) && configurationMap.value( "themes" ).type() == QVariant::List )
|
||||
{
|
||||
QMap< QString, QString > listedThemes;
|
||||
auto themeList = configurationMap.value( "themes" ).toList();
|
||||
// Create the ThemInfo objects for the listed themes; information
|
||||
// about the themes from Plasma (e.g. human-readable name and description)
|
||||
// are filled in by update_names() in PlasmaLnfPage.
|
||||
for ( const auto& i : themeList )
|
||||
if ( i.type() == QVariant::Map )
|
||||
{
|
||||
auto iv = i.toMap();
|
||||
listedThemes.insert( iv.value( "theme" ).toString(), iv.value( "image" ).toString() );
|
||||
}
|
||||
else if ( i.type() == QVariant::String )
|
||||
{
|
||||
listedThemes.insert( i.toString(), QString() );
|
||||
}
|
||||
|
||||
if ( listedThemes.count() == 1 )
|
||||
{
|
||||
cWarning() << "only one theme enabled in plasmalnf";
|
||||
}
|
||||
m_themeModel->setThemeImage( listedThemes );
|
||||
|
||||
bool showAll = CalamaresUtils::getBool( configurationMap, "showAll", false );
|
||||
if ( !listedThemes.isEmpty() && !showAll )
|
||||
{
|
||||
m_themeModel->showOnlyThemes( listedThemes );
|
||||
}
|
||||
}
|
||||
|
||||
m_themeModel->select( m_preselectThemeId );
|
||||
}
|
||||
|
||||
Calamares::JobList
|
||||
Config::createJobs() const
|
||||
{
|
||||
Calamares::JobList l;
|
||||
|
||||
cDebug() << "Creating Plasma LNF jobs ..";
|
||||
if ( !theme().isEmpty() )
|
||||
{
|
||||
if ( !lnfToolPath().isEmpty() )
|
||||
{
|
||||
l.append( Calamares::job_ptr( new PlasmaLnfJob( lnfToolPath(), theme() ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "no lnftool given for plasmalnf module.";
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Config::setTheme( const QString& id )
|
||||
{
|
||||
if ( m_themeId == id )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_themeId = id;
|
||||
if ( lnfToolPath().isEmpty() )
|
||||
{
|
||||
cWarning() << "no lnftool given for plasmalnf module.";
|
||||
}
|
||||
else
|
||||
{
|
||||
QStringList command;
|
||||
if ( !m_liveUser.isEmpty() )
|
||||
{
|
||||
command << "sudo"
|
||||
<< "-E"
|
||||
<< "-H"
|
||||
<< "-u" << m_liveUser;
|
||||
}
|
||||
command << lnfToolPath() << "--resetLayout"
|
||||
<< "--apply" << id;
|
||||
auto r = CalamaresUtils::System::instance()->runCommand( command, std::chrono::seconds( 10 ) );
|
||||
|
||||
if ( r.getExitCode() )
|
||||
{
|
||||
cWarning() << "Failed (" << r.getExitCode() << ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << "Plasma look-and-feel applied" << id;
|
||||
}
|
||||
}
|
||||
m_themeModel->select( id );
|
||||
emit themeChanged( id );
|
||||
}
|
77
src/modules/plasmalnf/Config.h
Normal file
77
src/modules/plasmalnf/Config.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PLASMALNF_CONFIG_H
|
||||
#define PLASMALNF_CONFIG_H
|
||||
|
||||
#include "Job.h"
|
||||
|
||||
#include "ThemeInfo.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Config : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( QString preselectedTheme READ preselectedTheme CONSTANT )
|
||||
Q_PROPERTY( QString theme READ theme WRITE setTheme NOTIFY themeChanged )
|
||||
Q_PROPERTY( QAbstractItemModel* themeModel READ themeModel CONSTANT )
|
||||
|
||||
public:
|
||||
Config( QObject* parent = nullptr );
|
||||
virtual ~Config() override = default; // QObject cleans up the model pointer
|
||||
|
||||
void setConfigurationMap( const QVariantMap& );
|
||||
Calamares::JobList createJobs() const;
|
||||
|
||||
/** @brief Full path to the lookandfeeltool (if it exists)
|
||||
*
|
||||
* This can be configured, or defaults to `lookandfeeltool` to find
|
||||
* it in $PATH.
|
||||
*/
|
||||
QString lnfToolPath() const { return m_lnfPath; }
|
||||
/** @brief For OEM mode, the name of the (current) live user
|
||||
*
|
||||
*/
|
||||
QString liveUser() const { return m_liveUser; }
|
||||
|
||||
/** @brief The id (in reverse-DNS notation) of the current theme.
|
||||
*/
|
||||
QString theme() const { return m_themeId; }
|
||||
|
||||
/** @brief The theme we start with
|
||||
*
|
||||
* This can be configured, or is taken from the live environment
|
||||
* if the environment is (also) KDE Plasma.
|
||||
*/
|
||||
QString preselectedTheme() const { return m_preselectThemeId; }
|
||||
|
||||
/** @brief The (list) model of available themes.
|
||||
*/
|
||||
QAbstractItemModel* themeModel() const { return m_filteredModel; }
|
||||
|
||||
public slots:
|
||||
void setTheme( const QString& id );
|
||||
|
||||
signals:
|
||||
void themeChanged( const QString& id );
|
||||
|
||||
private:
|
||||
QString m_lnfPath; // Path to the lnf tool
|
||||
QString m_liveUser; // Name of the live user (for OEM mode)
|
||||
|
||||
QString m_preselectThemeId;
|
||||
QString m_themeId; // Id of selected theme
|
||||
|
||||
QAbstractItemModel* m_filteredModel = nullptr;
|
||||
ThemesModel* m_themeModel = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
@ -10,49 +10,67 @@
|
||||
|
||||
#include "PlasmaLnfPage.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "ui_page_plasmalnf.h"
|
||||
|
||||
#include "Settings.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Retranslator.h"
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QHeaderView>
|
||||
#include <QListView>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
#include <KPackage/Package>
|
||||
#include <KPackage/PackageLoader>
|
||||
|
||||
ThemeInfo::ThemeInfo( const KPluginMetaData& data )
|
||||
: id( data.pluginId() )
|
||||
, name( data.name() )
|
||||
, description( data.description() )
|
||||
, widget( nullptr )
|
||||
class ThemeDelegate : public QStyledItemDelegate
|
||||
{
|
||||
public:
|
||||
using QStyledItemDelegate::QStyledItemDelegate;
|
||||
|
||||
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const override;
|
||||
// The size of the item is constant
|
||||
QSize sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const override;
|
||||
};
|
||||
|
||||
QSize
|
||||
ThemeDelegate::sizeHint( const QStyleOptionViewItem&, const QModelIndex& ) const
|
||||
{
|
||||
QSize image( ThemesModel::imageSize() );
|
||||
return { 3 * image.width(), image.height() };
|
||||
}
|
||||
|
||||
static ThemeInfoList
|
||||
plasma_themes()
|
||||
void
|
||||
ThemeDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
||||
{
|
||||
ThemeInfoList packages;
|
||||
auto label = index.data( ThemesModel::LabelRole ).toString();
|
||||
auto description = index.data( ThemesModel::DescriptionRole ).toString();
|
||||
auto selected = index.data( ThemesModel::SelectedRole ).toBool() ? QStyle::State_On : QStyle::State_Off;
|
||||
auto image_v = index.data( ThemesModel::ImageRole );
|
||||
QPixmap image = image_v.canConvert< QPixmap >() ? qvariant_cast< QPixmap >( image_v ) : QPixmap();
|
||||
|
||||
QList< KPluginMetaData > pkgs = KPackage::PackageLoader::self()->listPackages( "Plasma/LookAndFeel" );
|
||||
// The delegate paints three "columns", each of which takes 1/3
|
||||
// of the space: label, description and screenshot.
|
||||
QRect labelRect( option.rect );
|
||||
labelRect.setWidth( labelRect.width() / 3 );
|
||||
|
||||
for ( const KPluginMetaData& data : pkgs )
|
||||
{
|
||||
if ( data.isValid() && !data.isHidden() && !data.name().isEmpty() )
|
||||
{
|
||||
packages << ThemeInfo { data };
|
||||
}
|
||||
}
|
||||
QStyleOptionButton rbOption;
|
||||
rbOption.state |= QStyle::State_Enabled | selected;
|
||||
rbOption.rect = labelRect;
|
||||
rbOption.text = label;
|
||||
option.widget->style()->drawControl( QStyle::CE_RadioButton, &rbOption, painter, option.widget );
|
||||
|
||||
return packages;
|
||||
labelRect.moveLeft( labelRect.width() );
|
||||
option.widget->style()->drawItemText(
|
||||
painter, labelRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextWordWrap, option.palette, false, description );
|
||||
|
||||
labelRect.moveLeft( 2 * labelRect.width() );
|
||||
option.widget->style()->drawItemPixmap( painter, labelRect, Qt::AlignHCenter | Qt::AlignVCenter, image );
|
||||
}
|
||||
|
||||
|
||||
PlasmaLnfPage::PlasmaLnfPage( QWidget* parent )
|
||||
PlasmaLnfPage::PlasmaLnfPage( Config* config, QWidget* parent )
|
||||
: QWidget( parent )
|
||||
, ui( new Ui::PlasmaLnfPage )
|
||||
, m_showAll( false )
|
||||
, m_buttonGroup( nullptr )
|
||||
, m_config( config )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
CALAMARES_RETRANSLATE( {
|
||||
@ -67,134 +85,28 @@ PlasmaLnfPage::PlasmaLnfPage( QWidget* parent )
|
||||
"You can also skip this step and configure the look-and-feel "
|
||||
"once the system is installed. Clicking on a look-and-feel "
|
||||
"selection will give you a live preview of that look-and-feel." ) );
|
||||
updateThemeNames();
|
||||
fillUi();
|
||||
} )
|
||||
}
|
||||
|
||||
void
|
||||
PlasmaLnfPage::setLnfPath( const QString& path )
|
||||
{
|
||||
m_lnfPath = path;
|
||||
}
|
||||
|
||||
void
|
||||
PlasmaLnfPage::setEnabledThemes( const ThemeInfoList& themes, bool showAll )
|
||||
{
|
||||
m_enabledThemes = themes;
|
||||
|
||||
if ( showAll )
|
||||
{
|
||||
auto plasmaThemes = plasma_themes();
|
||||
for ( auto& installed_theme : plasmaThemes )
|
||||
if ( !m_enabledThemes.findById( installed_theme.id ) )
|
||||
{
|
||||
m_enabledThemes.append( installed_theme );
|
||||
}
|
||||
}
|
||||
|
||||
updateThemeNames();
|
||||
winnowThemes();
|
||||
fillUi();
|
||||
}
|
||||
|
||||
void
|
||||
PlasmaLnfPage::setEnabledThemesAll()
|
||||
{
|
||||
// Don't need to set showAll=true, because we're already passing in
|
||||
// the complete list of installed themes.
|
||||
setEnabledThemes( plasma_themes(), false );
|
||||
}
|
||||
|
||||
void
|
||||
PlasmaLnfPage::setPreselect( const QString& id )
|
||||
{
|
||||
m_preselect = id;
|
||||
if ( !m_enabledThemes.isEmpty() )
|
||||
{
|
||||
fillUi();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlasmaLnfPage::updateThemeNames()
|
||||
{
|
||||
auto plasmaThemes = plasma_themes();
|
||||
for ( auto& enabled_theme : m_enabledThemes )
|
||||
{
|
||||
ThemeInfo* t = plasmaThemes.findById( enabled_theme.id );
|
||||
if ( t != nullptr )
|
||||
{
|
||||
enabled_theme.name = t->name;
|
||||
enabled_theme.description = t->description;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlasmaLnfPage::winnowThemes()
|
||||
{
|
||||
auto plasmaThemes = plasma_themes();
|
||||
bool winnowed = true;
|
||||
int winnow_index = 0;
|
||||
while ( winnowed )
|
||||
{
|
||||
winnowed = false;
|
||||
winnow_index = 0;
|
||||
|
||||
for ( auto& enabled_theme : m_enabledThemes )
|
||||
{
|
||||
ThemeInfo* t = plasmaThemes.findById( enabled_theme.id );
|
||||
if ( t == nullptr )
|
||||
{
|
||||
cDebug() << "Removing" << enabled_theme.id;
|
||||
winnowed = true;
|
||||
break;
|
||||
}
|
||||
++winnow_index;
|
||||
}
|
||||
|
||||
if ( winnowed )
|
||||
{
|
||||
m_enabledThemes.removeAt( winnow_index );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlasmaLnfPage::fillUi()
|
||||
{
|
||||
if ( m_enabledThemes.isEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !m_buttonGroup )
|
||||
{
|
||||
m_buttonGroup = new QButtonGroup( this );
|
||||
m_buttonGroup->setExclusive( true );
|
||||
}
|
||||
|
||||
int c = 1; // After the general explanation
|
||||
for ( auto& theme : m_enabledThemes )
|
||||
{
|
||||
if ( !theme.widget )
|
||||
{
|
||||
ThemeWidget* w = new ThemeWidget( theme );
|
||||
m_buttonGroup->addButton( w->button() );
|
||||
ui->verticalLayout->insertWidget( c, w );
|
||||
connect( w, &ThemeWidget::themeSelected, this, &PlasmaLnfPage::plasmaThemeSelected );
|
||||
theme.widget = w;
|
||||
}
|
||||
else
|
||||
{
|
||||
theme.widget->updateThemeName( theme );
|
||||
}
|
||||
if ( theme.id == m_preselect )
|
||||
{
|
||||
const QSignalBlocker b( theme.widget->button() );
|
||||
theme.widget->button()->setChecked( true );
|
||||
}
|
||||
++c;
|
||||
}
|
||||
|
||||
auto* view = new QListView( this );
|
||||
view->setModel( m_config->themeModel() );
|
||||
view->setItemDelegate( new ThemeDelegate( view ) );
|
||||
view->setUniformItemSizes( true );
|
||||
view->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
||||
ui->verticalLayout->addWidget( view );
|
||||
|
||||
connect( view->selectionModel(),
|
||||
&QItemSelectionModel::selectionChanged,
|
||||
[this]( const QItemSelection& selected, const QItemSelection& ) {
|
||||
auto i = selected.indexes();
|
||||
if ( !i.isEmpty() )
|
||||
{
|
||||
auto row = i.first().row();
|
||||
auto* model = m_config->themeModel();
|
||||
auto id = model->data( model->index( row, 0 ), ThemesModel::KeyRole ).toString();
|
||||
if ( !id.isEmpty() )
|
||||
{
|
||||
m_config->setTheme( id );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ namespace Ui
|
||||
class PlasmaLnfPage;
|
||||
}
|
||||
|
||||
class Config;
|
||||
|
||||
/** @brief Page for selecting a Plasma Look-and-Feel theme.
|
||||
*
|
||||
* You must call setEnabledThemes -- either overload -- once
|
||||
@ -34,40 +36,11 @@ class PlasmaLnfPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PlasmaLnfPage( QWidget* parent = nullptr );
|
||||
|
||||
void setLnfPath( const QString& path );
|
||||
/** @brief enable only the listed themes.
|
||||
*
|
||||
* Shows the listed @p themes with full information (e.g. screenshot).
|
||||
* If @p showAll is true, then also show all installed themes
|
||||
* not explicitly listed (without a screenshot).
|
||||
*/
|
||||
void setEnabledThemes( const ThemeInfoList& themes, bool showAll );
|
||||
/** @brief enable all installed plasma themes. */
|
||||
void setEnabledThemesAll();
|
||||
/** @brief set which theme is to be preselected. */
|
||||
void setPreselect( const QString& id );
|
||||
|
||||
signals:
|
||||
void plasmaThemeSelected( const QString& id );
|
||||
explicit PlasmaLnfPage( Config* config, QWidget* parent = nullptr );
|
||||
|
||||
private:
|
||||
/** @brief Intersect the list of enabled themes with the installed ones. */
|
||||
void winnowThemes();
|
||||
/** @brief Get the translated names for all enabled themes. */
|
||||
void updateThemeNames();
|
||||
/** @brief show enabled themes in the UI. */
|
||||
void fillUi();
|
||||
|
||||
Ui::PlasmaLnfPage* ui;
|
||||
QString m_lnfPath;
|
||||
QString m_preselect;
|
||||
bool m_showAll; // If true, don't winnow according to enabledThemes
|
||||
ThemeInfoList m_enabledThemes;
|
||||
|
||||
QButtonGroup* m_buttonGroup;
|
||||
QList< ThemeWidget* > m_widgets;
|
||||
Config* m_config;
|
||||
};
|
||||
|
||||
#endif //PLASMALNFPAGE_H
|
||||
|
@ -8,40 +8,22 @@
|
||||
*/
|
||||
#include "PlasmaLnfViewStep.h"
|
||||
|
||||
#include "PlasmaLnfJob.h"
|
||||
#include "Config.h"
|
||||
#include "PlasmaLnfPage.h"
|
||||
#include "ThemeInfo.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QVariantMap>
|
||||
|
||||
#ifdef WITH_KCONFIG
|
||||
#include <KConfigGroup>
|
||||
#include <KSharedConfig>
|
||||
#endif
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( PlasmaLnfViewStepFactory, registerPlugin< PlasmaLnfViewStep >(); )
|
||||
|
||||
static QString
|
||||
currentPlasmaTheme()
|
||||
{
|
||||
#ifdef WITH_KCONFIG
|
||||
KConfigGroup cg( KSharedConfig::openConfig( QStringLiteral( "kdeglobals" ) ), "KDE" );
|
||||
return cg.readEntry( "LookAndFeelPackage", QString() );
|
||||
#else
|
||||
cWarning() << "No KConfig support, cannot determine Plasma theme.";
|
||||
return QString();
|
||||
#endif
|
||||
}
|
||||
|
||||
PlasmaLnfViewStep::PlasmaLnfViewStep( QObject* parent )
|
||||
: Calamares::ViewStep( parent )
|
||||
, m_widget( new PlasmaLnfPage )
|
||||
, m_config( new Config( this ) )
|
||||
, m_widget( new PlasmaLnfPage( m_config ) )
|
||||
{
|
||||
connect( m_widget, &PlasmaLnfPage::plasmaThemeSelected, this, &PlasmaLnfViewStep::themeSelected );
|
||||
emit nextStatusChanged( false );
|
||||
}
|
||||
|
||||
@ -106,112 +88,12 @@ PlasmaLnfViewStep::onLeave()
|
||||
Calamares::JobList
|
||||
PlasmaLnfViewStep::jobs() const
|
||||
{
|
||||
Calamares::JobList l;
|
||||
|
||||
cDebug() << "Creating Plasma LNF jobs ..";
|
||||
if ( !m_themeId.isEmpty() )
|
||||
{
|
||||
if ( !m_lnfPath.isEmpty() )
|
||||
{
|
||||
l.append( Calamares::job_ptr( new PlasmaLnfJob( m_lnfPath, m_themeId ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "no lnftool given for plasmalnf module.";
|
||||
}
|
||||
}
|
||||
return l;
|
||||
return m_config->createJobs();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
m_lnfPath = CalamaresUtils::getString( configurationMap, "lnftool" );
|
||||
m_widget->setLnfPath( m_lnfPath );
|
||||
|
||||
if ( m_lnfPath.isEmpty() )
|
||||
{
|
||||
cWarning() << "no lnftool given for plasmalnf module.";
|
||||
}
|
||||
|
||||
m_liveUser = CalamaresUtils::getString( configurationMap, "liveuser" );
|
||||
|
||||
QString preselect = CalamaresUtils::getString( configurationMap, "preselect" );
|
||||
if ( preselect == QStringLiteral( "*" ) )
|
||||
{
|
||||
preselect = currentPlasmaTheme();
|
||||
}
|
||||
if ( !preselect.isEmpty() )
|
||||
{
|
||||
m_widget->setPreselect( preselect );
|
||||
}
|
||||
|
||||
bool showAll = CalamaresUtils::getBool( configurationMap, "showAll", false );
|
||||
|
||||
if ( configurationMap.contains( "themes" ) && configurationMap.value( "themes" ).type() == QVariant::List )
|
||||
{
|
||||
ThemeInfoList listedThemes;
|
||||
auto themeList = configurationMap.value( "themes" ).toList();
|
||||
// Create the ThemInfo objects for the listed themes; information
|
||||
// about the themes from Plasma (e.g. human-readable name and description)
|
||||
// are filled in by update_names() in PlasmaLnfPage.
|
||||
for ( const auto& i : themeList )
|
||||
if ( i.type() == QVariant::Map )
|
||||
{
|
||||
auto iv = i.toMap();
|
||||
listedThemes.append( ThemeInfo( iv.value( "theme" ).toString(), iv.value( "image" ).toString() ) );
|
||||
}
|
||||
else if ( i.type() == QVariant::String )
|
||||
{
|
||||
listedThemes.append( ThemeInfo( i.toString() ) );
|
||||
}
|
||||
|
||||
if ( listedThemes.length() == 1 )
|
||||
{
|
||||
cWarning() << "only one theme enabled in plasmalnf";
|
||||
}
|
||||
m_widget->setEnabledThemes( listedThemes, showAll );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_widget->setEnabledThemesAll(); // All of them
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PlasmaLnfViewStep::themeSelected( const QString& id )
|
||||
{
|
||||
m_themeId = id;
|
||||
if ( m_lnfPath.isEmpty() )
|
||||
{
|
||||
cWarning() << "no lnftool given for plasmalnf module.";
|
||||
return;
|
||||
}
|
||||
|
||||
QProcess lnftool;
|
||||
if ( !m_liveUser.isEmpty() )
|
||||
lnftool.start( "sudo", { "-E", "-H", "-u", m_liveUser, m_lnfPath, "--resetLayout", "--apply", id } );
|
||||
else
|
||||
lnftool.start( m_lnfPath, { "--resetLayout", "--apply", id } );
|
||||
|
||||
if ( !lnftool.waitForStarted( 1000 ) )
|
||||
{
|
||||
cWarning() << "could not start look-and-feel" << m_lnfPath;
|
||||
return;
|
||||
}
|
||||
if ( !lnftool.waitForFinished() )
|
||||
{
|
||||
cWarning() << m_lnfPath << "timed out.";
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ( lnftool.exitCode() == 0 ) && ( lnftool.exitStatus() == QProcess::NormalExit ) )
|
||||
{
|
||||
cDebug() << "Plasma look-and-feel applied" << id;
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "could not apply look-and-feel" << id;
|
||||
}
|
||||
m_config->setConfigurationMap( configurationMap );
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "utils/PluginFactory.h"
|
||||
#include "viewpages/ViewStep.h"
|
||||
|
||||
class Config;
|
||||
class PlasmaLnfPage;
|
||||
|
||||
class PLUGINDLLEXPORT PlasmaLnfViewStep : public Calamares::ViewStep
|
||||
@ -40,14 +41,9 @@ public:
|
||||
|
||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||
|
||||
public slots:
|
||||
void themeSelected( const QString& id );
|
||||
|
||||
private:
|
||||
Config* m_config;
|
||||
PlasmaLnfPage* m_widget;
|
||||
QString m_lnfPath; // Path to the lnf tool
|
||||
QString m_themeId; // Id of selected theme
|
||||
QString m_liveUser; // Name of the live user (for OEM mode)
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( PlasmaLnfViewStepFactory )
|
||||
|
319
src/modules/plasmalnf/ThemeInfo.cpp
Normal file
319
src/modules/plasmalnf/ThemeInfo.cpp
Normal file
@ -0,0 +1,319 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
#include "ThemeInfo.h"
|
||||
|
||||
#include "Branding.h"
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <KPackage/Package>
|
||||
#include <KPackage/PackageLoader>
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QPixmap>
|
||||
|
||||
/** @brief describes a single plasma LnF theme.
|
||||
*
|
||||
* A theme description has an id, which is really the name of the desktop
|
||||
* file (e.g. org.kde.breeze.desktop), a name which is human-readable and
|
||||
* translated, and an optional image Page, which points to a local screenshot
|
||||
* of that theme.
|
||||
*/
|
||||
struct ThemeInfo
|
||||
{
|
||||
QString id;
|
||||
QString name;
|
||||
QString description;
|
||||
QString imagePath;
|
||||
mutable QPixmap pixmap;
|
||||
bool show = true;
|
||||
bool selected = false;
|
||||
|
||||
ThemeInfo() {}
|
||||
|
||||
explicit ThemeInfo( const QString& _id )
|
||||
: id( _id )
|
||||
{
|
||||
}
|
||||
|
||||
explicit ThemeInfo( const QString& _id, const QString& image )
|
||||
: id( _id )
|
||||
, imagePath( image )
|
||||
{
|
||||
}
|
||||
|
||||
explicit ThemeInfo( const KPluginMetaData& );
|
||||
|
||||
bool isValid() const { return !id.isEmpty(); }
|
||||
|
||||
/// @brief Fill in the pixmap member based on imagePath
|
||||
QPixmap loadImage() const;
|
||||
};
|
||||
|
||||
class ThemeInfoList : public QList< ThemeInfo >
|
||||
{
|
||||
public:
|
||||
std::pair< int, const ThemeInfo* > indexById( const QString& id ) const
|
||||
{
|
||||
int index = 0;
|
||||
for ( const ThemeInfo& i : *this )
|
||||
{
|
||||
if ( i.id == id )
|
||||
{
|
||||
return { index, &i };
|
||||
}
|
||||
}
|
||||
return { -1, nullptr };
|
||||
}
|
||||
|
||||
std::pair< int, ThemeInfo* > indexById( const QString& id )
|
||||
{
|
||||
// Call the const version and then munge the types
|
||||
auto [ i, p ] = const_cast< const ThemeInfoList* >( this )->indexById( id );
|
||||
return { i, const_cast< ThemeInfo* >( p ) };
|
||||
}
|
||||
|
||||
|
||||
/** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */
|
||||
ThemeInfo* findById( const QString& id )
|
||||
{
|
||||
auto [ i, p ] = indexById( id );
|
||||
return p;
|
||||
}
|
||||
|
||||
/** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */
|
||||
const ThemeInfo* findById( const QString& id ) const
|
||||
{
|
||||
auto [ i, p ] = indexById( id );
|
||||
return p;
|
||||
}
|
||||
|
||||
/** @brief Checks if a given @p id is in the list of themes. */
|
||||
bool contains( const QString& id ) const { return findById( id ) != nullptr; }
|
||||
};
|
||||
|
||||
ThemesModel::ThemesModel( QObject* parent )
|
||||
: QAbstractListModel( parent )
|
||||
, m_themes( new ThemeInfoList )
|
||||
{
|
||||
auto packages = KPackage::PackageLoader::self()->listPackages( "Plasma/LookAndFeel" );
|
||||
m_themes->reserve( packages.length() );
|
||||
|
||||
for ( const auto& p : packages )
|
||||
{
|
||||
m_themes->append( ThemeInfo { p } );
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ThemesModel::rowCount( const QModelIndex& ) const
|
||||
{
|
||||
return m_themes->count();
|
||||
}
|
||||
|
||||
QVariant
|
||||
ThemesModel::data( const QModelIndex& index, int role ) const
|
||||
{
|
||||
if ( !index.isValid() )
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
if ( index.row() < 0 || index.row() >= m_themes->count() )
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const auto& item = m_themes->at( index.row() );
|
||||
switch ( role )
|
||||
{
|
||||
case LabelRole:
|
||||
return item.name;
|
||||
case KeyRole:
|
||||
return item.id;
|
||||
case ShownRole:
|
||||
return item.show;
|
||||
case SelectedRole:
|
||||
return item.selected;
|
||||
case DescriptionRole:
|
||||
return item.description;
|
||||
case ImageRole:
|
||||
return item.loadImage();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
QHash< int, QByteArray >
|
||||
ThemesModel::roleNames() const
|
||||
{
|
||||
return { { LabelRole, "label" },
|
||||
{ KeyRole, "key" },
|
||||
{ SelectedRole, "selected" },
|
||||
{ ShownRole, "show" },
|
||||
{ ImageRole, "image" } };
|
||||
}
|
||||
|
||||
void
|
||||
ThemesModel::setThemeImage( const QString& id, const QString& imagePath )
|
||||
{
|
||||
auto [ i, theme ] = m_themes->indexById( id );
|
||||
if ( theme )
|
||||
{
|
||||
theme->imagePath = imagePath;
|
||||
emit dataChanged( index( i, 0 ), index( i, 0 ), { ImageRole } );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ThemesModel::setThemeImage( const QMap< QString, QString >& images )
|
||||
{
|
||||
if ( m_themes->isEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't emit signals from each call, aggregate to one call (below this block)
|
||||
{
|
||||
QSignalBlocker b( this );
|
||||
for ( auto k = images.constKeyValueBegin(); k != images.constKeyValueEnd(); ++k )
|
||||
{
|
||||
setThemeImage( k->first, k->second );
|
||||
}
|
||||
}
|
||||
emit dataChanged( index( 0, 0 ), index( m_themes->count() - 1 ), { ImageRole } );
|
||||
}
|
||||
|
||||
void
|
||||
ThemesModel::showTheme( const QString& id, bool show )
|
||||
{
|
||||
auto [ i, theme ] = m_themes->indexById( id );
|
||||
if ( theme )
|
||||
{
|
||||
theme->show = show;
|
||||
emit dataChanged( index( i, 0 ), index( i, 0 ), { ShownRole } );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ThemesModel::showOnlyThemes( const QMap< QString, QString >& onlyThese )
|
||||
{
|
||||
if ( m_themes->isEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// No signal blocker block needed here because we're not calling showTheme()
|
||||
// QSignalBlocker b( this );
|
||||
for ( auto& t : *m_themes )
|
||||
{
|
||||
t.show = onlyThese.contains( t.id );
|
||||
}
|
||||
emit dataChanged( index( 0, 0 ), index( m_themes->count() - 1 ), { ShownRole } );
|
||||
}
|
||||
|
||||
QSize
|
||||
ThemesModel::imageSize()
|
||||
{
|
||||
return { qMax( 12 * CalamaresUtils::defaultFontHeight(), 120 ),
|
||||
qMax( 8 * CalamaresUtils::defaultFontHeight(), 80 ) };
|
||||
}
|
||||
|
||||
void
|
||||
ThemesModel::select( const QString& themeId )
|
||||
{
|
||||
int i = 0;
|
||||
for ( auto& t : *m_themes )
|
||||
{
|
||||
if ( t.selected && t.id != themeId )
|
||||
{
|
||||
t.selected = false;
|
||||
emit dataChanged( index( i, 0 ), index( i, 0 ), { SelectedRole } );
|
||||
}
|
||||
if ( !t.selected && t.id == themeId )
|
||||
{
|
||||
t.selected = true;
|
||||
emit dataChanged( index( i, 0 ), index( i, 0 ), { SelectedRole } );
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Massage the given @p path to the most-likely
|
||||
* path that actually contains a screenshot. For
|
||||
* empty image paths, returns the QRC path for an
|
||||
* empty screenshot. Returns blank if the path
|
||||
* doesn't exist anywhere in the search paths.
|
||||
*/
|
||||
static QString
|
||||
munge_imagepath( const QString& path )
|
||||
{
|
||||
if ( path.isEmpty() )
|
||||
{
|
||||
return ":/view-preview.png";
|
||||
}
|
||||
|
||||
if ( path.startsWith( '/' ) )
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
if ( QFileInfo::exists( path ) )
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
QFileInfo fi( QDir( Calamares::Branding::instance()->componentDirectory() ), path );
|
||||
if ( fi.exists() )
|
||||
{
|
||||
return fi.absoluteFilePath();
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
ThemeInfo::ThemeInfo( const KPluginMetaData& data )
|
||||
: id( data.pluginId() )
|
||||
, name( data.name() )
|
||||
, description( data.description() )
|
||||
{
|
||||
}
|
||||
|
||||
QPixmap
|
||||
ThemeInfo::loadImage() const
|
||||
{
|
||||
if ( pixmap.isNull() )
|
||||
{
|
||||
|
||||
const QSize image_size( ThemesModel::imageSize() );
|
||||
|
||||
const QString path = munge_imagepath( imagePath );
|
||||
cDebug() << "Loading initial image for" << id << imagePath << "->" << path;
|
||||
QPixmap image( path );
|
||||
if ( image.isNull() )
|
||||
{
|
||||
// Not found or not specified, so convert the name into some (horrible, likely)
|
||||
// color instead.
|
||||
image = QPixmap( image_size );
|
||||
auto hash_color = qHash( imagePath.isEmpty() ? id : imagePath );
|
||||
cDebug() << Logger::SubEntry << "Theme image" << imagePath << "not found, hash" << hash_color;
|
||||
image.fill( QColor( QRgb( hash_color ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << Logger::SubEntry << "Theme image" << image.size();
|
||||
}
|
||||
|
||||
pixmap = image.scaled( image_size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
|
||||
}
|
||||
return pixmap;
|
||||
}
|
@ -10,82 +10,66 @@
|
||||
#ifndef PLASMALNF_THEMEINFO_H
|
||||
#define PLASMALNF_THEMEINFO_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
class KPluginMetaData;
|
||||
class ThemeWidget;
|
||||
class ThemeInfoList;
|
||||
|
||||
/** @brief describes a single plasma LnF theme.
|
||||
*
|
||||
* A theme description has an id, which is really the name of the desktop
|
||||
* file (e.g. org.kde.breeze.desktop), a name which is human-readable and
|
||||
* translated, and an optional image Page, which points to a local screenshot
|
||||
* of that theme.
|
||||
*/
|
||||
struct ThemeInfo
|
||||
class ThemesModel : public QAbstractListModel
|
||||
{
|
||||
QString id;
|
||||
QString name;
|
||||
QString description;
|
||||
QString imagePath;
|
||||
ThemeWidget* widget;
|
||||
Q_OBJECT
|
||||
|
||||
ThemeInfo()
|
||||
: widget( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
explicit ThemeInfo( const QString& _id )
|
||||
: id( _id )
|
||||
, widget( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
explicit ThemeInfo( const QString& _id, const QString& image )
|
||||
: id( _id )
|
||||
, imagePath( image )
|
||||
, widget( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
// Defined in PlasmaLnfPage.cpp
|
||||
explicit ThemeInfo( const KPluginMetaData& );
|
||||
|
||||
bool isValid() const { return !id.isEmpty(); }
|
||||
};
|
||||
|
||||
class ThemeInfoList : public QList< ThemeInfo >
|
||||
{
|
||||
public:
|
||||
/** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */
|
||||
ThemeInfo* findById( const QString& id )
|
||||
enum
|
||||
{
|
||||
for ( ThemeInfo& i : *this )
|
||||
{
|
||||
if ( i.id == id )
|
||||
{
|
||||
return &i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
LabelRole = Qt::DisplayRole,
|
||||
KeyRole = Qt::UserRole,
|
||||
ShownRole, // Should theme be displayed
|
||||
SelectedRole, // Is theme selected
|
||||
DescriptionRole,
|
||||
ImageRole
|
||||
};
|
||||
|
||||
/** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */
|
||||
const ThemeInfo* findById( const QString& id ) const
|
||||
{
|
||||
for ( const ThemeInfo& i : *this )
|
||||
{
|
||||
if ( i.id == id )
|
||||
{
|
||||
return &i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
explicit ThemesModel( QObject* parent );
|
||||
|
||||
/** @brief Checks if a given @p id is in the list of themes. */
|
||||
bool contains( const QString& id ) const { return findById( id ) != nullptr; }
|
||||
int rowCount( const QModelIndex& = QModelIndex() ) const override;
|
||||
QVariant data( const QModelIndex& index, int role ) const override;
|
||||
|
||||
QHash< int, QByteArray > roleNames() const override;
|
||||
|
||||
/// @brief Set the screenshot to go with the given @p id
|
||||
void setThemeImage( const QString& id, const QString& imagePath );
|
||||
|
||||
/// @brief Call setThemeImage( key, value ) for all keys in @p images
|
||||
void setThemeImage( const QMap< QString, QString >& images );
|
||||
|
||||
/// @brief Set whether to show the given theme @p id (or not)
|
||||
void showTheme( const QString& id, bool show = true );
|
||||
|
||||
/// @brief Shows the keys in the @p onlyThese map, and hides the rest
|
||||
void showOnlyThemes( const QMap< QString, QString >& onlyThese );
|
||||
|
||||
/** @brief Mark the @p themeId as current / selected
|
||||
*
|
||||
* One theme can be selected at a time; this will emit data
|
||||
* changed signals for any (one) theme already selected, and
|
||||
* the newly-selected theme. If @p themeId does not name any
|
||||
* theme, none are selected.
|
||||
*/
|
||||
void select( const QString& themeId );
|
||||
|
||||
/** @brief The size of theme Images
|
||||
*
|
||||
* The size is dependent on the font size used by Calamares,
|
||||
* and is constant within one run of Calamares, but may change
|
||||
* if the font settings do between runs.
|
||||
*/
|
||||
static QSize imageSize();
|
||||
|
||||
private:
|
||||
ThemeInfoList* m_themes;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -28,19 +28,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
|
@ -24,10 +24,18 @@ lnftool: "/usr/bin/lookandfeeltool"
|
||||
#
|
||||
# liveuser: "live"
|
||||
|
||||
# If *showAll* is true, then all installed themes are shown in the
|
||||
# UI for selection, even if they are not listed in *themes* (below).
|
||||
# This allows selection of all themes even while not all of them are
|
||||
# listed in *themes* -- which is useful to show screenshots for those
|
||||
# you do have a screenshot for. If *themes* is empty or missing,
|
||||
# the value of *showAll* is treated as `true`.
|
||||
showAll: false
|
||||
|
||||
# You can limit the list of Plasma look-and-feel themes by listing ids
|
||||
# here. If this key is not present, all of the installed themes are listed.
|
||||
# If the key is present, only installed themes that are **also** included
|
||||
# in the list are shown (could be none!). See the *showAll* key, below,
|
||||
# in the list are shown (could be none!). See the *showAll* key, above,
|
||||
# to change that.
|
||||
#
|
||||
# Themes may be listed by id, (e.g. fluffy-bunny, below) or as a theme
|
||||
@ -58,13 +66,6 @@ themes:
|
||||
image: "breeze-dark.png"
|
||||
- org.kde.fluffy-bunny.desktop
|
||||
|
||||
# If *showAll* is true, then all installed themes are shown in the
|
||||
# UI for selection, even if they are not listed in *themes*. This
|
||||
# allows selection of all themes even while not all of them are
|
||||
# listed in *themes* -- which is useful to show screenshots for those
|
||||
# you do have a screenshot for.
|
||||
showAll: false
|
||||
|
||||
# You can pre-select one of the themes; it is not applied
|
||||
# immediately, but its radio-button is switched on to indicate
|
||||
# that that is the theme (that is most likely) currently in use.
|
||||
|
Loading…
Reference in New Issue
Block a user