Initial upload of HyprArch releng configuration

This commit is contained in:
2026-03-03 20:31:33 +00:00
commit 7df61351c0
634 changed files with 36355 additions and 0 deletions

View File

@@ -0,0 +1,326 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
* SPDX-FileCopyrightText: 2018 Raul Rodrigo Segura (raurodse)
* SPDX-FileCopyrightText: 2019 Camilo Higuita <milo.h@aol.com>
* SPDX-FileCopyrightText: 2021 Anubhav Choudhary <ac.10edu@gmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef BRANDING_H
#define BRANDING_H
#include "CalamaresConfig.h"
#include "DllMacro.h"
#include "utils/NamedSuffix.h"
#include <QMap>
#include <QObject>
#include <QPixmap>
#include <QSize>
#include <QStringList>
#include <QUrl>
namespace YAML
{
class Node;
} // namespace YAML
namespace Calamares
{
class GlobalStorage;
class UIDLLEXPORT Branding : public QObject
{
Q_OBJECT
public:
/**
* Descriptive strings in the configuration file. use
* e.g. *Branding::ProductName to get the string value for
* the product name.
*/
enum StringEntry
{
ProductName,
Version,
ShortVersion,
VersionedName,
ShortVersionedName,
ShortProductName,
BootloaderEntryName,
ProductUrl,
SupportUrl,
KnownIssuesUrl,
ReleaseNotesUrl,
DonateUrl
};
Q_ENUM( StringEntry )
enum ImageEntry : short
{
ProductBanner,
ProductIcon,
ProductLogo,
ProductWallpaper,
ProductWelcome
};
Q_ENUM( ImageEntry )
/** @brief Names of style entries, for use in code
*
* These names are mapped to names in the branding.desc file through
* an internal table s_styleEntryStrings, which defines which names
* in `branding.desc` key *style* are used for which entry.
*/
enum StyleEntry : short
{
SidebarBackground,
SidebarText,
SidebarTextCurrent,
SidebarBackgroundCurrent,
};
Q_ENUM( StyleEntry )
/** @brief Supported log-upload servers.
*
* 'None' is here as a fallback.
*/
enum UploadServerType : short
{
None,
Fiche
};
Q_ENUM( UploadServerType )
/** @brief Setting for how much the main window may expand. */
enum class WindowExpansion
{
Normal,
Fullscreen,
Fixed
};
Q_ENUM( WindowExpansion )
/** @brief Setting for the main window size.
*
* The units are pixels (Pixies) or something-based-on-fontsize (Fonties), which
* we suffix as "em", e.g. "600px" or "32em".
*/
enum class WindowDimensionUnit
{
None,
Pixies,
Fonties
};
Q_ENUM( WindowDimensionUnit )
class WindowDimension : public NamedSuffix< WindowDimensionUnit, WindowDimensionUnit::None >
{
public:
static const NamedEnumTable< WindowDimensionUnit >& suffixes();
bool isValid() const;
using NamedSuffix::NamedSuffix;
WindowDimension( const QString& s )
: NamedSuffix( suffixes(), s )
{
}
};
/** @brief Placement of main window.
*/
enum class WindowPlacement
{
Center,
Free
};
Q_ENUM( WindowPlacement )
///@brief What kind of panel (sidebar, navigation) to use in the main window
enum class PanelFlavor
{
None,
Widget
#ifdef WITH_QML
,
Qml
#endif
};
Q_ENUM( PanelFlavor )
///@brief Where to place a panel (sidebar, navigation)
enum class PanelSide
{
None,
Left,
Right,
Top,
Bottom
};
Q_ENUM( PanelSide )
static Branding* instance();
explicit Branding( const QString& brandingFilePath, QObject* parent = nullptr, qreal devicePixelRatio = 1.0 );
/** @brief Complete path of the branding descriptor file. */
QString descriptorPath() const { return m_descriptorPath; }
/** @brief The component name found in the descriptor file.
*
* The component name always matches the last directory name in the path.
*/
QString componentName() const { return m_componentName; }
/** @brief The directory holding all of the branding assets. */
QString componentDirectory() const;
/** @brief The directory where branding translations live.
*
* This is componentDir + "/lang".
*/
QString translationsDirectory() const { return m_translationsPathPrefix; }
/** @brief Path to the slideshow QML file, if any. (API == 1 or 2)*/
QString slideshowPath() const { return m_slideshowPath; }
/// @brief List of pathnames of slideshow images, if any. (API == -1)
QStringList slideshowImages() const { return m_slideshowFilenames; }
/** @brief Which slideshow API to use for the slideshow?
*
* - 2 For QML-based slideshows loaded asynchronously (current)
* - 1 For QML-based slideshows, loaded when shown (legacy)
* - -1 For oldschool image-slideshows.
*/
int slideshowAPI() const { return m_slideshowAPI; }
QPixmap image( Branding::ImageEntry imageEntry, const QSize& size ) const;
/** @brief Look up an image in the branding directory or as an icon
*
* The @p name is checked in the branding directory: if it is an image
* file, return the pixmap from that file, at the requested size.
* If it isn't a file, look it up as an icon name in the current theme.
* May return a null pixmap if nothing is found.
*/
QPixmap image( const QString& name, const QSize& size ) const;
/** @brief Look up image with alternate names
*
* Calls image() for each name in the @p list and returns the first
* one that is non-null. May return a null pixmap if nothing is found.
*/
QPixmap image( const QStringList& list, const QSize& size ) const;
/** @brief Stylesheet to apply for this branding. May be empty.
*
* The file is loaded every time this function is called, so
* it may be quite expensive -- although normally it will be
* called only once, on startup. (Or from the debug window)
*/
QString stylesheet() const;
bool welcomeStyleCalamares() const { return m_welcomeStyleCalamares; }
bool welcomeExpandingLogo() const { return m_welcomeExpandingLogo; }
bool windowMaximize() const { return m_windowExpansion == WindowExpansion::Fullscreen; }
bool windowExpands() const { return m_windowExpansion != WindowExpansion::Fixed; }
QPair< WindowDimension, WindowDimension > windowSize() const
{
return QPair< WindowDimension, WindowDimension >( m_windowWidth, m_windowHeight );
}
bool windowPlacementCentered() const { return m_windowPlacement == WindowPlacement::Center; }
///@brief Which sidebar flavor is configured
PanelFlavor sidebarFlavor() const { return m_sidebarFlavor; }
///@brief Which navigation flavor is configured
PanelFlavor navigationFlavor() const { return m_navigationFlavor; }
/** @brief Upload server configuration
*
* This object has 3 items : the type (which may be none, in which case the URL
* is irrelevant and usually empty), the URL for the upload and the size limit of upload
* in bytes (for configuration value < 0, it serves -1, which stands for having no limit).
*/
struct UploadServerInfo
{
UploadServerType type;
QUrl url;
qint64 size;
operator bool() const { return type != Calamares::Branding::UploadServerType::None && size != 0; }
};
UploadServerInfo uploadServer() const { return m_uploadServer; }
/**
* Creates a map called "branding" in the global storage, and inserts an
* entry for each of the branding strings. This makes the branding
* information accessible to the Python modules.
*/
void setGlobals( GlobalStorage* globalStorage ) const;
public slots:
QString string( StringEntry stringEntry ) const;
QString versionedName() const { return string( VersionedName ); }
QString productName() const { return string( ProductName ); }
QString shortProductName() const { return string( ShortProductName ); }
QString shortVersionedName() const { return string( ShortVersionedName ); }
/** @brief Map an enum-value to the entry from the *style* key.
*
* e.g. StyleEntry::SidebarTextCurrent maps to the corresponding
* *style* entry, which is (confusingly) named "sidebarTextSelect"
* in the branding file.
*/
QString styleString( StyleEntry styleEntry ) const;
QString imagePath( ImageEntry imageEntry ) const;
PanelSide sidebarSide() const { return m_sidebarSide; }
PanelSide navigationSide() const { return m_navigationSide; }
private:
static Branding* s_instance;
static const QStringList s_stringEntryStrings;
static const QStringList s_imageEntryStrings;
static const QStringList s_uploadServerStrings;
QString m_descriptorPath; // Path to descriptor (e.g. "/etc/calamares/default/branding.desc")
QString m_componentName; // Matches last part of full path to containing directory
QMap< QString, QString > m_strings;
QMap< QString, QString > m_images;
QMap< QString, QString > m_style;
UploadServerInfo m_uploadServer;
/* The slideshow can be done in one of two ways:
* - as a sequence of images
* - as a QML file
* The slideshow: setting selects which one is used. If it is
* a list (of filenames) then it is a sequence of images, and otherwise
* it is a QML file which is run. (For QML, the slideshow API is
* important).
*/
QStringList m_slideshowFilenames;
QString m_slideshowPath;
int m_slideshowAPI;
QString m_translationsPathPrefix;
/** @brief Initialize the simple settings below */
void initSimpleSettings( const YAML::Node& doc );
///@brief Initialize the slideshow settings, above
void initSlideshowSettings( const YAML::Node& doc );
bool m_welcomeStyleCalamares;
bool m_welcomeExpandingLogo;
WindowExpansion m_windowExpansion;
WindowDimension m_windowHeight, m_windowWidth;
WindowPlacement m_windowPlacement;
PanelFlavor m_sidebarFlavor = PanelFlavor::Widget;
PanelFlavor m_navigationFlavor = PanelFlavor::Widget;
PanelSide m_sidebarSide = PanelSide::Left;
PanelSide m_navigationSide = PanelSide::Bottom;
qreal m_devicePixelRatio;
};
} // namespace Calamares
#endif // BRANDING_H

View File

@@ -0,0 +1,31 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2022 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARES_CALAMARESABOUT_H
#define CALAMARES_CALAMARESABOUT_H
#include "DllMacro.h"
#include <QString>
namespace Calamares
{
/** @brief Returns an about string for the application
*
* The about string includes a header-statement, a list of maintainer
* addresses, and a thank-you to Blue Systems. There is on %-substitution
* left, where you can fill in the name of the product (e.g. to say
* "Calamares for Netrunner" or ".. for Manjaro").
*/
DLLEXPORT const QString aboutStringUntranslated();
/// @brief As above, but translated in the current Calamares language
DLLEXPORT const QString aboutString();
} // namespace Calamares
#endif

View File

@@ -0,0 +1,34 @@
/* === 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 CALAMARESCONFIG_H
#define CALAMARESCONFIG_H
#define CMAKE_INSTALL_PREFIX "/usr"
#define CMAKE_INSTALL_FULL_LIBEXECDIR "/usr/libexec"
#define CMAKE_INSTALL_LIBDIR "lib"
#define CMAKE_INSTALL_FULL_LIBDIR "/usr/lib"
#define CMAKE_INSTALL_FULL_DATADIR "/usr/share/calamares"
#define CMAKE_INSTALL_FULL_SYSCONFDIR "/etc"
#define CMAKE_BUILD_TYPE "Release"
/*
* These are feature-settings that affect consumers of Calamares
* libraries as well; without Python-support in the libs, for instance,
* there's no point in having a Python plugin.
*
* This list should match the one in CalamaresConfig.cmake
* which is the CMake-time side of the same configuration.
*/
#define WITH_PYTHON
#define WITH_PYBIND11
/* #undef WITH_BOOST_PYTHON */
#define WITH_QML
#define WITH_QT6
#endif // CALAMARESCONFIG_H

View File

@@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: no
// SPDX-License-Identifier: CC0-1.0
#ifndef CALAMARES_VERSION_H
#define CALAMARES_VERSION_H
#define CALAMARES_ORGANIZATION_NAME "Calamares"
#define CALAMARES_ORGANIZATION_DOMAIN "calamares.io"
#define CALAMARES_APPLICATION_NAME "Calamares"
#define CALAMARES_VERSION "3.4.0"
#define CALAMARES_VERSION_SHORT "3.4.0"
#define CALAMARES_VERSION_MAJOR "3"
#define CALAMARES_VERSION_MINOR "4"
/* #undef CALAMARES_VERSION_PATCH */
/* #undef CALAMARES_VERSION_RC */
#endif // CALAMARES_VERSION_H

View File

@@ -0,0 +1,44 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2016 Kevin Kofler <kevin.kofler@chello.at>
* 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 CALAMARES_CPPJOB_H
#define CALAMARES_CPPJOB_H
#include "DllMacro.h"
#include "Job.h"
#include "modulesystem/InstanceKey.h"
#include <QObject>
#include <QVariant>
namespace Calamares
{
class DLLEXPORT CppJob : public Job
{
Q_OBJECT
public:
explicit CppJob( QObject* parent = nullptr );
~CppJob() override;
void setModuleInstanceKey( const Calamares::ModuleSystem::InstanceKey& instanceKey );
Calamares::ModuleSystem::InstanceKey moduleInstanceKey() const { return m_instanceKey; }
virtual void setConfigurationMap( const QVariantMap& configurationMap );
protected:
Calamares::ModuleSystem::InstanceKey m_instanceKey;
};
} // namespace Calamares
#endif // CALAMARES_CPPJOB_H

View File

@@ -0,0 +1,68 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* 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 DLLMACRO_H
#define DLLMACRO_H
#ifndef CALAMARES_EXPORT
#define CALAMARES_EXPORT __attribute__( ( visibility( "default" ) ) )
#endif
/*
* Mark symbols exported from Calamares non-GUI library with DLLEXPORT.
* These are the public API of libcalamares.
*/
#ifndef DLLEXPORT
#if defined( DLLEXPORT_PRO )
#define DLLEXPORT CALAMARES_EXPORT
#else
#define DLLEXPORT
#endif
#endif
/*
* Mark symbols exported from Calamares GUI library with DLLEXPORT.
* These are the public API of libcalamaresui.
*/
#ifndef UIDLLEXPORT
#if defined( UIDLLEXPORT_PRO )
#define UIDLLEXPORT CALAMARES_EXPORT
#else
#define UIDLLEXPORT
#endif
#endif
/*
* Mark symbols exported from Calamares C++ plugins with PLUGINDLLEXPORT.
* These are the public API of the libraries (generally, the plugin
* entry point)
*/
#ifndef PLUGINDLLEXPORT
#if defined( PLUGINDLLEXPORT_PRO )
#define PLUGINDLLEXPORT CALAMARES_EXPORT
#else
#define PLUGINDLLEXPORT
#endif
#endif
/*
* For functions that should be static in production but also need to
* be tested, use STATICTEST as linkage specifier. When built as part
* of a test, the function will be given normal linkage.
*/
#ifndef STATICTEST
#if defined( BUILD_AS_TEST )
#define STATICTEST
#else
#define STATICTEST static
#endif
#endif
#endif

View File

@@ -0,0 +1,192 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_GLOBALSTORAGE_H
#define CALAMARES_GLOBALSTORAGE_H
#include "DllMacro.h"
#include <QMutex>
#include <QObject>
#include <QString>
#include <QVariantMap>
namespace Calamares
{
/** @brief Storage for data that passes between Calamares modules.
*
* The Global Storage is global to the Calamares JobQueue and
* everything that depends on that: all of its modules use the
* same instance of the JobQueue, and so of the Global Storage.
*
* GS is used to pass data between modules; there is only convention
* about what keys are used, and individual modules should document
* what they put in to GS or what they expect to find in it.
*
* GS behaves as a basic key-value store, with a QVariantMap behind
* it. Any QVariant can be put into the storage, and the signal
* changed() is emitted when any data is modified.
*
* In general, see QVariantMap (possibly after calling data()) for details.
*
* This class is thread-safe -- most accesses go through JobQueue, which
* handles threading itself, but because modules load in parallel and can
* have asynchronous tasks like GeoIP lookups, the storage itself also
* has locking. All methods are thread-safe, use data() to make a snapshot
* copy for use outside of the thread-safe API.
*/
class DLLEXPORT GlobalStorage : public QObject
{
Q_OBJECT
public:
/** @brief Create a GS object
*
* **Generally** there is only one GS object (hence, "global") which
* is owned by the JobQueue instance (which is a singleton). However,
* it is possible to create more GS objects.
*/
explicit GlobalStorage( QObject* parent = nullptr );
/** @brief Insert a key and value into the store
*
* The @p value is added to the store with key @p key. If @p key
* already exists in the store, its existing value is overwritten.
* The changed() signal is emitted regardless.
*/
void insert( const QString& key, const QVariant& value );
/** @brief Removes a key and its value
*
* The @p key is removed from the store. If the @p key does not
* exist, nothing happens. changed() is emitted regardless.
*
* @return the number of keys remaining
*/
int remove( const QString& key );
/// @brief Clears all keys in this GS object
void clear();
/** @brief dump keys and values to the debug log
*
* All the keys and their values are written to the debug log.
* See save() for caveats: this can leak sensitive information.
*/
void debugDump() const;
/** @brief write as JSON to the given filename
*
* The file named @p filename is overwritten with a JSON representation
* of the entire global storage (this may be structured, for instance
* if maps or lists have been inserted).
*
* No tidying, sanitization, or censoring is done -- for instance,
* the user module sets a slightly-obscured password in global storage,
* and this JSON file will contain that password in-the-only-slightly-
* obscured form.
*/
bool saveJson( const QString& filename ) const;
/** @brief Adds the keys from the given JSON file
*
* No tidying, sanitization, or censoring is done.
* The JSON file is read and each key is added as a value to
* the global storage. The storage is not cleared first: existing
* keys will remain; keys that also occur in the JSON file are overwritten.
*/
bool loadJson( const QString& filename );
/** @brief write as YAML to the given filename
*
* See also save(), above.
*/
bool saveYaml( const QString& filename ) const;
/** @brief reads settings from the given filename
*
* See also load(), above.
*/
bool loadYaml( const QString& filename );
/** @brief Make a complete copy of the data
*
* Provides a snapshot of the data at a given time.
*/
QVariantMap data() const { return m; }
public Q_SLOTS:
/** @brief Does the store contain the given key?
*
* This can distinguish an explicitly-inserted QVariant() from
* a no-value-exists QVariant. See value() for details.
*/
bool contains( const QString& key ) const;
/** @brief The number of keys in the store
*
* This should be unsigned, but the underlying QMap uses signed as well.
* Equal to keys().length(), in theory.
*/
int count() const;
/** @brief The keys in the store
*
* This makes a copy of all the keys currently in the store, which
* could be used for iterating over all the values in the store.
*/
QStringList keys() const;
/** @brief Gets a value from the store
*
* If a value has been previously inserted, returns that value.
* If @p key does not exist in the store, returns a QVariant()
* (an invalid QVariant, which boolean-converts to false). Since
* QVariant() van also be inserted explicitly, use contains()
* to check for the presence of a key if you need that.
*/
QVariant value( const QString& key ) const;
signals:
/** @brief Emitted any time the store changes
*
* Also emitted sometimes when the store does not change, e.g.
* when removing a non-existent key or inserting a value that
* is already present.
*/
void changed();
private:
class ReadLock;
class WriteLock;
QVariantMap m;
mutable QMutex m_mutex;
};
/** @brief Gets a value from the store
*
* When @p nestedKey contains no '.' characters, equivalent
* to `gs->value(nestedKey)`. Otherwise recursively looks up
* the '.'-separated parts of @p nestedKey in successive sub-maps
* of the store, returning the value in the innermost one.
*
* Example: `lookup(gs, "branding.name")` finds the value of the
* 'name' key in the 'branding' submap of the store.
*
* Sets @p ok to @c true if a value was found. Returns the value
* as a variant. If no value is found (e.g. the key is missing
* or some prefix submap is missing) sets @p ok to @c false
* and returns an invalid QVariant.
*
* @see GlobalStorage::value
*/
DLLEXPORT QVariant lookup( const GlobalStorage* gs, const QString& nestedKey, bool& ok );
} // namespace Calamares
#endif // CALAMARES_GLOBALSTORAGE_H

View File

@@ -0,0 +1,175 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_JOB_H
#define CALAMARES_JOB_H
#include "DllMacro.h"
#include <QList>
#include <QObject>
#include <QSharedPointer>
namespace Calamares
{
class DLLEXPORT JobResult
{
public:
/** @brief Distinguish classes of errors
*
* All "ok result" have errorCode 0 (NoError).
* Errors returned from job execution have values < 0.
* Errors before job execution, or not returned by the job execution
* itself, have values > 0.
*/
enum
{
NoError = 0,
GenericError = -1,
PythonUncaughtException = 1,
InvalidConfiguration = 2,
MissingRequirements = 3,
};
// Can't copy, but you can keep a temporary
JobResult( const JobResult& rhs ) = delete;
JobResult( JobResult&& rhs );
virtual ~JobResult() {}
/** @brief Is this JobResult a success?
*
* Equivalent to errorCode() == 0, see succeeded().
*/
virtual operator bool() const;
virtual QString message() const;
virtual void setMessage( const QString& message );
virtual QString details() const;
virtual void setDetails( const QString& details );
int errorCode() const { return m_number; }
/** @brief Is this JobResult a success?
*
* Equivalent to errorCode() == 0.
*/
bool succeeded() const { return this->operator bool(); }
/// @brief an "ok status" result
static JobResult ok();
/** @brief an "error" result resulting from the execution of the job
*
* The error code is set to GenericError.
*/
static JobResult error( const QString& message, const QString& details = QString() );
/** @brief an "internal error" meaning the job itself has a problem (usually for python)
*
* Pass in a suitable error code; using 0 (which would normally mean "ok") instead
* gives you a GenericError code.
*/
static JobResult internalError( const QString& message, const QString& details, int errorCode );
protected:
explicit JobResult( const QString& message, const QString& details, int errorCode );
private:
QString m_message;
QString m_details;
int m_number;
};
class DLLEXPORT Job : public QObject
{
Q_OBJECT
public:
explicit Job( QObject* parent = nullptr );
~Job() override;
/** @brief The job's (relative) weight.
*
* The default implementation returns 1, which gives all jobs
* the same weight, so they advance the overall progress the same
* amount. This is nonsense, since some jobs take much longer than
* others; it's up to the individual jobs to say something about
* how much work is (relatively) done.
*
* Since jobs are caused by **modules** from the sequence, the
* overall weight of the module is taken into account: its weight
* is divided among the jobs based on each jobs relative weight.
* This can be used in a module that runs a bunch of jobs to indicate
* which of the jobs is "heavy" and which is not.
*/
virtual int getJobWeight() const;
/** @brief The human-readable name of this job
*
* This should be a very short statement of what the job does.
* For status and state information, see prettyStatusMessage().
*
* The job's name may be similar to the status message, but this is
* a name, and should not be an active verb phrase. The translation
* should use context @c \@label .
*
* The name of the job is used as a **fallback** when the status
* or descriptions are empty. If a job has no implementation of
* those methods, it is OK to use other contexts, but it may look
* strange in some places in the UI.
*/
virtual QString prettyName() const = 0;
/** @brief a longer human-readable description of what the job will do
*
* This **may** be used by view steps to fill in the summary
* messages for the summary page; at present, only the *partition*
* module does so.
*
* The default implementation returns an empty string.
*
* The translation should use context @c \@title .
*/
virtual QString prettyDescription() const;
/** @brief A human-readable status for progress reporting
*
* This is called from the JobQueue when progress is made, and should
* return a not-too-long description of the job's status. This
* is made visible in the progress bar of the execution view step.
*
* The job's status should say **what** the job is doing. It should be in
* present active tense. Typically the translation uses tr() context
* @c \@status . See prettyName() for examples.
*/
virtual QString prettyStatusMessage() const;
virtual JobResult exec() = 0;
bool isEmergency() const { return m_emergency; }
void setEmergency( bool e ) { m_emergency = e; }
signals:
/** @brief Signals that the job has made progress
*
* The parameter @p percent should be between 0 (0%) and 1 (100%).
* Values outside of this range will be clamped.
*/
void progress( qreal percent );
private:
bool m_emergency = false;
};
using job_ptr = QSharedPointer< Job >;
using JobList = QList< job_ptr >;
} // namespace Calamares
#endif // CALAMARES_JOB_H

View File

@@ -0,0 +1,69 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARES_JOB_EXAMPLE_H
#define CALAMARES_JOB_EXAMPLE_H
#include "Job.h"
namespace Calamares
{
/** @brief A Job with a name
*
* This includes a default implementation of prettyName(),
* but is only used as a base for FailJob and GoodJob,
* which are support / bogus classes.
*/
class DLLEXPORT NamedJob : public Job
{
Q_OBJECT
public:
explicit NamedJob( const QString& name, QObject* parent = nullptr )
: Job( parent )
, m_name( name )
{
}
virtual QString prettyName() const override;
protected:
const QString m_name;
};
/// @brief Job does nothing, always succeeds
class DLLEXPORT GoodJob : public NamedJob
{
Q_OBJECT
public:
explicit GoodJob( const QString& name, QObject* parent = nullptr )
: NamedJob( name, parent )
{
}
virtual JobResult exec() override;
};
/// @brief Job does nothing, always fails
class DLLEXPORT FailJob : public NamedJob
{
Q_OBJECT
public:
explicit FailJob( const QString& name, QObject* parent = nullptr )
: NamedJob( name, parent )
{
}
virtual JobResult exec() override;
};
} // namespace Calamares
#endif // CALAMARES_JOB_EXAMPLE_H

View File

@@ -0,0 +1,122 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARES_JOBQUEUE_H
#define CALAMARES_JOBQUEUE_H
#include "DllMacro.h"
#include "Job.h"
#include <QObject>
namespace Calamares
{
class GlobalStorage;
class JobThread;
///@brief RAII class to suppress sleep / suspend during its lifetime
class DLLEXPORT SleepInhibitor : public QObject
{
Q_OBJECT
public:
SleepInhibitor();
~SleepInhibitor() override;
};
class DLLEXPORT JobQueue : public QObject
{
Q_OBJECT
public:
explicit JobQueue( QObject* parent = nullptr );
~JobQueue() override;
/** @brief Returns the most-recently-created instance.
*
* It is possible for instance() to be @c nullptr, since you must
* call the constructor explicitly first.
*/
static JobQueue* instance();
/* @brief Returns the GlobalStorage object for the instance.
*
* It is possible for instanceGlobalStorage() to be @c nullptr,
* since there might not be an instance to begin with.
*/
static GlobalStorage* instanceGlobalStorage()
{
auto* jq = instance();
return jq ? jq->globalStorage() : nullptr;
}
GlobalStorage* globalStorage() const;
/** @brief Queues up jobs from a single module source
*
* The total weight of the jobs is spread out to fill the weight
* of the module.
*/
void enqueue( int moduleWeight, const JobList& jobs );
/** @brief Starts all the jobs that are enqueued.
*
* After this, isRunning() returns @c true until
* finished() is emitted.
*/
void start();
bool isRunning() const { return !m_finished; }
signals:
/** @brief Report progress of the whole queue, with a status message
*
* The @p percent is a value between 0.0 and 1.0 (100%) of the
* overall queue progress (not of the current job), while
* @p prettyName is the status message from the job -- often
* just the name of the job, but some jobs include more information.
*/
void progress( qreal percent, const QString& prettyName );
/** @brief Indicate that the queue is empty, after calling start()
*
* Emitted when the queue empties. The queue may also emit
* failed(), if something went wrong, but finished() is always
* the last one.
*/
void finished();
/** @brief A job in the queue failed.
*
* Contains the (already-translated) text from the job describing
* the failure.
*/
void failed( const QString& message, const QString& details );
/** @brief Reports the names of jobs in the queue.
*
* When jobs are added via enqueue(), or when the queue otherwise
* changes, the **names** of the jobs are reported. This is
* primarily for debugging purposes.
*/
void queueChanged( const QStringList& jobNames );
public Q_SLOTS:
/** @brief Implementation detail
*
* This is a private implementation detail for the job thread,
* which should not be called by other core.
*/
void finish();
private:
static JobQueue* s_instance;
JobThread* m_thread;
GlobalStorage* m_storage;
bool m_finished = true; ///< Initially, not running
};
} // namespace Calamares
#endif // CALAMARES_JOBQUEUE_H

View File

@@ -0,0 +1,46 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARES_PROCESSJOB_H
#define CALAMARES_PROCESSJOB_H
#include "DllMacro.h"
#include "Job.h"
#include <chrono>
namespace Calamares
{
class DLLEXPORT ProcessJob : public Job
{
Q_OBJECT
public:
explicit ProcessJob( const QString& command,
const QString& workingPath,
bool runInChroot = false,
std::chrono::seconds secondsTimeout = std::chrono::seconds( 30 ),
QObject* parent = nullptr );
~ProcessJob() override;
QString prettyName() const override;
QString prettyStatusMessage() const override;
JobResult exec() override;
private:
QString m_command;
QString m_workingPath;
bool m_runInChroot;
std::chrono::seconds m_timeoutSec;
};
} // namespace Calamares
#endif // CALAMARES_PROCESSJOB_H

View File

@@ -0,0 +1,205 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2019 Gabriel Craciunescu <crazy@frugalware.org>
* SPDX-FileCopyrightText: 2019 Dominic Hayes <ferenosdev@outlook.com>
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef SETTINGS_H
#define SETTINGS_H
#include "DllMacro.h"
#include "modulesystem/Actions.h"
#include "modulesystem/InstanceKey.h"
#include <QObject>
#include <QStringList>
namespace Calamares
{
/** @brief Description of an instance as named in `settings.conf`
*
* An instance is an intended-step-in-sequence; it is not yet
* a loaded module. The instances have config-files and weights
* which are used by the module manager when loading modules
* and creating jobs.
*/
class DLLEXPORT InstanceDescription
{
using InstanceKey = Calamares::ModuleSystem::InstanceKey;
public:
/** @brief An invalid InstanceDescription
*
* Use `fromSettings()` to populate an InstanceDescription and
* check its validity.
*/
InstanceDescription() = default;
/** @brief An InstanceDescription with no special settings.
*
* Regardless of @p key being custom, sets weight to 1 and
* the configuration file to @c key.module() (plus the ".conf"
* extension).
*
* To InstanceDescription is custom if the key is.
*/
InstanceDescription( const InstanceKey& key );
static InstanceDescription fromSettings( const QVariantMap& );
bool isValid() const { return m_instanceKey.isValid(); }
const InstanceKey& key() const { return m_instanceKey; }
QString configFileName() const { return m_configFileName; }
bool isCustom() const { return m_instanceKey.isCustom(); }
int weight() const { return m_weight < 0 ? 1 : m_weight; }
bool explicitWeight() const { return m_weight > 0; }
private:
InstanceKey m_instanceKey;
QString m_configFileName;
int m_weight = 0;
};
class DLLEXPORT Settings : public QObject
{
Q_OBJECT
#ifdef BUILD_AS_TEST
public:
#endif
explicit Settings( bool debugMode );
explicit Settings( const QString& settingsFilePath, bool debugMode );
void setConfiguration( const QByteArray& configData, const QString& explainName );
void reconcileInstancesAndSequence();
public:
static Settings* instance();
/// @brief Find a settings.conf, following @p debugMode
static Settings* init( bool debugMode );
/// @brief Explicif filename, debug is always true (for testing)
static Settings* init( const QString& filename );
/// @brief Get the path this settings was created for (may be empty)
QString path() const { return m_settingsPath; }
QStringList modulesSearchPaths() const;
using InstanceDescriptionList = QList< InstanceDescription >;
/** @brief All the module instances used
*
* Each module-instance mentioned in `settings.conf` has an entry
* in the moduleInstances list -- both custom entries that are
* in the *instances* section, and each module mentioned in the
* *sequence*.
*/
InstanceDescriptionList moduleInstances() const;
using ModuleSequence = QList< QPair< ModuleSystem::Action, Calamares::ModuleSystem::InstanceKeyList > >;
/** @brief Representation of *sequence* of execution
*
* Each "section" of the *sequence* key in `settings.conf` gets an
* entry here, stating what kind of action is taken and which modules
* take part (in order). Each entry in the list is an instance key
* which can be found in the moduleInstances() list.
*/
ModuleSequence modulesSequence() const;
QString brandingComponentName() const;
/** @brief Are the settings consistent and valid?
*
* Checks that at least branding is set, and that the instances
* and sequence are valid.
*/
bool isValid() const;
/** @brief Is this a debugging run?
*
* Returns true if Calamares is in debug mode. In debug mode,
* modules and settings are loaded from more locations, to help
* development and debugging.
*/
bool debugMode() const { return m_debug; }
/** @brief Distinguish "install" from "OEM" modes.
*
* Returns true in "install" mode, which is where actions happen
* in a chroot -- the target system, which exists separately from
* the source system. In "OEM" mode, returns false and most actions
* apply to the *current* (host) system.
*/
bool doChroot() const { return m_doChroot; }
/** @brief Global setting of prompt-before-install.
*
* Returns true when the configuration is such that the user
* should be prompted one-last-time before any action is taken
* that really affects the machine.
*/
bool showPromptBeforeExecution() const { return m_promptInstall; }
/** @brief Distinguish between "install" and "setup" modes.
*
* This influences user-visible strings, for instance using the
* word "setup" instead of "install" where relevant.
*/
bool isSetupMode() const { return m_isSetupMode; }
/** @brief Returns whether the named module is enabled
*
* Returns true if @p module is enabled in settings.conf. Be aware that it
* only tests for a specific module name so if a QML and non-QML version
* of the same module exists, it must be specified explicitly
*
* @p module is a module name or module key e.g. packagechooser) and not a
* full module key+id (e.g. packagechooser@packagechooser)
*
*/
bool isModuleEnabled( const QString& module ) const;
/** @brief Global setting of disable-cancel: can't cancel ever. */
bool disableCancel() const { return m_disableCancel; }
/** @brief Temporary setting of disable-cancel: can't cancel during exec. */
bool disableCancelDuringExec() const { return m_disableCancelDuringExec; }
bool hideBackAndNextDuringExec() const { return m_hideBackAndNextDuringExec; }
/** @brief Is quit-at-end set? (Quit automatically when done) */
bool quitAtEnd() const { return m_quitAtEnd; }
private:
static Settings* s_instance;
QString m_settingsPath;
QStringList m_modulesSearchPaths;
InstanceDescriptionList m_moduleInstances;
ModuleSequence m_modulesSequence;
QString m_brandingComponentName;
// bools are initialized here according to default setting
bool m_debug;
bool m_doChroot = true;
bool m_isSetupMode = false;
bool m_promptInstall = false;
bool m_disableCancel = false;
bool m_disableCancelDuringExec = false;
bool m_hideBackAndNextDuringExec = false;
bool m_quitAtEnd = false;
};
} // namespace Calamares
#endif // SETTINGS_H

View File

@@ -0,0 +1,296 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef VIEWMANAGER_H
#define VIEWMANAGER_H
#include "DllMacro.h"
#include "viewpages/ViewStep.h"
#include <QAbstractListModel>
#include <QList>
#include <QPushButton>
#include <QStackedWidget>
namespace Calamares
{
/**
* @brief The ViewManager class handles progression through view pages.
* @note Singleton object, only use through ViewManager::instance().
*/
class UIDLLEXPORT ViewManager : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY( int currentStepIndex READ currentStepIndex NOTIFY currentStepChanged FINAL )
Q_PROPERTY( bool nextEnabled READ nextEnabled NOTIFY nextEnabledChanged FINAL )
Q_PROPERTY( QString nextLabel READ nextLabel NOTIFY nextLabelChanged FINAL )
Q_PROPERTY( QString nextIcon READ nextIcon NOTIFY nextIconChanged FINAL )
Q_PROPERTY( bool backEnabled READ backEnabled NOTIFY backEnabledChanged FINAL )
Q_PROPERTY( QString backLabel READ backLabel NOTIFY backLabelChanged FINAL )
Q_PROPERTY( QString backIcon READ backIcon NOTIFY backIconChanged FINAL )
Q_PROPERTY( bool quitEnabled READ quitEnabled NOTIFY quitEnabledChanged FINAL )
Q_PROPERTY( QString quitLabel READ quitLabel NOTIFY quitLabelChanged FINAL )
Q_PROPERTY( QString quitIcon READ quitIcon NOTIFY quitIconChanged FINAL )
Q_PROPERTY( QString quitTooltip READ quitTooltip NOTIFY quitTooltipChanged FINAL )
Q_PROPERTY( bool quitVisible READ quitVisible NOTIFY quitVisibleChanged FINAL )
Q_PROPERTY( bool backAndNextVisible READ backAndNextVisible NOTIFY backAndNextVisibleChanged FINAL )
///@brief Sides on which the ViewManager has side-panels
Q_PROPERTY( Qt::Orientations panelSides READ panelSides WRITE setPanelSides MEMBER m_panelSides )
// Global properties, where ViewManager proxies to Settings
Q_PROPERTY( bool isDebugMode READ isDebugMode CONSTANT FINAL )
Q_PROPERTY( bool isChrootMode READ isChrootMode CONSTANT FINAL )
Q_PROPERTY( bool isSetupMode READ isSetupMode CONSTANT FINAL )
Q_PROPERTY( QString logFilePath READ logFilePath CONSTANT FINAL )
public:
/**
* @brief instance access to the ViewManager singleton.
* @return pointer to the singleton instance.
*/
static ViewManager* instance();
static ViewManager* instance( QObject* parent );
/**
* @brief centralWidget always returns the central widget in the Calamares main
* window.
* @return a pointer to the active QWidget (usually a wizard page provided by a
* view module).
*/
QWidget* centralWidget();
/**
* @brief addViewStep appends a view step to the roster.
* @param step a pointer to the ViewStep object to add.
* @note a ViewStep is the active instance of a view module, it aggregates one
* or more view pages, plus zero or more jobs which may be created at runtime.
*/
void addViewStep( ViewStep* step );
/**
* @brief viewSteps returns the list of currently present view steps.
* @return the ViewStepList.
* This should only return an empty list before startup is complete.
*/
ViewStepList viewSteps() const;
/**
* @brief currentStep returns the currently active ViewStep, i.e. the ViewStep
* which owns the currently visible view page.
* @return the active ViewStep. Do not confuse this with centralWidget().
* @see ViewStep::centralWidget
*/
ViewStep* currentStep() const;
/**
* @brief currentStepIndex returns the index of the currently active ViewStep.
* @return the index.
*/
int currentStepIndex() const;
enum class Confirmation
{
Continue, // User rejects cancel / close question
CancelInstallation, // User accepts cancel / close question
EndOfInstallation, // There was no question because the installation was already done
};
/**
* @brief Called when "Cancel" is clicked; asks for confirmation.
* Other means of closing Calamares also call this method, e.g. alt-F4.
* At the end of installation, no confirmation is asked.
*
* @return a Confirmation value, @c Unasked if the installation is complete
*/
Confirmation confirmCancelInstallation();
Qt::Orientations panelSides() const { return m_panelSides; }
void setPanelSides( Qt::Orientations panelSides ) { m_panelSides = panelSides; }
public Q_SLOTS:
/**
* @brief next moves forward to the next page of the current ViewStep (if any),
* or to the first page of the next ViewStep if the current ViewStep doesn't
* have any more pages.
*/
void next();
bool nextEnabled() const
{
return m_nextEnabled; ///< Is the next-button to be enabled
}
QString nextLabel() const
{
return m_nextLabel; ///< What should be displayed on the next-button
}
QString nextIcon() const
{
return m_nextIcon; ///< Name of the icon to show
}
/**
* @brief back moves backward to the previous page of the current ViewStep (if any),
* or to the last page of the previous ViewStep if the current ViewStep doesn't
* have any pages before the current one.
*/
void back();
bool backEnabled() const
{
return m_backEnabled; ///< Is the back-button to be enabled
}
QString backLabel() const
{
return m_backLabel; ///< What should be displayed on the back-button
}
QString backIcon() const
{
return m_backIcon; ///< Name of the icon to show
}
bool backAndNextVisible() const
{
return m_backAndNextVisible; ///< Is the quit-button to be enabled
}
/**
* @brief Probably quit
*
* Asks for confirmation if necessary. Terminates the application.
*/
void quit();
bool quitEnabled() const
{
return m_quitEnabled; ///< Is the quit-button to be enabled
}
QString quitLabel() const
{
return m_quitLabel; ///< What should be displayed on the quit-button
}
QString quitIcon() const
{
return m_quitIcon; ///< Name of the icon to show
}
bool quitVisible() const
{
return m_quitVisible; ///< Should the quit-button be visible
}
QString quitTooltip() const { return m_quitTooltip; }
/**
* @brief onInstallationFailed displays an error message when a fatal failure
* happens in a ViewStep.
* @param message the error string.
* @param details the details string.
*/
void onInstallationFailed( const QString& message, const QString& details );
/** @brief Replaces the stack with a view step stating that initialization failed.
*
* @param modules a list of failed modules.
*/
void onInitFailed( const QStringList& modules );
/** @brief Tell the manager that initialization / loading is complete.
*
* Call this at least once, to tell the manager to activate the first page.
*/
void onInitComplete();
/// @brief Connected to ViewStep::nextStatusChanged for all steps
void updateNextStatus( bool enabled );
/// @brief Proxy to Settings::debugMode() default @c false
bool isDebugMode() const;
/// @brief Proxy to Settings::doChroot() default @c true
bool isChrootMode() const;
/// @brief Proxy to Settings::isSetupMode() default @c false
bool isSetupMode() const;
/// @brief Proxy to Logger::logFile(), default empty
QString logFilePath() const;
signals:
void currentStepChanged();
void ensureSize( QSize size ) const; // See ViewStep::ensureSize()
void cancelEnabled( bool enabled ) const;
void nextEnabledChanged( bool ) const;
void nextLabelChanged( QString ) const;
void nextIconChanged( QString ) const;
void backEnabledChanged( bool ) const;
void backLabelChanged( QString ) const;
void backIconChanged( QString ) const;
void backAndNextVisibleChanged( bool ) const;
void quitEnabledChanged( bool ) const;
void quitLabelChanged( QString ) const;
void quitIconChanged( QString ) const;
void quitVisibleChanged( bool ) const;
void quitTooltipChanged( QString ) const;
private:
explicit ViewManager( QObject* parent = nullptr );
~ViewManager() override;
void insertViewStep( int before, ViewStep* step );
void updateButtonLabels();
void updateCancelEnabled( bool enabled );
void updateBackAndNextVisibility( bool visible );
inline bool currentStepValid() const { return ( 0 <= m_currentStep ) && ( m_currentStep < m_steps.length() ); }
static ViewManager* s_instance;
ViewStepList m_steps;
int m_currentStep;
QWidget* m_widget;
QStackedWidget* m_stack;
bool m_nextEnabled = false;
QString m_nextLabel;
QString m_nextIcon; ///< Name of icon to show on button
bool m_backEnabled = false;
QString m_backLabel;
QString m_backIcon;
bool m_backAndNextVisible = true;
bool m_quitEnabled = false;
QString m_quitLabel;
QString m_quitIcon;
QString m_quitTooltip;
bool m_quitVisible = true;
Qt::Orientations m_panelSides;
public:
/** @section Model
*
* These are the methods and enums used for the as-a-model part
* of the ViewManager.
*/
enum Role
{
ProgressTreeItemCurrentIndex = Qt::UserRole + 13 ///< Index (row) of the current step
};
QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const override;
int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
};
} // namespace Calamares
#endif // VIEWMANAGER_H

View File

@@ -0,0 +1,30 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2024 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_COMPAT_XML_H
#define CALAMARES_COMPAT_XML_H
#include <QCheckBox>
namespace Calamares
{
#if QT_VERSION < QT_VERSION_CHECK( 6, 7, 0 )
using checkBoxStateType = int;
const auto checkBoxStateChangedSignal = &QCheckBox::stateChanged;
constexpr checkBoxStateType checkBoxUncheckedValue = 0;
#else
using checkBoxStateType = Qt::CheckState;
const auto checkBoxStateChangedSignal = &QCheckBox::checkStateChanged;
constexpr checkBoxStateType checkBoxUncheckedValue = Qt::Unchecked;
#endif
} // namespace Calamares
#endif

View File

@@ -0,0 +1,30 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2023 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_COMPAT_MUTEX_H
#define CALAMARES_COMPAT_MUTEX_H
#include <QMutexLocker>
namespace Calamares
{
/*
* In Qt5, QMutexLocker is a class and operates implicitly on
* QMutex but in Qt6 it is a template and needs a specialization.
*/
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
using MutexLocker = QMutexLocker;
#else
using MutexLocker = QMutexLocker< QMutex >;
#endif
} // namespace Calamares
#endif

View File

@@ -0,0 +1,23 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2024 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_COMPAT_SIZE_H
#define CALAMARES_COMPAT_SIZE_H
#include <QVariant>
namespace Calamares
{
/* Compatibility of size types (e.g. qsizetype, STL sizes, int) between Qt5 and Qt6 */
using NumberForTr = int;
}
#endif

View File

@@ -0,0 +1,57 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2023 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_COMPAT_VARIANT_H
#define CALAMARES_COMPAT_VARIANT_H
#include <QVariant>
namespace Calamares
{
/* Compatibility of QVariant between Qt5 and Qt6 */
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
const auto typeOf = []( const QVariant& v ) { return v.type(); };
const auto ListVariantType = QVariant::List;
const auto MapVariantType = QVariant::Map;
const auto HashVariantType = QVariant::Hash;
const auto StringVariantType = QVariant::String;
const auto CharVariantType = QVariant::Char;
const auto StringListVariantType = QVariant::StringList;
const auto BoolVariantType = QVariant::Bool;
const auto IntVariantType = QVariant::Int;
const auto UIntVariantType = QVariant::UInt;
const auto LongLongVariantType = QVariant::LongLong;
const auto ULongLongVariantType = QVariant::ULongLong;
const auto DoubleVariantType = QVariant::Double;
#else
const auto typeOf = []( const QVariant& v ) { return v.typeId(); };
const auto ListVariantType = QMetaType::Type::QVariantList;
const auto MapVariantType = QMetaType::Type::QVariantMap;
const auto HashVariantType = QMetaType::Type::QVariantHash;
const auto StringVariantType = QMetaType::Type::QString;
const auto CharVariantType = QMetaType::Type::Char;
const auto StringListVariantType = QMetaType::Type::QStringList;
const auto BoolVariantType = QMetaType::Type::Bool;
const auto IntVariantType = QMetaType::Type::Int;
const auto UIntVariantType = QMetaType::Type::UInt;
const auto LongLongVariantType = QMetaType::Type::LongLong;
const auto ULongLongVariantType = QMetaType::Type::ULongLong;
const auto DoubleVariantType = QMetaType::Type::Double;
#endif
inline bool
isIntegerVariantType( const QVariant& v )
{
const auto t = typeOf( v );
return t == IntVariantType || t == UIntVariantType || t == LongLongVariantType || t == ULongLongVariantType;
}
} // namespace Calamares
#endif

View File

@@ -0,0 +1,42 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2024 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_COMPAT_XML_H
#define CALAMARES_COMPAT_XML_H
#include <QDomDocument>
namespace Calamares
{
#if QT_VERSION < QT_VERSION_CHECK( 6, 6, 0 )
struct ParseResult
{
QString errorMessage;
int errorLine = -1;
int errorColumn = -1;
};
[[nodiscard]] inline ParseResult
setXmlContent( QDomDocument& doc, const QByteArray& ba )
{
ParseResult p;
const bool r = doc.setContent( ba, &p.errorMessage, &p.errorLine, &p.errorColumn );
return r ? ParseResult {} : p;
}
#else
[[nodiscard]] inline QDomDocument::ParseResult
setXmlContent( QDomDocument& doc, const QByteArray& ba )
{
return doc.setContent( ba );
}
#endif
} // namespace Calamares
#endif

View File

@@ -0,0 +1,43 @@
/* === 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 GEOIP_GEOIPFIXED_H
#define GEOIP_GEOIPFIXED_H
#include "Interface.h"
namespace Calamares
{
namespace GeoIP
{
/** @brief GeoIP with a fixed return value
*
* The data is ignored entirely and the attribute value is returned unchanged.
* Note that you still need to provide a usable URL for a successful GeoIP
* lookup -- the URL's data is just ignored.
*
* @note This class is an implementation detail.
*/
class GeoIPFixed : public Interface
{
public:
/** @brief Configure the value to return from rawReply()
*
* An empty string, which would not be a valid zone name, is
* translated to "Europe/Amsterdam".
*/
explicit GeoIPFixed( const QString& value = QString() );
virtual RegionZonePair processReply( const QByteArray& ) override;
virtual QString rawReply( const QByteArray& ) override;
};
} // namespace GeoIP
} // namespace Calamares
#endif

View File

@@ -0,0 +1,44 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2018-2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef GEOIP_GEOIPJSON_H
#define GEOIP_GEOIPJSON_H
#include "Interface.h"
namespace Calamares
{
namespace GeoIP
{
/** @brief GeoIP lookup for services that return JSON.
*
* This is the original implementation of GeoIP lookup,
* (e.g. using the FreeGeoIP.net service), or similar.
*
* The data is assumed to be in JSON format with a time_zone attribute.
*
* @note This class is an implementation detail.
*/
class GeoIPJSON : public Interface
{
public:
/** @brief Configure the attribute name which is selected.
*
* If an empty string is passed in (not a valid attribute name),
* then "time_zone" is used.
*/
explicit GeoIPJSON( const QString& attribute = QString() );
virtual RegionZonePair processReply( const QByteArray& ) override;
virtual QString rawReply( const QByteArray& ) override;
};
} // namespace GeoIP
} // namespace Calamares
#endif

View File

@@ -0,0 +1,37 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef GEOIPTESTS_H
#define GEOIPTESTS_H
#include <QObject>
class GeoIPTests : public QObject
{
Q_OBJECT
public:
GeoIPTests();
~GeoIPTests() override;
private Q_SLOTS:
void initTestCase();
void testFixed();
void testJSON();
void testJSONalt();
void testJSONbad();
void testXML();
void testXML2();
void testXMLalt();
void testXMLbad();
void testSplitTZ();
void testGet();
};
#endif

View File

@@ -0,0 +1,44 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2018-2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef GEOIP_GEOIPXML_H
#define GEOIP_GEOIPXML_H
#include "Interface.h"
namespace Calamares
{
namespace GeoIP
{
/** @brief GeoIP lookup with XML data
*
* The data is assumed to be in XML format with a
* <Response><TimeZone></TimeZone></Response>
* element, which contains the text (string) for the region/zone. This
* format is expected by, e.g. the Ubiquity installer.
*
* @note This class is an implementation detail.
*/
class GeoIPXML : public Interface
{
public:
/** @brief Configure the element tag which is selected.
*
* If an empty string is passed in (not a valid element tag),
* then "TimeZone" is used.
*/
explicit GeoIPXML( const QString& element = QString() );
virtual RegionZonePair processReply( const QByteArray& ) override;
virtual QString rawReply( const QByteArray& ) override;
};
} // namespace GeoIP
} // namespace Calamares
#endif

View File

@@ -0,0 +1,86 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef GEOIP_HANDLER_H
#define GEOIP_HANDLER_H
#include "Interface.h"
#include <QString>
#include <QVariantMap>
#include <QtConcurrent/QtConcurrentRun>
namespace Calamares
{
namespace GeoIP
{
/** @brief Handle one complete GeoIP lookup.
*
* This class handles one complete GeoIP lookup. Create it with
* suitable configuration values, then call get(). This is a
* synchronous API and will return an invalid zone pair on
* error or if the configuration is not understood. For an
* async API, use query().
*/
class DLLEXPORT Handler
{
public:
enum class Type
{
None, // No lookup, returns empty string
JSON, // JSON-formatted data, returns extracted field
XML, // XML-formatted data, returns extracted field
Fixed // Returns selector string verbatim
};
/** @brief An unconfigured handler; this always returns errors. */
Handler();
/** @brief A handler for a specific GeoIP source.
*
* The @p implementation name selects an implementation; currently JSON and XML
* are supported. The @p url is retrieved by query() and then the @p selector
* is used to select something from the data returned by the @url.
*/
Handler( const QString& implementation, const QString& url, const QString& selector );
~Handler();
/** @brief Synchronously get the GeoIP result.
*
* If the Handler is valid, then do the actual fetching and interpretation
* of data and return the result. An invalid Handler will return an
* invalid (empty) result.
*/
RegionZonePair get() const;
/// @brief Like get, but don't interpret the contents
QString getRaw() const;
/** @brief Asynchronously get the GeoIP result.
*
* See get() for the return value.
*/
QFuture< RegionZonePair > query() const;
/// @brief Like query, but don't interpret the contents
QFuture< QString > queryRaw() const;
bool isValid() const { return m_type != Type::None; }
Type type() const { return m_type; }
QString url() const { return m_url; }
QString selector() const { return m_selector; }
private:
Type m_type;
const QString m_url;
const QString m_selector;
};
} // namespace GeoIP
} // namespace Calamares
#endif

View File

@@ -0,0 +1,127 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2018-2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef GEOIP_INTERFACE_H
#define GEOIP_INTERFACE_H
#include "DllMacro.h"
#include <QDebug>
#include <QString>
#include <QUrl>
#include <tuple>
class QByteArray;
namespace Calamares
{
namespace GeoIP
{
/** @brief A Region, Zone pair of strings
*
* A GeoIP lookup returns a timezone, which is represented as a Region,
* Zone pair of strings (e.g. "Europe" and "Amsterdam"). Generally,
* pasting the strings back together with a "/" is the right thing to
* do. The Zone **may** contain a "/" (e.g. "Kentucky/Monticello").
*/
class DLLEXPORT RegionZonePair
{
public:
/** @brief Construct from two strings, like qMakePair(). */
RegionZonePair( const QString& region, const QString& zone )
: m_region( region )
, m_zone( zone )
{
}
/** @brief Construct from an existing pair. */
RegionZonePair( const RegionZonePair& p )
: RegionZonePair( p.m_region, p.m_zone )
{
}
/** @brief An invalid zone pair (empty strings). */
RegionZonePair() = default;
bool isValid() const { return !m_region.isEmpty(); }
QString region() const { return m_region; }
QString zone() const { return m_zone; }
friend bool operator==( const RegionZonePair& lhs, const RegionZonePair& rhs ) noexcept
{
return std::tie( lhs.m_region, lhs.m_zone ) == std::tie( rhs.m_region, rhs.m_zone );
}
QString asString() const { return isValid() ? region() + QChar( '/' ) + zone() : QString(); }
private:
QString m_region;
QString m_zone;
};
inline QDebug&
operator<<( QDebug&& s, const RegionZonePair& tz )
{
return s << tz.asString();
}
inline QDebug&
operator<<( QDebug& s, const RegionZonePair& tz )
{
return s << tz.asString();
}
/** @brief Splits a region/zone string into a pair.
*
* Cleans up the string by removing backslashes (\\)
* since some providers return silly-escaped names. Replaces
* spaces with _ since some providers return human-readable names.
* Splits on the first / in the resulting string, or returns a
* pair of empty QStrings if it can't. (e.g. America/North Dakota/Beulah
* will return "America", "North_Dakota/Beulah").
*/
DLLEXPORT RegionZonePair splitTZString( const QString& s );
/**
* @brief Interface for GeoIP retrievers.
*
* A GeoIP retriever takes a configured URL (from the config file)
* and can handle the data returned from its interpretation of that
* configured URL, returning a region and zone.
*/
class DLLEXPORT Interface
{
public:
virtual ~Interface();
/** @brief Handle a (successful) request by interpreting the data.
*
* Should return a ( <zone>, <region> ) pair, e.g.
* ( "Europe", "Amsterdam" ). This is called **only** if the
* request to the fullUrl was successful; the handler
* is free to read as much, or as little, data as it
* likes. On error, returns a RegionZonePair with empty
* strings (e.g. ( "", "" ) ).
*/
virtual RegionZonePair processReply( const QByteArray& ) = 0;
/** @brief Get the raw reply data. */
virtual QString rawReply( const QByteArray& ) = 0;
protected:
Interface( const QString& element = QString() );
QString m_element; // string for selecting from data
};
} // namespace GeoIP
} // namespace Calamares
#endif

View File

@@ -0,0 +1,83 @@
/* === 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.
*
*
*/
/** @file GlobalStorage management for Locale settings
*
* The *localeConf* key in Global Storage is semi-structured,
* and there are multiple modules that write to it (and some that
* read from it). Functions in this file provide access to
* that semi-structured data.
*/
#ifndef LOCALE_GLOBAL_H
#define LOCALE_GLOBAL_H
#include "DllMacro.h"
#include <QMap>
#include <QString>
#include <QVariantMap>
namespace Calamares
{
class GlobalStorage;
namespace Locale
{
/** @brief Selector for methods that insert multiple values.
*
* When inserting, use @c Overwrite to remove all keys not in the collection
* of values being inserted; use @c Merge to preserve whatever is
* already in Global Storage but not mentioned in the collection.
*/
enum class InsertMode
{
Overwrite,
Merge
};
/** @brief Insert the given @p values into the *localeConf* map in @p gs
*
* @param gs The Global Storage to write to
* @param values The collection of keys and values to write to @p gs
* @param mode Indicates whether the *localeConf* key is cleared first
*
* The keys in the collection @p values should be first-level keys
* in *localeConf*, e.g. "LANG" or "LC_TIME". No effort is made to
* enforce this.
*/
DLLEXPORT void insertGS( Calamares::GlobalStorage& gs, const QVariantMap& values, InsertMode mode = InsertMode::Merge );
/** @brief Insert the given @p values into the *localeConf* map in @p gs
*
* Alternate way of providing the keys and values.
*/
DLLEXPORT void
insertGS( Calamares::GlobalStorage& gs, const QMap< QString, QString >& values, InsertMode mode = InsertMode::Merge );
/** @brief Write a single @p key and @p value to the *localeConf* map
*/
DLLEXPORT void insertGS( Calamares::GlobalStorage& gs, const QString& key, const QString& value );
/** @brief Remove a single @p key from the *localeConf* map
*/
DLLEXPORT void removeGS( Calamares::GlobalStorage& gs, const QString& key );
/** @brief Remove the *localeConf* map from Global Storage
*/
DLLEXPORT void clearGS( Calamares::GlobalStorage& gs );
/** @brief Gets a value from the *localeConf* map in @p gs
*
* If the key is not set (or doesn't exist), returns QString().
*/
DLLEXPORT QString readGS( Calamares::GlobalStorage& gs, const QString& key );
} // namespace Locale
} // namespace Calamares
#endif

View File

@@ -0,0 +1,47 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef LOCALE_LOOKUP_H
#define LOCALE_LOOKUP_H
#include "DllMacro.h"
#include <QLocale>
#include <QPair>
namespace Calamares
{
namespace Locale
{
/* All the functions in this file do lookups of locale data
* based on CLDR tables; these are lookups that you can't (easily)
* do with just QLocale (e.g. from 2-letter country code to a likely
* locale).
*/
/// @brief Map a 2-letter code to a Country, or AnyCountry if not found
DLLEXPORT QLocale::Country countryForCode( const QString& code );
/** @brief Map a Country to a Language, or AnyLanguage if not found
*
* This is a *likely* language for the given country, based on the
* CLDR tables. For instance, this maps Belgium to Dutch.
*/
DLLEXPORT QLocale::Language languageForCountry( QLocale::Country country );
/// @brief Map a 2-letter code to a Language, or AnyLanguage if not found
DLLEXPORT QLocale::Language languageForCountry( const QString& code );
/// @brief Get both Country and Language for a 2-letter code
DLLEXPORT QPair< QLocale::Country, QLocale::Language > countryData( const QString& code );
/// @brief Get a likely locale for a 2-letter country code
DLLEXPORT QLocale countryLocale( const QString& code );
} // namespace Locale
} // namespace Calamares
#endif

View File

@@ -0,0 +1,237 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
/** @file Timezone data and models to go with it
*
* The TimeZoneData class holds information from zone.tab, about
* TZ names and locations (latitude and longitude) for geographic
* lookups.
*
* The RegionModel lists the regions of the world (about 12) and
* ZonesModel lists all the timezones; the RegionalZonesModel provides
* a way to restrict the view of timezones to those of a specific region.
*
*/
#ifndef LOCALE_TIMEZONE_H
#define LOCALE_TIMEZONE_H
#include "DllMacro.h"
#include "locale/TranslatableString.h"
#include <QAbstractListModel>
#include <QObject>
#include <QSortFilterProxyModel>
#include <QVariant>
namespace Calamares
{
namespace Locale
{
class Private;
class RegionalZonesModel;
class ZonesModel;
class DLLEXPORT TimeZoneData : public QObject, TranslatableString
{
friend class RegionalZonesModel;
friend class ZonesModel;
Q_OBJECT
Q_PROPERTY( QString region READ region CONSTANT )
Q_PROPERTY( QString zone READ zone CONSTANT )
Q_PROPERTY( QString name READ translated CONSTANT )
Q_PROPERTY( QString countryCode READ country CONSTANT )
public:
TimeZoneData( const QString& region,
const QString& zone,
const QString& country,
double latitude,
double longitude );
TimeZoneData( const TimeZoneData& ) = delete;
TimeZoneData( TimeZoneData&& ) = delete;
///@brief Returns a translated, human-readable form of region/zone (e.g. "America/New York")
QString translated() const override;
///@brief Returns the region key (e.g. "Europe") with no translation and no human-readable tweaks
QString region() const { return m_region; }
///@brief Returns the zone key (e.g. "New_York") with no translation and no human-readable tweaks
QString zone() const { return key(); }
QString country() const { return m_country; }
double latitude() const { return m_latitude; }
double longitude() const { return m_longitude; }
private:
QString m_region;
QString m_country;
double m_latitude;
double m_longitude;
};
/** @brief The list of timezone regions
*
* The regions are a short list of global areas (Africa, America, India ..)
* which contain zones.
*/
class DLLEXPORT RegionsModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles
{
NameRole = Qt::DisplayRole,
KeyRole = Qt::UserRole // So that currentData() will get the key
};
RegionsModel( QObject* parent = nullptr );
~RegionsModel() override;
int rowCount( const QModelIndex& parent ) const override;
QVariant data( const QModelIndex& index, int role ) const override;
QHash< int, QByteArray > roleNames() const override;
public Q_SLOTS:
/** @brief Provides a human-readable version of the region
*
* Returns @p region unchanged if there is no such region
* or no translation for the region's name.
*/
QString translated( const QString& region ) const;
private:
Private* m_private;
};
class DLLEXPORT ZonesModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles
{
NameRole = Qt::DisplayRole,
KeyRole = Qt::UserRole, // So that currentData() will get the key
RegionRole = Qt::UserRole + 1
};
ZonesModel( QObject* parent = nullptr );
~ZonesModel() override;
int rowCount( const QModelIndex& parent ) const override;
QVariant data( const QModelIndex& index, int role ) const override;
QHash< int, QByteArray > roleNames() const override;
/** @brief Iterator for the underlying list of zones
*
* Iterates over all the zones in the model. Operator * may return
* a @c nullptr when the iterator is not valid. Typical usage:
*
* ```
* for( auto it = model.begin(); it; ++it )
* {
* const auto* zonedata = *it;
* ...
* }
*/
class Iterator
{
friend class ZonesModel;
Iterator( const Private* m )
: m_index( 0 )
, m_p( m )
{
}
public:
operator bool() const;
void operator++() { ++m_index; }
const TimeZoneData* operator*() const;
int index() const { return m_index; }
private:
int m_index;
const Private* m_p;
};
Iterator begin() const { return Iterator( m_private ); }
/** @brief Look up TZ data based on an arbitrary distance function
*
* This is a generic method that can define distance in whatever
* coordinate system is wanted; returns the zone with the smallest
* distance. The @p distanceFunc must return "the distance" for
* each zone. It would be polite to return something non-negative.
*
* Note: not a slot, because the parameter isn't moc-able.
*/
const TimeZoneData* find( const std::function< double( const TimeZoneData* ) >& distanceFunc ) const;
public Q_SLOTS:
/** @brief Look up TZ data based on its name.
*
* Returns @c nullptr if not found.
*/
const TimeZoneData* find( const QString& region, const QString& zone ) const;
/** @brief Look up TZ data based on the location.
*
* Returns the nearest zone to the given lat and lon. This is a
* convenience function for calling find(), below, with a standard
* distance function based on the distance between the given
* location (lat and lon) and each zone's given location.
*/
const TimeZoneData* find( double latitude, double longitude ) const;
/** @brief Look up TZ data based on the location.
*
* Returns the nearest zone, or New York. This is non-const for QML
* purposes, but the object should be considered const anyway.
*/
QObject* lookup( double latitude, double longitude ) const;
private:
Private* m_private;
};
class DLLEXPORT RegionalZonesModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY( QString region READ region WRITE setRegion NOTIFY regionChanged )
public:
RegionalZonesModel( ZonesModel* source, QObject* parent = nullptr );
~RegionalZonesModel() override;
bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const override;
QString region() const { return m_region; }
public Q_SLOTS:
void setRegion( const QString& r );
signals:
void regionChanged( const QString& );
private:
Private* m_private;
QString m_region;
};
} // namespace Locale
} // namespace Calamares
#endif // LOCALE_TIMEZONE_H

View File

@@ -0,0 +1,104 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
/** @file Run-time translation of strings from configuration files
*
* The TranslatedString class provides a way of doing run-time
* lookups of human-readable strings, from data provided in
* the configuration files (*.conf) for Calamares. This acts
* like "normal" translation through tr() calls, as far as the
* user-visible part goes.
*/
#ifndef LOCALE_TRANSLATABLECONFIGURATION_H
#define LOCALE_TRANSLATABLECONFIGURATION_H
#include "DllMacro.h"
#include <QLocale>
#include <QMap>
#include <QVariant>
namespace Calamares
{
namespace Locale
{
/** @brief A human-readable string from a configuration file
*
* The configuration files can contain human-readable strings,
* but those need their own translations and are not supported
* by QObject::tr or anything else.
*/
class DLLEXPORT TranslatedString
{
public:
/** @brief Get all the translations connected to @p key
*
* Gets map[key] as the "untranslated" form, and then all the
* keys of the form <key>[lang] are taken as the translation
* for <lang> of the untranslated form.
*
* If @p context is not a nullptr, then that is taken as an
* indication to **also** use the regular QObject::tr() translation
* mechanism for these strings. It is recommended to pass in
* metaObject()->className() as context (from a QObject based class)
* to give the TranslatedString the same context as other calls
* to tr() within that class.
*
* The @p context, if any, should point to static data; it is
* **not** owned by the TranslatedString.
*/
TranslatedString( const QVariantMap& map, const QString& key, const char* context = nullptr );
/** @brief Not-actually-translated string.
*/
TranslatedString( const QString& string );
/** @brief Proxy for calling QObject::tr()
*
* This is like the two constructors above, with an empty map an a
* non-null context. It will end up calling tr() with that context.
*
* The @p context, if any, should point to static data; it is
* **not** owned by the TranslatedString.
*/
TranslatedString( const QString& key, const char* context );
/// @brief Empty string
TranslatedString()
: TranslatedString( QString() )
{
}
/** @brief How many strings (translations) are there?
*
* This is always at least 1 (for the untranslated string),
* but may be more than 1 even when isEmpty() is true --
* if there is no untranslated version, for instance.
*/
int count() const { return m_strings.count(); }
/** @brief Consider this string empty?
*
* Only the state of the untranslated string is considered,
* so count() may be more than 1 even while the string is empty.
*/
bool isEmpty() const { return m_strings[ QString() ].isEmpty(); }
/// @brief Gets the string in the current locale
QString get() const;
/// @brief Gets the string from the given locale
QString get( const QLocale& ) const;
private:
// Maps locale name to human-readable string, "" is English
QMap< QString, QString > m_strings;
const char* m_context = nullptr;
};
} // namespace Locale
} // namespace Calamares
#endif

View File

@@ -0,0 +1,58 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef LOCALE_TRANSLATABLESTRING_H
#define LOCALE_TRANSLATABLESTRING_H
#include <QString>
namespace Calamares
{
namespace Locale
{
/** @brief A pair of strings, one human-readable, one a key
*
* Given an identifier-like string (e.g. "New_York"), makes
* a human-readable version of that and keeps a copy of the
* identifier itself.
*
* This explicitly uses const char* instead of just being
* QPair<QString, QString> because the human-readable part
* may need to be translated through tr(), and that takes a char*
* C-style strings.
*/
class TranslatableString
{
public:
/// @brief An empty pair
TranslatableString() {}
/// @brief Given an identifier, create the pair
explicit TranslatableString( const char* s1 );
explicit TranslatableString( const QString& s );
TranslatableString( TranslatableString&& t );
TranslatableString( const TranslatableString& );
virtual ~TranslatableString();
/// @brief Give the localized human-readable form
virtual QString translated() const = 0;
QString key() const { return m_key; }
bool operator==( const TranslatableString& other ) const { return m_key == other.m_key; }
bool operator<( const TranslatableString& other ) const { return m_key < other.m_key; }
protected:
char* m_human = nullptr;
QString m_key;
};
} // namespace Locale
} // namespace Calamares
#endif

View File

@@ -0,0 +1,145 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef LOCALE_TRANSLATION_H
#define LOCALE_TRANSLATION_H
#include "utils/Logger.h"
#include <QLocale>
#include <QObject>
#include <QString>
///@brief Define to 1 if the Qt version being used supports Interlingue fully
#if QT_VERSION < QT_VERSION_CHECK( 6, 7, 0 )
#define CALAMARES_QT_SUPPORT_INTERLINGUE 0
#else
#define CALAMARES_QT_SUPPORT_INTERLINGUE 1
#endif
namespace Calamares
{
namespace Locale
{
/**
* @brief Consistent locale (language + country) naming.
*
* Support class to turn locale names (as used by Calamares's
* translation system) into QLocales, and also into consistent
* human-readable text labels.
*
* This handles special-cases in Calamares translations:
* - `sr@latin` is the name which Qt recognizes as `sr@latn`,
* Serbian written with Latin characters (not Cyrillic).
* - `ca@valencia` is the Catalan dialect spoken in Valencia.
* There is no Qt code for it.
*
* (There are more special cases, not documented here)
*/
class DLLEXPORT Translation : public QObject
{
Q_OBJECT
public:
/** @brief Formatting option for label -- add (country) to label. */
enum class LabelFormat
{
AlwaysWithCountry,
IfNeededWithCountry
};
struct Id
{
QString name;
};
/** @brief Empty locale. This uses the system-default locale. */
Translation( QObject* parent = nullptr );
/** @brief Construct from a locale name.
*
* The @p localeName should be one that Qt recognizes, e.g. en_US or ar_EY.
* The @p format determines whether the country name is always present
* in the label (human-readable form) or only if needed for disambiguation.
*/
Translation( const Id& localeId, LabelFormat format = LabelFormat::IfNeededWithCountry, QObject* parent = nullptr );
/** @brief Define a sorting order.
*
* Locales are sorted by their id, which means the ISO 2-letter code + country.
*/
bool operator<( const Translation& other ) const { return m_localeId < other.m_localeId; }
/** @brief Is this locale English?
*
* en_US and en (American English) is defined as English. The Queen's
* English -- proper English -- is relegated to non-English status.
*/
bool isEnglish() const { return m_localeId == QLatin1String( "en_US" ) || m_localeId == QLatin1String( "en" ); }
/** @brief Get the human-readable name for this locale. */
QString label() const { return m_label; }
/** @brief Get the *English* human-readable name for this locale. */
QString englishLabel() const { return m_englishLabel; }
/** @brief Get the Qt locale. */
QLocale locale() const { return m_locale; }
/** @brief Gets the Calamares internal name (code) of the locale.
*
* This is a strongly-typed return to avoid it ending up all over
* the place as a QString.
*/
Id id() const { return { m_localeId }; }
/// @brief Convenience accessor to the language part of the locale
QLocale::Language language() const { return m_locale.language(); }
/// @brief Convenience accessor to the country part (if any) of the locale
QLocale::Country country() const
{
#if QT_VERSION < QT_VERSION_CHECK( 6, 6, 0 )
return m_locale.country();
#else
return m_locale.territory();
#endif
}
/** @brief Get a Qt locale for the given @p localeName
*
* This obeys special cases as described in the class documentation.
*/
static QLocale getLocale( const Id& localeId );
private:
QLocale m_locale;
QString m_localeId; // the locale identifier, e.g. "en_GB"
QString m_label; // the native name of the locale
QString m_englishLabel;
};
static inline QDebug&
operator<<( QDebug& s, const Translation::Id& id )
{
return s << id.name;
}
static inline bool
operator==( const Translation::Id& lhs, const Translation::Id& rhs )
{
return lhs.name == rhs.name;
}
} // namespace Locale
} // namespace Calamares
#endif

View File

@@ -0,0 +1,94 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Camilo Higuita <milo.h@aol.com>
* SPDX-FileCopyrightText: 2019-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 LOCALE_TRANSLATIONSMODEL_H
#define LOCALE_TRANSLATIONSMODEL_H
#include "DllMacro.h"
#include "Translation.h"
#include <QAbstractListModel>
#include <QVector>
namespace Calamares
{
namespace Locale
{
class DLLEXPORT TranslationsModel : public QAbstractListModel
{
Q_OBJECT
public:
enum
{
LabelRole = Qt::DisplayRole,
EnglishLabelRole = Qt::UserRole + 1
};
TranslationsModel( const QStringList& locales, QObject* parent = nullptr );
~TranslationsModel() override;
int rowCount( const QModelIndex& parent ) const override;
QVariant data( const QModelIndex& index, int role ) const override;
QHash< int, QByteArray > roleNames() const override;
/** @brief Gets locale information for entry #n
*
* This is the backing data for the model; if @p row is out-of-range,
* returns a reference to en_US.
*/
const Translation& locale( int row ) const;
/// @brief Returns all of the locale Ids (e.g. en_US) put into this model.
const QStringList& localeIds() const { return m_localeIds; }
/** @brief Searches for an item that matches @p predicate
*
* Returns the row number of the first match, or -1 if there isn't one.
*/
int find( std::function< bool( const QLocale& ) > predicate ) const;
int find( std::function< bool( const Translation& ) > predicate ) const;
/// @brief Looks for an item using the same locale, -1 if there isn't one
int find( const QLocale& ) const;
/// @brief Looks for an item that best matches the 2-letter country code
int find( const QString& countryCode ) const;
/// @brief Looks up a translation Id
int find( const Translation::Id& id ) const;
private:
QVector< Translation* > m_locales;
QStringList m_localeIds;
};
/** @brief Returns a model with all available translations.
*
* The translations are set when Calamares is compiled; the list
* of names used can be queried with avalableLanguages().
*
* This model is a singleton and can be shared.
*
* NOTE: While the model is not typed const, it should be. Do not modify.
*/
DLLEXPORT TranslationsModel* availableTranslations();
/** @brief The list of names (e.g. en, pt_BR) of available translations.
*
* The translations are set when Calamares is compiled.
* At CMake-time, the list CALAMARES_TRANSLATION_LANGUAGES
* is used to create the table.
*/
DLLEXPORT const QStringList& availableLanguages();
} // namespace Locale
} // namespace Calamares
#endif

View File

@@ -0,0 +1,29 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef MODULESYSTEM_ACTIONS_H
#define MODULESYSTEM_ACTIONS_H
namespace Calamares
{
namespace ModuleSystem
{
enum class Action : char
{
Show,
Exec
};
} // namespace ModuleSystem
} // namespace Calamares
#endif

View File

@@ -0,0 +1,147 @@
/* === 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 CALAMARES_MODULESYSTEM_CONFIG_H
#define CALAMARES_MODULESYSTEM_CONFIG_H
#include "DllMacro.h"
#include <QObject>
#include <QStringList>
#include <QVariantMap>
#include <memory>
namespace Calamares
{
namespace ModuleSystem
{
/** @brief Base class for Config-objects
*
* This centralizes the things every Config-object should
* do and provides one source of preset-data. A Config-object
* for a module can **optionally** inherit from this class
* to get presets-support.
*
* TODO:3.3 This is not optional
* TODO:3.3 Put consistent i18n for Configurations in here too
*/
class DLLEXPORT Config : public QObject
{
Q_OBJECT
public:
Config( QObject* parent = nullptr );
~Config() override;
/** @brief Set the configuration from the config file
*
* Subclasses must implement this to load configuration data;
* that subclass **should** also call loadPresets() with the
* same map, to pick up the "presets" key consistently.
*/
virtual void setConfigurationMap( const QVariantMap& ) = 0;
public Q_SLOTS:
/** @brief Checks if a @p fieldName is editable according to presets
*
* If the field is named as a preset, **and** the field is set
* to not-editable, returns @c false. Otherwise, return @c true.
* Calling this with an unknown field (one for which no presets
* are accepted) will print a warning and return @c true.
*
* @see CONFIG_PREVENT_EDITING
*
* Most setters will call isEditable() to check if the field should
* be editable. Do not count on the setter not being called: the
* UI might not have set the field to fixed / constant / not-editable
* and then you can have the setter called by changes in the UI.
*
* To prevent the UI from changing **and** to make sure that the UI
* reflects the unchanged value (rather than the changed value it
* sent to the Config object), use CONFIG_PREVENT_EDITING, like so:
*
* CONFIG_PREVENT_EDITING( type, "propertyName" );
*
* The ; is necessary. <type> is the type of the property; for instance
* QString. The name of the property is a (constant) string. The
* macro will return (out of the setter it is used in) if the field
* is not editable, and will send a notification event with the old
* value as soon as the event loop resumes.
*/
bool isEditable( const QString& fieldName ) const;
protected:
friend class ApplyPresets;
/** @brief "Builder" class for presets
*
* Derived classes should instantiate this (with themselves,
* and the whole configuration map that is passed to
* setConfigurationMap()) and then call .apply() to apply
* the presets specified in the configuration to the **named**
* QObject properties.
*/
class ApplyPresets
{
public:
/** @brief Create a preset-applier for this config
*
* The @p configurationMap should be the one passed in to
* setConfigurationMap() . Presets are extracted from the
* standard key *presets* and can be applied to the configuration
* with apply() or operator<<.
*/
ApplyPresets( Config& c, const QVariantMap& configurationMap );
~ApplyPresets();
/** @brief Add a preset for the given @p fieldName
*
* This checks for preset-entries in the configuration map that was
* passed in to the constructor.
*/
ApplyPresets& apply( const char* fieldName );
/** @brief Alternate way of writing apply()
*/
ApplyPresets& operator<<( const char* fieldName ) { return apply( fieldName ); }
private:
Config& m_c;
bool m_bogus = true;
const QVariantMap m_map;
};
private:
class Private;
std::unique_ptr< Private > d;
bool m_unlocked = false;
};
} // namespace ModuleSystem
} // namespace Calamares
/// @see Config::isEditable()
//
// This needs to be a macro, because Q_ARG() is a macro that stringifies
// the type name.
#define CONFIG_PREVENT_EDITING( type, fieldName ) \
do \
{ \
if ( !isEditable( QStringLiteral( fieldName ) ) ) \
{ \
auto prop = property( fieldName ); \
const auto& metaobject = metaObject(); \
auto metaprop = metaobject->property( metaobject->indexOfProperty( fieldName ) ); \
if ( metaprop.hasNotifySignal() ) \
{ \
metaprop.notifySignal().invoke( this, Qt::QueuedConnection, Q_ARG( type, prop.value< type >() ) ); \
} \
return; \
} \
} while ( 0 )
#endif

View File

@@ -0,0 +1,50 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2016 Kevin Kofler <kevin.kofler@chello.at>
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARES_CPPJOBMODULE_H
#define CALAMARES_CPPJOBMODULE_H
#include "DllMacro.h"
#include "modulesystem/Module.h"
class QPluginLoader;
namespace Calamares
{
class UIDLLEXPORT CppJobModule : public Module
{
public:
Type type() const override;
Interface interface() const override;
void loadSelf() override;
JobList jobs() const override;
protected:
void initFrom( const ModuleSystem::Descriptor& moduleDescriptor ) override;
private:
explicit CppJobModule();
~CppJobModule() override;
QPluginLoader* m_loader;
job_ptr m_job;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares
#endif // CALAMARES_CPPJOBMODULE_H

View File

@@ -0,0 +1,148 @@
/* === 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 MODULESYSTEM_DESCRIPTOR_H
#define MODULESYSTEM_DESCRIPTOR_H
#include "DllMacro.h"
#include "utils/NamedEnum.h"
#include <QVariantMap>
namespace Calamares
{
namespace ModuleSystem
{
/**
* @brief The Type enum represents the intended functionality of the module
* Every module is either a job module or a view module.
* A job module is a single Calamares job.
* A view module has a UI (one or more view pages) and zero-to-many jobs.
*/
enum class Type
{
Job,
View
};
DLLEXPORT const NamedEnumTable< Type >& typeNames();
/**
* @brief The Interface enum represents the interface through which the module
* talks to Calamares.
* Not all Type-Interface associations are valid.
*/
enum class Interface
{
QtPlugin, // Jobs or Views
Python, // Jobs only
Process, // Deprecated interface
};
DLLEXPORT const NamedEnumTable< Interface >& interfaceNames();
/**
* @brief Description of a module (obtained from module.desc)
*
* Provides access to the fields of a descriptor, use type() to
* determine which specialized fields make sense for a given
* descriptor (e.g. a Python module has no shared-library path).
*/
class DLLEXPORT Descriptor
{
public:
///@brief an invalid, and empty, descriptor
Descriptor();
/** @brief Fills a descriptor from the loaded (YAML) data.
*
* The @p descriptorPath is used only for debug messages, the
* data is only read from @p moduleDesc.
*
*/
static Descriptor fromDescriptorData( const QVariantMap& moduleDesc, const QString& descriptorPath );
bool isValid() const { return m_isValid; }
QString name() const { return m_name; }
Type type() const { return m_type; }
Interface interface() const { return m_interface; }
bool isEmergency() const { return m_isEmergeny; }
bool hasConfig() const { return m_hasConfig; } // TODO: 3.5 rename to noConfig() to match descriptor key
int weight() const { return m_weight < 1 ? 1 : m_weight; }
bool explicitWeight() const { return m_weight > 0; }
/// @brief The directory where the module.desc lives
QString directory() const { return m_directory; }
void setDirectory( const QString& d ) { m_directory = d; }
const QStringList& requiredModules() const { return m_requiredModules; }
/** @section C++ Modules
*
* The C++ modules are the most general, and are loaded as
* a shared library after which a suitable factory creates
* objects from them.
*/
/// @brief Short path to the shared-library; no extension.
QString load() const { return m_interface == Interface::QtPlugin ? m_script : QString(); }
/** @section Process Job modules
*
* Process Jobs are somewhat deprecated in favor of shellprocess
* and contextualprocess jobs, since those handle multiple configuration
* much more gracefully.
*
* Process Jobs execute one command.
*/
/// @brief The command to execute; passed to the shell
QString command() const { return m_interface == Interface::Process ? m_script : QString(); }
/// @brief Timeout in seconds
int timeout() const { return m_processTimeout; }
/// @brief Run command in chroot?
bool chroot() const { return m_processChroot; }
/** @section Python Job modules
*
* Python job modules have one specific script to load and run.
*/
QString script() const { return m_interface == Interface::Python ? m_script : QString(); }
private:
QString m_name;
QString m_directory;
QStringList m_requiredModules;
int m_weight = -1;
Type m_type;
Interface m_interface;
bool m_isValid = false;
bool m_isEmergeny = false;
bool m_hasConfig = true;
/** @brief The name of the thing to load
*
* - A C++ module loads a shared library (via key *load*),
* - A Python module loads a Python script (via key *script*),
* - A process runs a specific command (via key *command*)
*
* This name-of-the-thing is stored here, regardless of which
* interface is being used.
*/
QString m_script;
int m_processTimeout = 30;
bool m_processChroot = false;
};
} // namespace ModuleSystem
} // namespace Calamares
#endif

View File

@@ -0,0 +1,117 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2018-2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef MODULESYSTEM_INSTANCEKEY_H
#define MODULESYSTEM_INSTANCEKEY_H
#include "DllMacro.h"
#include <QDebug>
#include <QList>
#include <QString>
#include <tuple>
#include <utility>
namespace Calamares
{
namespace ModuleSystem
{
/** @brief A module instance's key (`module@id`)
*
* A module instance is identified by both the module's name
* (a Calamares module, e.g. `users`) and an instance id.
* Usually, the instance id is the same as the module name
* and the whole module instance key is `users@users`, but
* it is possible to use the same module more than once
* and then you distinguish those module instances by their
* secondary id (e.g. `users@one`).
*
* This is supported by the *instances* configuration entry
* in `settings.conf`.
*/
class DLLEXPORT InstanceKey
{
public:
/// @brief Create an instance key from explicit module and id.
InstanceKey( const QString& module, const QString& id )
: first( module )
, second( id )
{
if ( second.isEmpty() )
{
second = first;
}
validate();
}
/// @brief Create unusual, invalid instance key
InstanceKey() = default;
/// @brief A valid module has both name and id
bool isValid() const { return !first.isEmpty() && !second.isEmpty(); }
/// @brief A custom module has a non-default id
bool isCustom() const { return first != second; }
QString module() const { return first; }
QString id() const { return second; }
/// @brief Create instance key from stringified version
static InstanceKey fromString( const QString& s );
QString toString() const
{
if ( isValid() )
{
return first + '@' + second;
}
return QString();
}
friend bool operator==( const InstanceKey& lhs, const InstanceKey& rhs ) noexcept
{
return std::tie( lhs.first, lhs.second ) == std::tie( rhs.first, rhs.second );
}
friend bool operator<( const InstanceKey& lhs, const InstanceKey& rhs ) noexcept
{
return std::tie( lhs.first, lhs.second ) < std::tie( rhs.first, rhs.second );
}
private:
/** @brief Check validity and reset module and id if needed. */
void validate()
{
if ( first.contains( '@' ) || second.contains( '@' ) )
{
first = QString();
second = QString();
}
}
QString first;
QString second;
};
using InstanceKeyList = QList< InstanceKey >;
DLLEXPORT QDebug& operator<<( QDebug& s, const Calamares::ModuleSystem::InstanceKey& i );
inline QDebug&
operator<<( QDebug&& s, const Calamares::ModuleSystem::InstanceKey& i )
{
return s << i;
}
} // namespace ModuleSystem
} // namespace Calamares
#endif

View File

@@ -0,0 +1,169 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_MODULE_H
#define CALAMARES_MODULE_H
#include "DllMacro.h"
#include "Job.h"
#include "modulesystem/Descriptor.h"
#include "modulesystem/InstanceKey.h"
#include "modulesystem/Requirement.h"
#include <QStringList>
#include <QVariant>
namespace Calamares
{
class Module;
Module* moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
/**
* @brief The Module class is a common supertype for Calamares modules.
* It enforces a common interface for all the different types of modules, and it
* takes care of creating an object of the correct type starting from a module
* descriptor structure.
*/
class DLLEXPORT Module
{
public:
using Type = ModuleSystem::Type;
using Interface = ModuleSystem::Interface;
virtual ~Module();
/**
* @brief name returns the name of this module.
* @return a string with this module's name.
*/
QString name() const { return m_key.module(); }
/**
* @brief instanceId returns the instance id of this module.
* @return a string with this module's instance id.
*/
QString instanceId() const { return m_key.id(); }
/**
* @brief instanceKey returns the instance key of this module.
* @return a string with the instance key.
* A module instance's instance key is modulename\@instanceid.
* For instance, "partition\@partition" (default configuration) or
* "locale\@someconfig" (custom configuration)
*/
ModuleSystem::InstanceKey instanceKey() const { return m_key; }
/**
* @brief location returns the full path of this module's directory.
* @return the path.
*/
QString location() const { return m_directory; }
/**
* @brief Is this an emergency module?
*
* An emergency module is run even if an error occurs
* which would terminate Calamares earlier in the same
* *exec* block. Emergency modules in later exec blocks
* are not run (in the common case where there is only
* one exec block, this doesn't really matter).
*/
bool isEmergency() const { return m_emergency; }
/**
* @brief isLoaded reports on the loaded status of a module.
* @return true if the module's loading phase has finished, otherwise false.
*/
bool isLoaded() const { return m_loaded; }
/**
* @brief configurationMap returns the contents of the configuration file for
* this module instance.
* @return the instance's configuration, already parsed from YAML into a variant map.
*/
QVariantMap configurationMap();
/**
* @brief typeString returns a user-visible string for the module's type.
* @return the type string.
*/
QString typeString() const;
/**
* @brief interface returns a user-visible string for the module's interface.
* @return the interface string.
*/
QString interfaceString() const;
/**
* @brief loadSelf initialized the module.
* Subclasses must reimplement this depending on the module type and interface.
*/
virtual void loadSelf() = 0;
/**
* @brief jobs returns any jobs exposed by this module.
* @return a list of jobs (can be empty).
*/
virtual JobList jobs() const = 0;
/**
* @brief type returns the Type of this module object.
* @return the type enum value.
*/
virtual Type type() const = 0;
/**
* @brief interface the Interface used by this module.
* @return the interface enum value.
*/
virtual Interface interface() const = 0;
/**
* @brief Check the requirements of this module.
*/
virtual RequirementsList checkRequirements();
protected:
explicit Module();
/// @brief For subclasses to read their part of the descriptor
virtual void initFrom( const ModuleSystem::Descriptor& moduleDescriptor ) = 0;
/// @brief Generic part of descriptor reading (and instance id)
void initFrom( const ModuleSystem::Descriptor& moduleDescriptor, const QString& id );
QVariantMap m_configurationMap;
bool m_loaded = false;
bool m_emergency = false; // Based on module and local config
bool m_maybe_emergency = false; // Based on the module.desc
private:
void loadConfigurationFile( const QString& configFileName ); //throws YAML::Exception
QString m_directory;
ModuleSystem::InstanceKey m_key;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares
#endif // CALAMARES_MODULE_H

View File

@@ -0,0 +1,38 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARES_MODULEFACTORY_H
#define CALAMARES_MODULEFACTORY_H
#include "DllMacro.h"
#include "modulesystem/Descriptor.h"
#include "modulesystem/Module.h"
#include <QString>
namespace Calamares
{
/**
* @brief fromDescriptor creates a new Module object of the correct type.
* @param moduleDescriptor a module descriptor, already parsed into a variant map.
* @param instanceId the instance id of the new module instance.
* @param configFileName the name of the configuration file to read.
* @param moduleDirectory the path to the directory with this module's files.
* @return a pointer to an object of a subtype of Module.
*/
UIDLLEXPORT Module* moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
} // namespace Calamares
#endif // CALAMARES_MODULEFACTORY_H

View File

@@ -0,0 +1,177 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef MODULELOADER_H
#define MODULELOADER_H
#include "DllMacro.h"
#include "modulesystem/Descriptor.h"
#include "modulesystem/InstanceKey.h"
#include "modulesystem/Requirement.h"
#include <QObject>
#include <QStringList>
#include <QVariantMap>
namespace Calamares
{
class Module;
class RequirementsModel;
/**
* @brief The ModuleManager class is a singleton which manages Calamares modules.
*
* It goes through the module search directories and reads module metadata. It then
* constructs objects of type Module, loads them and makes them accessible by their
* instance key.
*/
class UIDLLEXPORT ModuleManager : public QObject
{
Q_OBJECT
public:
explicit ModuleManager( const QStringList& paths, QObject* parent = nullptr );
~ModuleManager() override;
static ModuleManager* instance();
/**
* @brief init goes through the module search directories and gets a list of
* modules available for loading, along with their metadata.
* This information is stored as a map of Module* objects, indexed by name.
*/
void init();
/**
* @brief loadedInstanceKeys returns a list of instance keys for the available
* modules.
* @return a QStringList with the instance keys.
*/
QList< ModuleSystem::InstanceKey > loadedInstanceKeys();
/**
* @brief moduleDescriptor returns the module descriptor structure for a given module.
* @param name the name of the module for which to return the module descriptor.
* @return the module descriptor, as a variant map already parsed from YAML.
*/
ModuleSystem::Descriptor moduleDescriptor( const QString& name );
/** @brief returns the module descriptor structure for the module @p instance
*
* Descriptors are for the module, which may have multiple instances;
* this is the same as moduleDescriptor( instance.module() ).
*/
ModuleSystem::Descriptor moduleDescriptor( const ModuleSystem::InstanceKey& instanceKey )
{
return moduleDescriptor( instanceKey.module() );
}
/**
* @brief moduleInstance returns a Module object for a given instance key.
* @param instanceKey the instance key for a module instance.
* @return a pointer to an object of a subtype of Module.
*/
Module* moduleInstance( const ModuleSystem::InstanceKey& instanceKey );
/**
* @brief loadModules does all of the module loading operation.
* When this is done, the signal modulesLoaded is emitted.
* It is recommended to call this from a single-shot QTimer.
*/
void loadModules();
/**
* @brief Adds a single module (loaded by some other means)
*
* Returns @c true on success (that is, the module's dependencies
* are satisfied, it wasn't already loaded, ...).
*/
bool addModule( Module* );
/**
* @brief Starts asynchronous requirements checking for each module.
* When this is done, the signal requirementsComplete is emitted.
*/
void checkRequirements();
///@brief Gets the model that requirements-checking works on.
RequirementsModel* requirementsModel() { return m_requirementsModel; }
signals:
/** @brief Emitted when all the module **configuration** has been read
*
* This indicates that all of the module.desc files have been
* loaded; bad ones are silently skipped, so this just indicates
* that the module manager is ready for the next phase (loading).
*/
void initDone();
/** @brief Emitted when all the modules are loaded successfully
*
* Each module listed in the settings is loaded. Modules are loaded
* only once, even when instantiated multiple times. If all of
* the listed modules are successfully loaded, this signal is
* emitted (otherwise, it isn't, so you need to wait for **both**
* of the signals).
*
* If this is emitted (i.e. all modules have loaded) then the next
* phase, requirements checking, can be started.
*/
void modulesLoaded();
/** @brief Emitted if any modules failed to load
*
* Modules that failed to load (for any reason) are listed by
* instance key (e.g. "welcome@welcome", "shellprocess@mycustomthing").
*/
void modulesFailed( QStringList );
/** @brief Emitted after all requirements have been checked
*
* The bool @p canContinue indicates if all of the **mandatory** requirements
* are satisfied (e.g. whether installation can continue).
*/
void requirementsComplete( bool canContinue );
private slots:
void doInit();
private:
/**
* Check in a general sense whether the dependencies between
* modules are valid. Returns the number of modules that
* have missing dependencies -- this is **not** a problem
* unless any of those modules are actually used.
*
* Returns 0 on success.
*
* Also modifies m_availableDescriptorsByModuleName to remove
* all the entries that (so that later, when we try to look
* them up, they are not found).
*/
size_t checkDependencies();
/**
* Check for this specific module if its required modules have
* already been loaded (i.e. are in sequence before it).
*
* Returns true if the requirements are met.
*/
bool checkModuleDependencies( const Module& );
QMap< QString, ModuleSystem::Descriptor > m_availableDescriptorsByModuleName;
QMap< ModuleSystem::InstanceKey, Module* > m_loadedModulesByInstanceKey;
const QStringList m_paths;
RequirementsModel* m_requirementsModel;
static ModuleManager* s_instance;
};
} // namespace Calamares
#endif // MODULELOADER_H

View File

@@ -0,0 +1,91 @@
/* === 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 CALAMARES_MODULESYSTEM_PRESET_H
#define CALAMARES_MODULESYSTEM_PRESET_H
#include <QString>
#include <QVariantMap>
#include <QVector>
namespace Calamares
{
namespace ModuleSystem
{
/** @brief The settings for a single field
*
* The settings apply to a single field; **often** this will
* correspond to a single value or property of a Config
* object, but there is no guarantee of a correspondence
* between names here and names in the code.
*
* The value is stored as a string; consumers (e.g. the UI)
* will need to translate the value to whatever is actually
* used (e.g. in the case of an integer field).
*
* By default, presets are still editable. Set that to @c false
* to make the field unchangeable (again, the UI is responsible
* for setting that up).
*/
struct PresetField
{
QString fieldName;
QVariant value;
bool editable = true;
bool isValid() const { return !fieldName.isEmpty(); }
};
/** @brief All the presets for one UI entity
*
* This is a collection of presets read from a module
* configuration file, one setting per field.
*/
class Presets : public QVector< PresetField >
{
public:
/** @brief Reads preset entries from the map
*
* The map's keys are used as field name, and each value entry
* should specify an initial value and whether the entry is editable.
* Fields are editable by default.
*/
explicit Presets( const QVariantMap& configurationMap );
/** @brief Reads preset entries from the @p configurationMap
*
* As above, but only field names that occur in @p recognizedKeys
* are kept; others are discarded.
*/
Presets( const QVariantMap& configurationMap, const QStringList& recognizedKeys );
/** @brief Creates an empty presets map
*
* This constructor is primarily intended for use by the ApplyPresets
* helper class, which will reserve suitable space and load
* presets on-demand.
*/
Presets() = default;
/** @brief Is the given @p fieldName editable?
*
* Fields are editable by default, so if there is no explicit setting,
* returns @c true.
*/
bool isEditable( const QString& fieldName ) const;
/** @brief Finds the settings for a field @p fieldName
*
* If there is no such field, returns an invalid PresetField.
*/
PresetField find( const QString& fieldName ) const;
};
} // namespace ModuleSystem
} // namespace Calamares
#endif

View File

@@ -0,0 +1,52 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARES_PROCESSJOBMODULE_H
#define CALAMARES_PROCESSJOBMODULE_H
#include "DllMacro.h"
#include "modulesystem/Module.h"
#include <chrono>
namespace Calamares
{
class UIDLLEXPORT ProcessJobModule : public Module
{
public:
Type type() const override;
Interface interface() const override;
void loadSelf() override;
JobList jobs() const override;
protected:
void initFrom( const ModuleSystem::Descriptor& moduleDescriptor ) override;
private:
explicit ProcessJobModule();
~ProcessJobModule() override;
QString m_command;
QString m_workingPath;
std::chrono::seconds m_secondsTimeout;
bool m_runInChroot;
job_ptr m_job;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares
#endif // CALAMARES_PROCESSJOBMODULE_H

View File

@@ -0,0 +1,47 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARES_PYTHONJOBMODULE_H
#define CALAMARES_PYTHONJOBMODULE_H
#include "DllMacro.h"
#include "modulesystem/Module.h"
namespace Calamares
{
class UIDLLEXPORT PythonJobModule : public Module
{
public:
Type type() const override;
Interface interface() const override;
void loadSelf() override;
JobList jobs() const override;
protected:
void initFrom( const ModuleSystem::Descriptor& moduleDescriptor ) override;
private:
explicit PythonJobModule();
~PythonJobModule() override;
QString m_scriptFileName;
QString m_workingPath;
job_ptr m_job;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares
#endif // CALAMARES_PYTHONJOBMODULE_H

View File

@@ -0,0 +1,61 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_REQUIREMENT_H
#define CALAMARES_REQUIREMENT_H
#include "DllMacro.h"
#include <QList>
#include <QMetaType>
#include <QString>
#include <functional>
namespace Calamares
{
/**
* An indication of a requirement, which is checked in preparation
* for system installation. An entry has a name and some explanation functions
* (functions, because they need to respond to translations).
*
* A requirement can be *satisfied* or not.
* A requirement can be optional (i.e. a "good to have") or mandatory.
*
* Requirements which are not satisfied, and also mandatory, will prevent the
* installation from proceeding.
*/
struct RequirementEntry
{
using TextFunction = std::function< QString() >;
/// @brief name of this requirement; not shown to user and used as ID
QString name;
/// @brief Detailed description of this requirement, for use in user-visible lists
TextFunction enumerationText;
/// @brief User-visible string to show that the requirement is not met, short form
TextFunction negatedText;
bool satisfied;
bool mandatory;
/// @brief Convenience to check if this entry should be shown in details dialog
bool hasDetails() const { return !enumerationText().isEmpty(); }
};
using RequirementsList = QList< RequirementEntry >;
} // namespace Calamares
Q_DECLARE_METATYPE( Calamares::RequirementEntry )
#endif

View File

@@ -0,0 +1,73 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef CALAMARES_REQUIREMENTSCHECKER_H
#define CALAMARES_REQUIREMENTSCHECKER_H
#include "DllMacro.h"
#include "modulesystem/Requirement.h"
#include <QFutureWatcher>
#include <QObject>
#include <QTimer>
#include <QVector>
namespace Calamares
{
class Module;
class RequirementsModel;
/** @brief A manager-class that checks all the module requirements
*
* Asynchronously checks the requirements for each module, and
* emits progress signals as appropriate.
*/
class DLLEXPORT RequirementsChecker : public QObject
{
Q_OBJECT
public:
RequirementsChecker( QVector< Module* > modules, RequirementsModel* model, QObject* parent = nullptr );
~RequirementsChecker() override;
public Q_SLOTS:
/// @brief Start checking all the requirements
void run();
/// @brief Called when requirements are reported by a module
void addCheckedRequirements( Module* );
/// @brief Called when all requirements have been checked
void finished();
/// @brief Called periodically while requirements are being checked
void reportProgress();
signals:
/// @brief Human-readable progress message
void requirementsProgress( const QString& );
/// @brief Emitted after requirementsComplete
void done();
private:
QVector< Module* > m_modules;
using Watcher = QFutureWatcher< void >;
QVector< Watcher* > m_watchers;
RequirementsModel* m_model;
QTimer* m_progressTimer;
unsigned m_progressTimeouts;
};
} // namespace Calamares
#endif

View File

@@ -0,0 +1,100 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019-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 CALAMARES_REQUIREMENTSMODEL_H
#define CALAMARES_REQUIREMENTSMODEL_H
#include "Requirement.h"
#include "DllMacro.h"
#include <QAbstractListModel>
#include <QMutex>
namespace Calamares
{
class RequirementsChecker;
/** @brief System requirements from each module and their checked-status
*
* A Calamares module can have system requirements (e.g. check for
* internet, or amount of RAM, or an available disk) which can
* be stated and checked.
*
* This model collects those requirements, can run the checks, and
* reports on the overall status of those checks.
*/
class DLLEXPORT RequirementsModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY( bool satisfiedRequirements READ satisfiedRequirements NOTIFY satisfiedRequirementsChanged FINAL )
Q_PROPERTY( bool satisfiedMandatory READ satisfiedMandatory NOTIFY satisfiedMandatoryChanged FINAL )
Q_PROPERTY( QString progressMessage READ progressMessage NOTIFY progressMessageChanged FINAL )
public:
using QAbstractListModel::QAbstractListModel;
enum Roles : short
{
NegatedText = Qt::DisplayRole,
Details = Qt::ToolTipRole,
Name = Qt::UserRole,
Satisfied,
Mandatory,
HasDetails
};
// No Q_ENUM because these are exposed through roleNames()
///@brief Are all the requirements satisfied?
bool satisfiedRequirements() const { return m_satisfiedRequirements; }
///@brief Are all the **mandatory** requirements satisfied?
bool satisfiedMandatory() const { return m_satisfiedMandatory; }
///@brief Message (from an ongoing check) about progress
QString progressMessage() const { return m_progressMessage; }
QVariant data( const QModelIndex& index, int role ) const override;
int rowCount( const QModelIndex& ) const override; // TODO 3.4 use qsizetype
int count() const { return static_cast< int >( m_requirements.count() ); } // TODO 3.4 use qsizetype
///@brief Debugging tool, describe the checking-state
void describe() const;
///@brief Update progress message (called by the checker)
void setProgressMessage( const QString& m );
///@brief Append some requirements; resets the model
void addRequirementsList( const Calamares::RequirementsList& requirements );
///@brief Check the whole list, emit signals satisfied...()
void reCheckList();
signals:
void satisfiedRequirementsChanged( bool value );
void satisfiedMandatoryChanged( bool value );
void progressMessageChanged( QString message );
protected:
QHash< int, QByteArray > roleNames() const override;
///@brief Clears the requirements; resets the model
void clear();
private:
QString m_progressMessage;
QMutex m_addLock;
RequirementsList m_requirements;
bool m_satisfiedRequirements = false;
bool m_satisfiedMandatory = false;
};
} // namespace Calamares
#endif

View File

@@ -0,0 +1,53 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARES_VIEWMODULE_H
#define CALAMARES_VIEWMODULE_H
#include "DllMacro.h"
#include "modulesystem/Module.h"
class QPluginLoader;
namespace Calamares
{
class ViewStep;
class UIDLLEXPORT ViewModule : public Module
{
public:
Type type() const override;
Interface interface() const override;
void loadSelf() override;
JobList jobs() const override;
RequirementsList checkRequirements() override;
protected:
void initFrom( const ModuleSystem::Descriptor& moduleDescriptor ) override;
private:
explicit ViewModule();
~ViewModule() override;
QPluginLoader* m_loader;
ViewStep* m_viewStep = nullptr;
friend Module* Calamares::moduleFromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
};
} // namespace Calamares
#endif // CALAMARES_VIEWMODULE_H

View File

@@ -0,0 +1,166 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef LIBCALAMARES_NETWORK_MANAGER_H
#define LIBCALAMARES_NETWORK_MANAGER_H
#include "DllMacro.h"
#include <QByteArray>
#include <QDebug>
#include <QObject>
#include <QUrl>
#include <QVector>
#include <chrono>
#include <memory>
class QNetworkReply;
class QNetworkRequest;
namespace Calamares
{
namespace Network
{
class DLLEXPORT RequestOptions
{
public:
using milliseconds = std::chrono::milliseconds;
enum Flag
{
FollowRedirect = 0x1,
FakeUserAgent = 0x100
};
Q_DECLARE_FLAGS( Flags, Flag )
RequestOptions()
: m_flags( Flags() )
, m_timeout( -1 )
{
}
RequestOptions( Flags f, milliseconds timeout = milliseconds( -1 ) )
: m_flags( f )
, m_timeout( timeout )
{
}
void applyToRequest( QNetworkRequest* ) const;
bool hasTimeout() const { return m_timeout > milliseconds( 0 ); }
auto timeout() const { return m_timeout; }
private:
Flags m_flags;
milliseconds m_timeout;
};
Q_DECLARE_OPERATORS_FOR_FLAGS( RequestOptions::Flags );
struct RequestStatus
{
enum State
{
Ok,
Timeout, // Timeout exceeded
Failed, // bad Url
HttpError, // some other HTTP error (eg. SSL failed)
Empty // for ping(), response is empty
};
RequestStatus( State s = Ok )
: status( s )
{
}
operator bool() const { return status == Ok; }
State status;
};
DLLEXPORT QDebug& operator<<( QDebug& s, const RequestStatus& e );
class DLLEXPORT Manager : public QObject
{
Q_OBJECT
Q_PROPERTY( bool hasInternet READ hasInternet NOTIFY hasInternetChanged FINAL )
Q_PROPERTY( QVector< QUrl > checkInternetUrls READ getCheckInternetUrls WRITE setCheckHasInternetUrl )
public:
Manager();
~Manager() override;
/** @brief Checks if the given @p url returns data.
*
* Returns a RequestStatus, which converts to @c true if the ping
* was successful. Other status reasons convert to @c false,
* typically because of no data, a Url error or no network access.
*
* May return Empty if the request was successful but returned
* no data at all.
*/
RequestStatus synchronousPing( const QUrl& url, const RequestOptions& options = RequestOptions() );
/** @brief Downloads the data from a given @p url
*
* Returns the data as a QByteArray, or an empty
* array if any error occurred (or no data was returned).
*/
QByteArray synchronousGet( const QUrl& url, const RequestOptions& options = RequestOptions() );
/** @brief Do a network request asynchronously.
*
* Returns a pointer to the reply-from-the-request.
* This may be a nullptr if an error occurs immediately.
* The caller is responsible for cleaning up the reply (eventually).
*/
QNetworkReply* asynchronousGet( const QUrl& url, const RequestOptions& options = RequestOptions() );
/// @brief Set the URL which is used for the general "is there internet" check.
static void setCheckHasInternetUrl( const QUrl& url );
/// @brief Adds an (extra) URL to check
static void addCheckHasInternetUrl( const QUrl& url );
/// @brief Set a collection of URLs used for the general "is there internet" check.
static void setCheckHasInternetUrl( const QVector< QUrl >& urls );
/// @brief What URLs are used to check for internet connectivity?
static QVector< QUrl > getCheckInternetUrls();
public Q_SLOTS:
/** @brief Do an explicit check for internet connectivity.
*
* This **may** do a ping to the configured check URL, but can also
* use other mechanisms.
*/
bool checkHasInternet();
/** @brief Is there internet connectivity?
*
* This returns the result of the last explicit check, or if there
* is other information about the state of the internet connection,
* whatever is known. @c true means you can expect (all) internet
* connectivity to be present.
*/
bool hasInternet();
signals:
/** @brief Indicates that internet connectivity status has changed
*
* The value is that returned from hasInternet() -- @c true when there
* is connectivity, @c false otherwise.
*/
void hasInternetChanged( bool );
private:
class Private;
};
} // namespace Network
} // namespace Calamares
#endif // LIBCALAMARES_NETWORK_MANAGER_H

View File

@@ -0,0 +1,32 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef LIBCALAMARES_NETWORK_TESTS_H
#define LIBCALAMARES_NETWORK_TESTS_H
#include <QObject>
class NetworkTests : public QObject
{
Q_OBJECT
public:
NetworkTests();
~NetworkTests() override;
private Q_SLOTS:
void initTestCase();
void testInstance();
void testPing();
void testCheckUrl();
void testCheckMultiUrl();
};
#endif

View File

@@ -0,0 +1,45 @@
/* === 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 LIBCALAMARES_PACKAGES_GLOBALS_H
#define LIBCALAMARES_PACKAGES_GLOBALS_H
#include "DllMacro.h"
#include "GlobalStorage.h"
#include "modulesystem/InstanceKey.h"
namespace Calamares
{
namespace Packages
{
/** @brief Sets the install-packages GS keys for the given module
*
* This replaces previously-set install-packages lists for the
* given module by the two new lists.
*
* Returns @c true if anything was changed, @c false otherwise.
*/
DLLEXPORT bool setGSPackageAdditions( Calamares::GlobalStorage* gs,
const Calamares::ModuleSystem::InstanceKey& module,
const QVariantList& installPackages,
const QVariantList& tryInstallPackages );
/** @brief Sets the install-packages GS keys for the given module
*
* This replaces previously-set install-packages lists. Use this with
* plain lists of package names. It does not support try-install.
*/
DLLEXPORT bool setGSPackageAdditions( Calamares::GlobalStorage* gs,
const Calamares::ModuleSystem::InstanceKey& module,
const QStringList& installPackages );
// void setGSPackageRemovals( const Calamares::ModuleSystem::InstanceKey& key, const QVariantList& removePackages );
} // namespace Packages
} // namespace Calamares
#endif

View File

@@ -0,0 +1,51 @@
/* === 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 PARTITION_AUTOMOUNT_H
#define PARTITION_AUTOMOUNT_H
#include "DllMacro.h"
#include <memory>
namespace Calamares
{
namespace Partition
{
struct AutoMountInfo;
/** @brief Disable automount
*
* Various subsystems can do "agressive automount", which can get in the
* way of partitioning actions. In particular, Solid can be configured
* to automount every device it sees, and partitioning happens in multiple
* steps (create table, create partition, set partition flags) which are
* blocked if the partition gets mounted partway through the operation.
*
* @param disable set this to false to reverse the sense of the function
* call and force *enabling* automount, instead.
*
* Returns an opaque structure which can be passed to automountRestore()
* to return the system to the previously-configured automount settings.
*/
DLLEXPORT std::shared_ptr< AutoMountInfo > automountDisable( bool disable = true );
/** @brief Restore automount settings
*
* Pass the value returned from automountDisable() to restore the
* previous settings.
*/
DLLEXPORT void automountRestore( const std::shared_ptr< AutoMountInfo >& t );
} // namespace Partition
} // namespace Calamares
#endif

View File

@@ -0,0 +1,100 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
* SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
/*
* NOTE: this functionality is only available when Calamares is compiled
* with KPMcore support.
*/
#ifndef PARTITION_FILESYSTEM_H
#define PARTITION_FILESYSTEM_H
#include "DllMacro.h"
#include "partition/Global.h"
#include <kpmcore/fs/filesystem.h>
namespace Calamares
{
namespace Partition
{
QString DLLEXPORT prettyNameForFileSystemType( FileSystem::Type t );
/** @brief Returns a machine-readable identifier for the filesystem type
*
* This identifier is used in filesystem manipulation --
* e.g. when mounting the filesystem, or in /etc/fstab. It
* is almost always just what KPMCore says it is, with
* the following exceptions:
* - reiserfs is called "reiser" by KPMCore, "reiserfs" by Calamares
*/
QString DLLEXPORT untranslatedFS( FileSystem::Type t );
/** @brief Returns the machine-readable identifier for the given @p fs
*
* See notes for untranslatedFS(), above.
*/
static inline QString
untranslatedFS( FileSystem& fs )
{
return untranslatedFS( fs.type() );
}
/** @brief Returns a machine-readable identifier for the given @p fs
*
* Returns an empty string is the @p fs is not valid (e.g. nullptr).
*/
static inline QString
untranslatedFS( FileSystem* fs )
{
return fs ? untranslatedFS( *fs ) : QString();
}
static inline QString
userVisibleFS( FileSystem& fs )
{
return fs.name();
}
static inline QString
userVisibleFS( FileSystem* fs )
{
return fs ? userVisibleFS( *fs ) : QString();
}
/** @brief Mark a particular filesystem type as used (or not)
*
* See useFilesystemGS(const QString&, bool); this method uses the filesystem type
* enumeration to pick the name. (The other implementation is in `Global.h`
* because it touches Global Storage, but this one needs KPMcore)
*/
inline void
useFilesystemGS( FileSystem::Type filesystem, bool used )
{
useFilesystemGS( untranslatedFS( filesystem ), used );
}
/* @brief Reads from global storage whether the typesystem type is used
*
* See isFilesystemUsedGS(const QString&). (The other implementation is in `Global.h`
* because it touches Global Storage, but this one needs KPMcore)
*/
inline bool
isFilesystemUsedGS( FileSystem::Type filesystem )
{
return isFilesystemUsedGS( untranslatedFS( filesystem ) );
}
} // namespace Partition
} // namespace Calamares
#endif // PARTITION_PARTITIONQUERY_H

View File

@@ -0,0 +1,78 @@
/* === 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.
*
*
*/
/*
* This is the API for manipulating Global Storage keys related to
* filesystems and partitions. This does **not** depend on KPMcore.
*/
#ifndef PARTITION_GLOBAL_H
#define PARTITION_GLOBAL_H
#include "DllMacro.h"
#include "JobQueue.h"
namespace Calamares
{
namespace Partition
{
/** @brief Mark a particular filesystem type as used (or not)
*
* Filesystems are marked used (or not) in the global storage
* key *filesystem_use*. Sub-keys are the filesystem name,
* and the values are boolean; filesystems that are used in
* the target system are marked with @c true. Unused filesystems
* may be unmarked, or may be marked @c false.
*
* The filesystem name should be the untranslated name. Filesystem
* names are **lower**cased when used as keys.
*/
void DLLEXPORT useFilesystemGS( Calamares::GlobalStorage* gs, const QString& filesystemType, bool used );
/** @brief Reads from global storage whether the filesystem type is used
*
* Reads from the global storage key *filesystem_use* and returns
* the boolean value stored in subkey @p filesystemType. Returns
* @c false if the subkey is not set at all.
*
* The filesystem name should be the untranslated name. Filesystem
* names are **lower**cased when used as keys.
*/
bool DLLEXPORT isFilesystemUsedGS( const Calamares::GlobalStorage* gs, const QString& filesystemType );
/** @brief Clears the usage data for filesystems
*
* This removes the internal key *filesystem_use*.
*/
void DLLEXPORT clearFilesystemGS( Calamares::GlobalStorage* gs );
/** @brief Convenience function for using "the" Global Storage
*
* @see useFilesystemGS(const QString&, bool)
*/
inline void
useFilesystemGS( const QString& filesystemType, bool used )
{
useFilesystemGS( Calamares::JobQueue::instanceGlobalStorage(), filesystemType, used );
}
/** @brief Convenience function for using "the" Global Storage
*
* @see isFilesystemUsedGS(const QString&);
*/
inline bool
isFilesystemUsedGS( const QString& filesystemType )
{
return isFilesystemUsedGS( Calamares::JobQueue::instanceGlobalStorage(), filesystemType );
}
} // namespace Partition
} // namespace Calamares
#endif

View File

@@ -0,0 +1,43 @@
/* === 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.
*
*/
/*
* KPMCore header file inclusion.
*
* Includes the system KPMCore headers without warnings (by switching off
* the expected warnings).
*/
#ifndef PARTITION_KPMHELPER_H
#define PARTITION_KPMHELPER_H
#include <qglobal.h>
// The kpmcore headers are not C++17 warning-proof, especially
// with picky compilers like Clang 10. Since we use Clang for the
// find-all-the-warnings case, switch those warnings off for
// the we-can't-change-them system headers.
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG( "-Wdocumentation" )
QT_WARNING_DISABLE_CLANG( "-Wsuggest-destructor-override" )
QT_WARNING_DISABLE_CLANG( "-Winconsistent-missing-destructor-override" )
// Because of __lastType
QT_WARNING_DISABLE_CLANG( "-Wreserved-identifier" )
#include <backend/corebackend.h>
#include <core/device.h>
#include <core/lvmdevice.h>
#include <core/partition.h>
#include <core/partitionrole.h>
#include <core/partitiontable.h>
#include <fs/filesystem.h>
#include <fs/filesystemfactory.h>
QT_WARNING_POP
#endif

View File

@@ -0,0 +1,63 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
/*
* NOTE: this functionality is only available when Calamares is compiled
* with KPMcore support.
*/
#ifndef PARTITION_KPMMANAGER_H
#define PARTITION_KPMMANAGER_H
#include "DllMacro.h"
#include <memory>
class CoreBackend;
namespace Calamares
{
namespace Partition
{
/// @brief Handle to KPMCore
class InternalManager;
/** @brief KPMCore loader and cleanup
*
* A Calamares plugin that uses KPMCore should hold an object of
* this class; its only responsibility is to load KPMCore
* and to cleanly unload it on destruction (with KPMCore 4,
* also to shutdown the privileged helper application).
*
* It loads the default plugin ("parted" with KPMCore 3, "sfdisk"
* with KPMCore 4), but this can be overridden by setting the
* environment variable KPMCORE_BACKEND. Setting it to
* "dummy" will load the dummy plugin instead.
*/
class DLLEXPORT KPMManager
{
public:
KPMManager();
~KPMManager();
/// @brief Is KPMCore loaded correctly?
operator bool() const;
/// @brief Gets the KPMCore backend (e.g. CoreBackendManager::self()->backend() )
CoreBackend* backend() const;
private:
std::shared_ptr< InternalManager > m_d;
};
} // namespace Partition
} // namespace Calamares
#endif // PARTITION_KPMMANAGER_H

View File

@@ -0,0 +1,112 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef PARTITION_MOUNT_H
#define PARTITION_MOUNT_H
#include "DllMacro.h"
#include <QList>
#include <QString>
#include <QStringList>
#include <memory>
namespace Calamares
{
namespace Partition
{
/**
* Runs the mount utility with the specified parameters.
* @param devicePath the path of the partition to mount.
* @param mountPoint the full path of the target mount point.
* @param filesystemName the name of the filesystem (optional).
* @param options any additional options as passed to mount -o (optional).
* If @p options starts with a dash (-) then it is passed unchanged
* and no -o option is added; this is used in handling --bind mounts.
* @returns the program's exit code, or:
* Crashed = QProcess crash
* FailedToStart = QProcess cannot start
* NoWorkingDirectory = bad arguments
*/
DLLEXPORT int mount( const QString& devicePath,
const QString& mountPoint,
const QString& filesystemName = QString(),
const QString& options = QString() );
/** @brief Unmount the given @p path (device or mount point).
*
* Runs umount(8) in the host system.
*
* @returns the program's exit code, or special codes like mount().
*/
DLLEXPORT int unmount( const QString& path, const QStringList& options = QStringList() );
/** @brief Mount and automatically unmount a device
*
* The TemporaryMount object mounts a filesystem, and is like calling
* the mount() function, above. When the object is destroyed, unmount()
* is called with suitable options to undo the original mount.
*/
class DLLEXPORT TemporaryMount
{
public:
TemporaryMount( const QString& devicePath,
const QString& filesystemName = QString(),
const QString& options = QString() );
TemporaryMount( const TemporaryMount& ) = delete;
TemporaryMount& operator=( const TemporaryMount& ) = delete;
~TemporaryMount();
bool isValid() const { return bool( m_d ); }
QString path() const;
private:
struct Private;
std::unique_ptr< Private > m_d;
};
/** @brief Information about a mount point from /etc/mtab
*
* Entries in /etc/mtab are of the form: <device> <mountpoint> <other>
* This struct only stores device and mountpoint.
*
* The main way of getting these structs is to call fromMtab() to read
* an /etc/mtab-like file and storing all of the entries from it.
*/
struct DLLEXPORT MtabInfo
{
QString device;
QString mountPoint;
/** @brief Reads an mtab-like file and returns the entries from it
*
* When @p mtabPath is given, that file is read. If the given name is
* empty (e.g. the default) then /etc/mtab is read, instead.
*
* If @p mountPrefix is given, then only entries that have a mount point
* that starts with that prefix are returned.
*/
static QList< MtabInfo > fromMtabFilteredByPrefix( const QString& mountPrefix = QString(),
const QString& mtabPath = QString() );
/// @brief Predicate to sort MtabInfo objects by device-name
static bool deviceOrder( const MtabInfo& a, const MtabInfo& b ) { return a.device > b.device; }
/// @brief Predicate to sort MtabInfo objects by mount-point
static bool mountPointOrder( const MtabInfo& a, const MtabInfo& b ) { return a.mountPoint > b.mountPoint; }
};
} // namespace Partition
} // namespace Calamares
#endif

View File

@@ -0,0 +1,69 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
* SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
/*
* NOTE: this functionality is only available when Calamares is compiled
* with KPMcore support.
*/
#ifndef PARTITION_PARTITIONITERATOR_H
#define PARTITION_PARTITIONITERATOR_H
#include "DllMacro.h"
class Device;
class Partition;
class PartitionTable;
namespace Calamares
{
namespace Partition
{
/** @brief Iterator over KPMCore partitions
*
* A forward-only iterator to go through the partitions of a device,
* independently of whether they are primary, logical or extended.
*
* An iterator can be created from a device (then it refers to the
* partition table of that device) or a partition table. The
* partition table must remain valid throughout iteration.
*
* A nullptr is valid, for an empty iterator.
*/
class DLLEXPORT PartitionIterator
{
public:
::Partition* operator*() const;
void operator++();
bool operator==( const PartitionIterator& other ) const;
bool operator!=( const PartitionIterator& other ) const;
static PartitionIterator begin( ::Device* device );
static PartitionIterator begin( ::PartitionTable* table );
static PartitionIterator end( ::Device* device );
static PartitionIterator end( ::PartitionTable* table );
private:
PartitionIterator( ::PartitionTable* table );
::PartitionTable* m_table;
::Partition* m_current = nullptr;
};
} // namespace Partition
} // namespace Calamares
#endif // PARTITION_PARTITIONITERATOR_H

View File

@@ -0,0 +1,77 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
* SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
/*
* NOTE: this functionality is only available when Calamares is compiled
* with KPMcore support.
*/
#ifndef PARTITION_PARTITIONQUERY_H
#define PARTITION_PARTITIONQUERY_H
#include "DllMacro.h"
#include <QList>
#include <functional>
class Device;
class Partition;
class PartitionTable;
namespace Calamares
{
namespace Partition
{
using ::Device;
using ::Partition;
using ::PartitionTable;
/** @brief Get partition table */
DLLEXPORT const PartitionTable* getPartitionTable( const Partition* partition );
/** @brief Is this a free-space area? */
DLLEXPORT bool isPartitionFreeSpace( const Partition* );
/** @brief Is this partition newly-to-be-created?
*
* Returns true if the partition is planned to be created by the installer as
* opposed to already existing on the disk.
*/
DLLEXPORT bool isPartitionNew( const Partition* );
/**
* Iterates on all devices and return the first partition which is (already)
* mounted on @p mountPoint.
*/
DLLEXPORT Partition* findPartitionByCurrentMountPoint( const QList< Device* >& devices, const QString& mountPoint );
// TODO: add this distinction
// Partition* findPartitionByIntendedMountPoint( const QList< Device* >& devices, const QString& mountPoint );
/**
* Iterates on all devices and partitions and returns a pointer to the Partition object
* for the given path, or nullptr if a Partition for the given path cannot be found.
*/
DLLEXPORT Partition* findPartitionByPath( const QList< Device* >& devices, const QString& path );
/**
* Iterates on all devices and partitions and returns a list of pointers to the Partition
* objects that satisfy the conditions defined in the criterion function.
*/
DLLEXPORT QList< Partition* > findPartitions( const QList< Device* >& devices,
std::function< bool( Partition* ) > criterionFunction );
} // namespace Partition
} // namespace Calamares
#endif // PARTITION_PARTITIONQUERY_H

View File

@@ -0,0 +1,120 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Collabora Ltd <arnaud.ferraris@collabora.com>
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef PARTITION_PARTITIONSIZE_H
#define PARTITION_PARTITIONSIZE_H
#include "DllMacro.h"
#include "utils/NamedSuffix.h"
#include "utils/Units.h"
// Qt
#include <QString>
namespace Calamares
{
namespace Partition
{
enum class SizeUnit
{
None,
Percent,
Byte,
KB,
KiB,
MB,
MiB,
GB,
GiB
};
/** @brief Partition size expressions
*
* Sizes can be specified in bytes, KiB, MiB, GiB or percent (of
* the available drive space are on). This class handles parsing
* of such strings from the config file.
*/
class DLLEXPORT PartitionSize : public NamedSuffix< SizeUnit, SizeUnit::None >
{
public:
PartitionSize()
: NamedSuffix()
{
}
PartitionSize( int v, SizeUnit u )
: NamedSuffix( v, u )
{
}
PartitionSize( const QString& );
bool isValid() const { return ( unit() != SizeUnit::None ) && ( value() > 0 ); }
bool operator<( const PartitionSize& other ) const;
bool operator>( const PartitionSize& other ) const;
bool operator==( const PartitionSize& other ) const;
/** @brief Convert the size to the number of sectors @p totalSectors .
*
* Each sector has size @p sectorSize, for converting sizes in Bytes,
* KiB, MiB or GiB to sector counts.
*
* @return the number of sectors needed, or -1 for invalid sizes.
*/
qint64 toSectors( qint64 totalSectors, qint64 sectorSize ) const;
/** @brief Convert the size to bytes.
*
* The device's sectors count @p totalSectors and sector size
* @p sectoreSize are used to calculated the total size, which
* is then used to calculate the size when using Percent.
*
* @return the size in bytes, or -1 for invalid sizes.
*/
qint64 toBytes( qint64 totalSectors, qint64 sectorSize ) const;
/** @brief Convert the size to bytes.
*
* Total size @p totalBytes is needed for sizes in Percent. This
* parameter is unused in any other case.
*
* @return the size in bytes, or -1 for invalid sizes.
*/
qint64 toBytes( qint64 totalBytes ) const;
/** @brief Convert the size to bytes.
*
* This method is only valid for sizes in Bytes, KiB, MiB or GiB.
* It will return -1 in any other case. Note that 0KiB and 0MiB and
* 0GiB are considered **invalid** sizes and return -1.
*
* @return the size in bytes, or -1 if it cannot be calculated.
*/
qint64 toBytes() const;
/** @brief Are the units comparable?
*
* None units cannot be compared with anything. Percentages can
* be compared with each other, and all the explicit sizes (KiB, ...)
* can be compared with each other.
*/
static constexpr bool unitsComparable( const SizeUnit u1, const SizeUnit u2 )
{
return !( ( u1 == SizeUnit::None || u2 == SizeUnit::None )
|| ( u1 == SizeUnit::Percent && u2 != SizeUnit::Percent )
|| ( u1 != SizeUnit::Percent && u2 == SizeUnit::Percent ) );
}
};
} // namespace Partition
} // namespace Calamares
#endif // PARTITION_PARTITIONSIZE_H

View File

@@ -0,0 +1,40 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef PARTITION_SYNC_H
#define PARTITION_SYNC_H
#include "DllMacro.h"
namespace Calamares
{
namespace Partition
{
/** @brief Run "udevadm settle" or other disk-sync mechanism.
*
* Call this after mounting, unmount, toggling swap, or other functions
* that might cause the disk to be "busy" for other disk-modifying
* actions (in particular, KPMcore actions with the sfdisk backend
* are sensitive, and systemd tends to keep disks busy after a change
* for a while).
*/
DLLEXPORT void sync();
/** @brief RAII class for calling sync() */
struct DLLEXPORT Syncer
{
~Syncer() { sync(); }
};
} // namespace Partition
} // namespace Calamares
#endif

View File

@@ -0,0 +1,167 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_COMMANDLIST_H
#define UTILS_COMMANDLIST_H
#include "DllMacro.h"
#include "Job.h"
#include <QStringList>
#include <QVariant>
#include <chrono>
#include <optional>
#include <utility>
class KMacroExpanderBase;
namespace Calamares
{
/**
* Each command can have an associated timeout in seconds. The timeout
* defaults to 10 seconds. Provide some convenience naming and construction.
*/
class DLLEXPORT CommandLine
{
public:
static inline constexpr std::chrono::seconds TimeoutNotSet() { return std::chrono::seconds( -1 ); }
/// An invalid command line
CommandLine() = default;
CommandLine( const QString& s )
: m_command( s )
{
}
CommandLine( const QString& s, std::chrono::seconds t )
: m_command( s )
, m_timeout( t )
{
}
CommandLine( const QString& s, const QStringList& env, std::chrono::seconds t )
: m_command( s )
, m_environment( env )
, m_timeout( t )
{
}
/** @brief Constructs a CommandLine from a map with keys
*
* Relevant keys are *command*, *environment* and *timeout*.
*/
CommandLine( const QVariantMap& m );
QString command() const { return m_command; }
[[nodiscard]] QStringList environment() const { return m_environment; }
std::chrono::seconds timeout() const { return m_timeout; }
bool isVerbose() const { return m_verbose.value_or( false ); }
bool isValid() const { return !m_command.isEmpty(); }
/** @brief Returns a copy of this one command, with variables expanded
*
* The given macro-expander is used to expand the command-line.
* This will normally be a Calamares::String::DictionaryExpander
* instance, which handles the ROOT and USER variables.
*/
DLLEXPORT CommandLine expand( KMacroExpanderBase& expander ) const;
/** @brief As above, with a default macro-expander.
*
* The default macro-expander assumes RunInHost (e.g. ROOT will
* expand to the RootMountPoint set in Global Storage).
*/
DLLEXPORT CommandLine expand() const;
/** @brief If nothing has set verbosity yet, update to @p verbose */
void updateVerbose( bool verbose )
{
if ( !m_verbose.has_value() )
{
m_verbose = verbose;
}
}
/** @brief Unconditionally set verbosity (can also reset it to nullopt) */
void setVerbose( std::optional< bool > v ) { m_verbose = v; }
private:
QString m_command;
QStringList m_environment;
std::chrono::seconds m_timeout = TimeoutNotSet();
std::optional< bool > m_verbose;
};
/** @brief Abbreviation, used internally. */
using CommandList_t = QList< CommandLine >;
/**
* A list of commands; the list may have its own default timeout
* for commands (which is then applied to each individual command
* that doesn't have one of its own).
*
* Documentation for the format of commands can be found in
* `shellprocess.conf`.
*/
class DLLEXPORT CommandList : protected CommandList_t
{
public:
/** @brief empty command-list with timeout to apply to entries. */
CommandList( bool doChroot = true, std::chrono::seconds timeout = std::chrono::seconds( 10 ) );
/** @brief command-list constructed from script-entries in @p v
*
* The global settings @p doChroot and @p timeout can be overridden by
* the individual script-entries.
*/
CommandList( const QVariant& v, bool doChroot = true, std::chrono::seconds timeout = std::chrono::seconds( 10 ) );
CommandList( int ) = delete;
CommandList( const QVariant&, int ) = delete;
bool doChroot() const { return m_doChroot; }
std::chrono::seconds defaultTimeout() const { return m_timeout; }
Calamares::JobResult run();
using CommandList_t::at;
using CommandList_t::cbegin;
using CommandList_t::cend;
using CommandList_t::const_iterator;
using CommandList_t::count;
using CommandList_t::isEmpty;
using CommandList_t::push_back;
using CommandList_t::value_type;
/** @brief Return a copy of this command-list, with variables expanded
*
* Each command-line in the list is expanded with the given @p expander.
* @see CommandLine::expand() for details.
*/
DLLEXPORT CommandList expand( KMacroExpanderBase& expander ) const;
/** @brief As above, with a default macro-expander.
*
* Each command-line in the list is expanded with that default macro-expander.
* @see CommandLine::expand() for details.
*/
DLLEXPORT CommandList expand() const;
/** @brief Applies default-value @p verbose to each entry without an explicit setting. */
DLLEXPORT void updateVerbose( bool verbose );
private:
bool m_doChroot;
std::chrono::seconds m_timeout;
};
} // namespace Calamares
#endif

View File

@@ -0,0 +1,61 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2013-2016 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Originally from Tomahawk, portions:
* SPDX-FileCopyrightText: 2010-2011 Christian Muehlhaeuser <muesli@tomahawk-player.org>
* SPDX-FileCopyrightText: 2010-2011 Leo Franchi <lfranchi@kde.org>
* SPDX-FileCopyrightText: 2010-2012 Jeff Mitchell <jeff@tomahawk-player.org>
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_DIRS_H
#define UTILS_DIRS_H
#include "DllMacro.h"
#include <QDir>
namespace Calamares
{
/**
* @brief appDataDir returns the directory with common application data.
* Defaults to CMAKE_INSTALL_FULL_DATADIR (usually /usr/share/calamares).
*/
DLLEXPORT QDir appDataDir();
/**
* @brief appLogDir returns the directory for Calamares logs.
* Defaults to QStandardPaths::CacheLocation (usually ~/.cache/Calamares).
*/
DLLEXPORT QDir appLogDir();
/**
* @brief systemLibDir returns the system's lib directory.
* Defaults to CMAKE_INSTALL_FULL_LIBDIR (usually /usr/lib64 or /usr/lib).
*/
DLLEXPORT QDir systemLibDir();
/**
* Override app data dir. Only for testing purposes.
*/
DLLEXPORT void setAppDataDir( const QDir& dir );
DLLEXPORT bool isAppDataDirOverridden();
/** @brief Setup extra config and data dirs from the XDG variables.
*/
DLLEXPORT void setXdgDirs();
/** @brief Are any extra directories configured? */
DLLEXPORT bool haveExtraDirs();
/** @brief XDG_CONFIG_DIRS, each guaranteed to end with / */
DLLEXPORT QStringList extraConfigDirs();
/** @brief XDG_DATA_DIRS, each guaranteed to end with / */
DLLEXPORT QStringList extraDataDirs();
} // namespace Calamares
#endif

View File

@@ -0,0 +1,46 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019-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 UTILS_ENTROPY_H
#define UTILS_ENTROPY_H
#include "DllMacro.h"
#include <QByteArray>
namespace Calamares
{
/// @brief Which entropy source was actually used for the entropy.
enum class EntropySource
{
None, ///< Buffer is empty, no random data
URandom, ///< Read from /dev/urandom
Twister ///< Generated by pseudo-random
};
/** @brief Fill buffer @p b with exactly @p size random bytes
*
* The array is cleared and resized, then filled with 0xcb
* "just in case", after which it is filled with random
* bytes from a suitable source. Returns which source was used.
*/
DLLEXPORT EntropySource getEntropy( int size, QByteArray& b );
/** @brief Fill string @p s with exactly @p size random printable ASCII characters
*
* The characters are picked from a set of 64 (2^6). The string
* contains 6 * size bits of entropy. * Returns which source was used.
* @see getEntropy
*/
DLLEXPORT EntropySource getPrintableEntropy( int size, QString& s );
} // namespace Calamares
#endif

View File

@@ -0,0 +1,102 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef CALAMARESUTILSGUI_H
#define CALAMARESUTILSGUI_H
#include "DllMacro.h"
#include <QObject>
#include <QPixmap>
#include <QSize>
class QLayout;
namespace Calamares
{
/**
* @brief The ImageType enum lists all common Calamares icons.
* Icons are loaded from SVGs and cached. Each icon has an enum value, through which
* it can be accessed.
* You can forward-declare this as:
* enum ImageType : int;
*/
enum ImageType : int
{
Yes,
No,
Information,
Fail,
Bugs,
Help,
Release,
Donate,
PartitionDisk,
PartitionPartition,
PartitionAlongside,
PartitionEraseAuto,
PartitionManual,
PartitionReplaceOs,
PartitionTable,
BootEnvironment,
Squid,
StatusOk, // Icons for the requirements checker
StatusWarning,
StatusError
};
/**
* @brief The ImageMode enum contains different transformations that can be applied.
* Most of these are currently unused.
*/
enum ImageMode
{
Original,
CoverInCase,
Grid,
DropShadow,
};
/**
* @brief defaultPixmap returns a resized and/or transformed pixmap for a given
* ImageType.
* @param type the ImageType i.e. the enum value for an SVG.
* @param mode the transformation to apply (default: no transformation).
* @param size the target pixmap size (default: original SVG size).
* @return the new pixmap.
*/
UIDLLEXPORT QPixmap defaultPixmap( ImageType type,
ImageMode mode = Calamares::Original,
const QSize& size = QSize( 0, 0 ) );
/**
* @brief unmarginLayout recursively walks the QLayout tree and removes all margins.
* @param layout the layout to unmargin.
*/
UIDLLEXPORT void unmarginLayout( QLayout* layout );
UIDLLEXPORT void setDefaultFontSize( int points );
UIDLLEXPORT int defaultFontSize(); // in points
UIDLLEXPORT int defaultFontHeight(); // in pixels, DPI-specific
UIDLLEXPORT QFont largeFont();
UIDLLEXPORT QSize defaultIconSize();
/**
* @brief Size constants for the main Calamares window.
*/
constexpr int windowMinimumWidth = 800;
constexpr int windowMinimumHeight = 520;
constexpr int windowPreferredWidth = 1024;
constexpr int windowPreferredHeight = 520;
} // namespace Calamares
#endif // CALAMARESUTILSGUI_H

View File

@@ -0,0 +1,32 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2012 Christian Muehlhaeuser <muesli@tomahawk-player.org>
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#ifndef IMAGE_REGISTRY_H
#define IMAGE_REGISTRY_H
#include <QPixmap>
#include "DllMacro.h"
#include "utils/Gui.h"
class UIDLLEXPORT ImageRegistry
{
public:
static ImageRegistry* instance();
explicit ImageRegistry();
QIcon icon( const QString& image, Calamares::ImageMode mode = Calamares::Original );
QPixmap pixmap( const QString& image, const QSize& size, Calamares::ImageMode mode = Calamares::Original );
private:
qint64 cacheKey( const QSize& size );
void putInCache( const QString& image, const QSize& size, Calamares::ImageMode mode, const QPixmap& pixmap );
};
#endif // IMAGE_REGISTRY_H

View File

@@ -0,0 +1,404 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2010-2011 Christian Muehlhaeuser <muesli@tomahawk-player.org>
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_LOGGER_H
#define UTILS_LOGGER_H
#include "DllMacro.h"
#include <QDebug>
#include <QSharedPointer>
#include <QVariant>
#include <memory>
namespace Logger
{
class Once;
struct FuncSuppressor
{
explicit constexpr FuncSuppressor( const char[] );
const char* m_s;
};
struct NoQuote_t
{
};
struct Quote_t
{
};
DLLEXPORT extern const FuncSuppressor Continuation;
DLLEXPORT extern const FuncSuppressor SubEntry;
DLLEXPORT extern const NoQuote_t NoQuote;
DLLEXPORT extern const Quote_t Quote;
enum
{
LOG_DISABLE = 0,
LOGERROR = 1,
LOGWARNING = 2,
LOGDEBUG = 6,
LOGVERBOSE = 8
};
class DLLEXPORT CDebug : public QDebug
{
public:
explicit CDebug( unsigned int debugLevel = LOGDEBUG, const char* func = nullptr );
virtual ~CDebug();
friend CDebug& operator<<( CDebug&&, const FuncSuppressor& );
friend CDebug& operator<<( CDebug&&, const Once& );
inline unsigned int level() const { return m_debugLevel; }
private:
QString m_msg;
unsigned int m_debugLevel;
const char* m_funcinfo = nullptr;
};
inline CDebug&
operator<<( CDebug&& s, const FuncSuppressor& f )
{
if ( s.m_funcinfo )
{
s.m_funcinfo = nullptr;
s.m_msg = QString( f.m_s );
}
return s;
}
inline QDebug&
operator<<( QDebug& s, const FuncSuppressor& f )
{
return s << f.m_s;
}
inline QDebug&
operator<<( QDebug& s, const NoQuote_t& )
{
return s.noquote().nospace();
}
inline QDebug&
operator<<( QDebug& s, const Quote_t& )
{
return s.quote().space();
}
/**
* @brief The full path of the log file.
*/
DLLEXPORT QString logFile();
/**
* @brief Start logging to the log file.
*
* Call this (once) to start logging to the log file (usually
* ~/.cache/calamares/session.log ). An existing log file is
* rolled over if it is too large.
*/
DLLEXPORT void setupLogfile();
/**
* @brief Set a log level for future logging.
*
* Pass in a value from the LOG* enum, above. Use 0 to
* disable logging. Values greater than LOGVERBOSE are
* limited to LOGVERBOSE, which will log everything.
*
* Practical values are 0, 1, 2, and 6.
*/
DLLEXPORT void setupLogLevel( unsigned int level );
/** @brief Return the configured log-level. */
DLLEXPORT unsigned int logLevel();
/** @brief Would the given @p level really be logged? */
DLLEXPORT bool logLevelEnabled( unsigned int level );
/**
* @brief Row-oriented formatted logging.
*
* Use DebugRow to produce multiple rows of 2-column output
* in a debugging statement. For instance,
* cDebug() << DebugRow<int,int>(1,12)
* << DebugRow<int,int>(2,24)
* will produce a single timestamped debug line with continuations.
* Each DebugRow produces one line of output, with the two values.
*/
template < typename T, typename U >
struct DebugRow
{
public:
explicit DebugRow( const T& t, const U& u )
: first( t )
, second( u )
{
}
const T first;
const U second;
};
/**
* @brief List-oriented formatted logging.
*
* Use DebugList to produce multiple rows of output in a debugging
* statement. For instance,
* cDebug() << DebugList( QStringList() << "foo" << "bar" )
* will produce a single timestamped debug line with continuations.
* Each element of the list of strings will be logged on a separate line.
*/
/* TODO: Calamares 3.3, bump requirements to C++17, and rename
* this to DebugList, dropping the convenience-definition
* below. In C++17, class template argument deduction is
* added, so `DebugList( whatever )` determines the right
* type already (also for QStringList).
*/
template < typename T >
struct DebugListT
{
using list_t = QList< T >;
explicit DebugListT( const list_t& l )
: list( l )
{
}
const list_t& list;
};
///@brief Convenience for QStringList, needs no template parameters
struct DebugList : public DebugListT< QString >
{
explicit DebugList( const list_t& l )
: DebugListT( l )
{
}
};
/**
* @brief Map-oriented formatted logging.
*
* Use DebugMap to produce multiple rows of output in a debugging
* statement from a map. The output is intentionally a bit-yaml-ish.
* cDebug() << DebugMap( map )
* will produce a single timestamped debug line with continuations.
* The continued lines will have a key (from the map) and a value
* on each line.
*/
struct DebugMap
{
public:
explicit DebugMap( const QVariantMap& m )
: map( m )
{
}
const QVariantMap& map;
};
/** @brief When logging commands, don't log everything.
*
* The command-line arguments to some commands may contain the
* encrypted password set by the user. Don't log that password,
* since the log may get posted to bug reports, or stored in
* the target system.
*/
struct RedactedCommand
{
RedactedCommand( const QStringList& l )
: list( l )
{
}
const QStringList& list;
};
DLLEXPORT QDebug& operator<<( QDebug& s, const RedactedCommand& l );
/** @brief When logging "private" identifiers, keep them consistent but private
*
* Send a string to a logger in such a way that each time it is logged,
* it logs the same way, but without revealing the actual contents.
* This can be applied to user names, UUIDs, etc.
*/
struct DLLEXPORT RedactedName
{
RedactedName( const char* context, const QString& s );
RedactedName( const QString& context, const QString& s );
operator QString() const;
private:
const uint m_id;
const QString m_context;
};
inline QDebug&
operator<<( QDebug& s, const RedactedName& n )
{
return s << NoQuote << QString( n ) << Quote;
}
/**
* @brief Formatted logging of a pointer
*
* Pointers are printed as void-pointer, so just an address (unlike, say,
* QObject pointers which show an address and some metadata) preceded
* by an '@'. This avoids C-style (void*) casts in the code.
*
* Shared pointers are indicated by 'S@' and unique pointers by 'U@'.
*/
struct Pointer
{
public:
explicit Pointer( const void* p )
: ptr( p )
, kind( 0 )
{
}
template < typename T >
explicit Pointer( const std::shared_ptr< T >& p )
: ptr( p.get() )
, kind( 'S' )
{
}
template < typename T >
explicit Pointer( const std::unique_ptr< T >& p )
: ptr( p.get() )
, kind( 'U' )
{
}
const void* const ptr;
const char kind;
};
/** @brief output operator for DebugRow */
template < typename T, typename U >
inline QDebug&
operator<<( QDebug& s, const DebugRow< T, U >& t )
{
s << Continuation << t.first << ':' << ' ' << t.second;
return s;
}
/** @brief output operator for DebugList, assuming operator<< for T exists */
template < typename T = QString >
inline QDebug&
operator<<( QDebug& s, const DebugListT< T >& c )
{
for ( const auto& i : c.list )
{
s << Continuation << i;
}
return s;
}
/** @brief supporting method for outputting a DebugMap */
DLLEXPORT QString toString( const QVariant& v );
/** @brief output operator for DebugMap */
inline QDebug&
operator<<( QDebug& s, const DebugMap& t )
{
for ( auto it = t.map.constBegin(); it != t.map.constEnd(); ++it )
{
s << Continuation << it.key().toUtf8().constData() << ':' << ' ' << toString( it.value() ).toUtf8().constData();
}
return s;
}
inline QDebug&
operator<<( QDebug& s, const Pointer& p )
{
s << NoQuote;
if ( p.kind )
{
s << p.kind;
}
s << '@' << p.ptr << Quote;
return s;
}
/** @brief Convenience object for supplying SubEntry to a debug stream
*
* In a function with convoluted control paths, it may be unclear
* when to supply SubEntry to a debug stream -- it is convenient
* for the **first** debug statement from a given function to print
* the function header, and all subsequent onces to get SubEntry.
*
* Create an object of type Once and send it (first) to all CDebug
* objects; this will print the function header only once within the
* lifetime of that Once object.
*/
class Once
{
public:
Once()
: m( true )
{
}
friend CDebug& operator<<( CDebug&&, const Once& );
/** @brief Restore the object to "fresh" state
*
* It may be necessary to allow the Once object to stream the
* function header again -- for instance, after logging an error,
* any following debug log might want to re-introduce the header.
*/
void refresh() { m = true; }
/** @brief Is this object "fresh"?
*
* Once a Once-object has printed (once) it is no longer fresh.
*/
operator bool() const { return m; }
private:
mutable bool m = false;
};
inline CDebug&
operator<<( CDebug&& s, const Once& o )
{
if ( !logLevelEnabled( s.level() ) )
{
// This won't print, so it's not using the "onceness"
return s;
}
if ( o.m )
{
o.m = false;
return s;
}
s.m_funcinfo = nullptr;
s << SubEntry;
return s;
}
} // namespace Logger
#define cVerbose() Logger::CDebug( Logger::LOGVERBOSE, Q_FUNC_INFO )
#define cDebug() Logger::CDebug( Logger::LOGDEBUG, Q_FUNC_INFO )
#define cWarning() Logger::CDebug( Logger::LOGWARNING, Q_FUNC_INFO )
#define cError() Logger::CDebug( Logger::LOGERROR, Q_FUNC_INFO )
#endif

View File

@@ -0,0 +1,263 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Collabora Ltd <arnaud.ferraris@collabora.com>
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
/** @brief Support for "named" enumerations
*
* When a string needs to be one specific string out of a set of
* alternatives -- one "name" from an enumerated set -- then it
* is useful to have an **enum type** for the enumeration so that
* C++ code can work with the (strong) type of the enum, while
* the string can be used for human-readable interaction.
* The `NamedEnumTable<E>` template provides support for naming
* values of an enum.
*/
#ifndef UTILS_NAMEDENUM_H
#define UTILS_NAMEDENUM_H
#include <QString>
#include <initializer_list>
#include <type_traits>
#include <vector>
/** @brief Type for collecting parts of a named enum.
*
* The `NamedEnumTable<E>` template provides support for naming
* values of an enum. It supports mapping strings to enum values
* and mapping enum values to strings.
*
* ## Example
*
* Suppose we have code where there are three alternatives; it is
* useful to have a strong type to make the alternatives visible
* in that code, so the compiler can help check:
*
* ```
* enum class MilkshakeSize { None, Small, Large };
* ```
*
* In a switch() statement, the compiler will check that all kinds
* of milkshakes are dealt with; we can pass a MilkshakeSize to
* a function and rest assured that nobody will call that function
* with a silly value, like `1`.
*
* There is no relation between the C++ identifiers used, and
* any I/O related to that enumeration. In other words,
*
* ```
* std::cout << MilkshakeSize::Small;
* ```
*
* Will **not** print out "Small", or "small", or 1. It won't even
* compile, because there is no mapping of the enum values to
* something that can be output.
*
* By making a `NamedEnumTable<MilkshakeSize>` we can define a mapping
* between strings (names) and enum values, so that we can easily
* output the human-readable name, and also take string input
* and convert it to an enum value. Suppose we have a function
* `milkshakeSizeNames()` that returns a reference to such a table,
* then we can use `find()` to map enums-to-names and names-to-enums.
*
* ```
* const auto& names = milkshakeSizeNames();
* MilkshakeSize sz{ MilkshakeSize::Large };
* std::cout << names.find(sz); // Probably "large"
*
* bool ok;
* sz = names.find( "small", ok ); // Probably MilkshakeSize::Small
* ```
*
* ## Usage
*
* It is recommended to use a static const declaration for the table;
* typical use will define a function that returns a reference to
* the table, for shared use.
*
* The constructor for a table takes an initializer_list; each element
* of the initializer_list is a **pair** consisting of a name and
* an associated enum value. The names should be QStrings. For each enum
* value that is listed, the canonical name should come **first** in the
* table, so that printing the enum values gives the canonical result.
*
* ```
* static const NamedEnumTable<MilkshakeSize>& milkshakeSizeNames()
* {
* static NamedEnumTable<MilkshakeSize> n { // Initializer list for n
* { "large", MilkshakeSize::Large }, // One pair of name-and-value
* { "small", MilkshakeSize::Small },
* { "big", MilkshakeSize::Large }
* };
* return n;
* }
* ```
*
* The function `eNames()`, above, returns a reference to a name table
* for the enum (presumably an enum class) `E`. It is possible to have
* more than one table for an enum, or to make the table locally,
* but **usually** you want one definitive table of names and values.
* The `eNames()` function gives you that definitive table. In Calamres
* code, such functions are usually named after the underlying enum.
*
* Using this particular table, looking up "large" will return `MilkshakeSize::Large`,
* looking up "big" will **also** return `MilkshakeSize::Large`, looking up "derp"
* will return `MilkshakeSize::Large` (because that is the first value in the table)
* but will set the boolean `ok` parameter to false. Conversely, looking
* up `MilkshakeSize::Large` will return "large" (never "big").
*
* Note that this particular table does **not** name MilkshakeSize::None,
* so it is probably wrong: you can't get a string for that enum
* value, and no string will map to MilkshakeSize::None either.
* In general, tables should cover all of the enum values.
*
* Passing an empty initializer_list to the constructor is supported,
* but will cause UB if the table is ever used for looking up a string.
*
*/
template < typename T >
struct NamedEnumTable
{
using string_t = QString;
using enum_t = T;
using pair_t = std::pair< string_t, enum_t >;
using type = std::vector< pair_t >;
type table;
/** @brief Create a table of named enum values.
*
* Use braced-initialisation for NamedEnum, and remember that the
* elements of the list are **pairs**, e.g.
*
* ```
* static const NamedEnumTable<Colors> c{ {"red", Colors::Red } };
* ```
*/
NamedEnumTable( const std::initializer_list< pair_t >& v )
: table( v )
{
/* static_assert( v.size() > 0 ); */
}
/** @brief Find a name @p s in the table.
*
* Searches case-insensitively.
*
* If the name @p s is not found, @p ok is set to @c false and
* the first enum value in the table is returned. Otherwise,
* @p ok is set to @c true and the corresponding value is returned.
* Use the output value of @p ok to determine if the lookup was
* successful: there is otherwise no sensible way to distinguish
* found-the-name-of-the-first-item from not-found.
*/
enum_t find( const string_t& s, bool& ok ) const
{
ok = false;
for ( const auto& p : table )
{
if ( 0 == QString::compare( s, p.first, Qt::CaseInsensitive ) )
{
ok = true;
return p.second;
}
}
// ok is still false
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
* name (the first name with that value, if there are aliases)
* and set @p ok to @c true.
*
* If the value @p s is not found, @p ok is set to @c false and
* an empty string is returned. This indicates that the table does
* not cover all of the values * in `enum_t` (and @p s is one
* of them), **or** that the passed-in value of @p s is
* not a legal value, e.g. via a static_cast<enum_t>.
*/
string_t find( enum_t s, bool& ok ) const
{
ok = false;
for ( const auto& p : table )
{
if ( s == p.second )
{
ok = true;
return p.first;
}
}
// ok is still false
return string_t();
}
/** @brief Find a value @p s in the table and return its name.
*
* Returns an empty string if the value @p s is not found (this
* indicates that the table does not cover all of the values
* in `enum_t`, **or** that the passed-in value of @p s is
* not a legal value, e.g. via a static_cast<enum_t>).
*/
string_t find( enum_t s ) const
{
bool ok = false;
return find( s, ok );
}
};
/** @brief Smashes an enum value to its underlying type.
*
* While an enum **class** is not an integral type, and its values can't be
* printed or treated like an integer (like an old-style enum can),
* the underlying type **is** integral. This template function
* returns the value of an enum value, in its underlying type.
* This can be useful for debugging purposes, e.g.
*
* ```
* MilkshakeSize sz{ MilkshakeSize::None };
* std::cout << milkshakeSizeNames().find( sz ) << smash( sz );
* ```
*
* This will print both the name and the underlying integer for the
* value; assuming the table from the example is used, there is
* no name for MilkshakeSize::None, so it will print an empty string,
* followed by the integral representation -- probably a 0.
*/
template < typename E >
constexpr typename std::underlying_type< E >::type
smash( const E e )
{
return static_cast< typename std::underlying_type< E >::type >( e );
}
#endif

View File

@@ -0,0 +1,100 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
/** @brief Support for unit-suffixed values.
*
* This combines a value with an (enum) unit indicating what kind
* of value it is, e.g. 10 meters, or 64 pixels. Includes simple
* parsing support for the values written as strings like <value><unit>,
* e.g. "10m" or "64px".
*
* When a suffixed unit value needs validation, define an isValid()
* method; similarly for simple construction from a string (with a fixed
* table of suffixes). Typical use then looks like:
*
* class MyUnit : public NamedSuffix<MyUnitEnum, MyUnitEnum::None>
* {
* public:
* using NamedSuffix::NamedSuffix; // Keep existing constructors
* MyUnit( const QString& s );
* bool isValid() const;
* } ;
*/
#ifndef UTILS_NAMEDSUFFIX_H
#define UTILS_NAMEDSUFFIX_H
#include "NamedEnum.h"
/** @brief Template that takes the enum type to work with and a special none-enum. */
template < typename T, T _none >
class NamedSuffix
{
public:
using unit_t = T;
static constexpr unit_t none = _none;
/** @brief Empty value. */
NamedSuffix()
: m_value( 0 )
, m_unit( none )
{
}
/** @brief Specific value and unit. */
NamedSuffix( qint64 value, unit_t unit )
: m_value( value )
, m_unit( unit )
{
}
/** @brief Construct value and unit from string.
*
* This parses the given string @p s by comparing with the suffixes
* in @p table and uses the first matching suffix as the unit.
*/
NamedSuffix( const NamedEnumTable< T >& table, const QString& s )
: NamedSuffix()
{
for ( const auto& suffix : table.table )
{
if ( s.endsWith( suffix.first ) )
{
m_value = s.left( s.length() - suffix.first.length() ).toLongLong();
m_unit = suffix.second;
break;
}
}
}
/** @brief Construct value from string.
*
* This is not defined in the template, because it should probably
* delegate to the constructor above with a fixed table.
*/
NamedSuffix( const QString& s );
qint64 value() const { return m_value; }
unit_t unit() const { return m_unit; }
/** @brief Check that a value-unit combination is valid.
*
* This is not defined in the template, because validity (e.g.
* range of acceptable values) depends on the kind of unit.
*/
bool isValid() const;
protected:
qint64 m_value;
unit_t m_unit;
};
#endif

View File

@@ -0,0 +1,46 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Bill Auger
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef UTILS_PASTE_H
#define UTILS_PASTE_H
#include "DllMacro.h"
#include <QString>
class QObject;
class QWidget;
namespace Calamares
{
namespace Paste
{
/** @brief Send the current log file to a pastebin
*
* Returns the (string) URL that the pastebin gives us.
*/
UIDLLEXPORT QString doLogUpload( QObject* parent );
/** @brief Send the current log file to a pastebin
*
* As doLogUpload(), but also sets the clipboard and displays
* a message saying it's been done.
*/
UIDLLEXPORT QString doLogUploadUI( QWidget* parent );
/** @brief Is paste enabled?
*
* Checks the branding instance if paste can be done.
*/
UIDLLEXPORT bool isEnabled();
} // namespace Paste
} // namespace Calamares
#endif

View File

@@ -0,0 +1,113 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2018 Scott Harvey <scott@spharvey.me>
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#ifndef LIBCALAMARES_PERMISSIONS_H
#define LIBCALAMARES_PERMISSIONS_H
#include "DllMacro.h"
#include <QString>
namespace Calamares
{
/**
* @brief Represents a <user>:<group>:<file-mode>
*
* The Permissions class takes a QString @p in the form of
* <user>:<group>:<file-mode>, checks it for validity, and makes the three
* components available indivdually.
*/
class DLLEXPORT Permissions
{
public:
/** @brief Constructor
*
* Splits the string @p at the colon (":") into separate elements for
* <user>, <group>, and <file-mode> (permissions), where <file-mode> is any
* value that can be parsed by parseFileMode() . One valid form
* is an **octal** integer. That is, "root:wheel:755" will give
* you an integer value of four-hundred-ninety-three (493),
* corresponding to the UNIX file permissions rwxr-xr-x,
* as one would expect from chmod and other command-line utilities.
*/
Permissions( QString const& p );
/// @brief Default constructor of an invalid Permissions.
Permissions();
/// @brief Was the Permissions object constructed from valid data?
bool isValid() const { return m_valid; }
/// @brief The user (first component, e.g. "root" in "root:wheel:755")
QString username() const { return m_username; }
/// @brief The group (second component, e.g. "wheel" in "root:wheel:755")
QString group() const { return m_group; }
/** @brief The value (file permission) as an integer.
*
* Bear in mind that input is in octal, but integers are just integers;
* naively printing them will get decimal results (e.g. 493 from the
* input of "root:wheel:755"). This is suitable to pass to apply().
*/
int value() const { return m_value; }
/** @brief The value (file permission) as octal string
*
* This is suitable for passing to chmod-the-program, or for
* recreating the original Permissions string.
*/
QString octal() const { return QString::number( value(), 8 ); }
/** @brief Sets the file-access @p mode of @p path
*
* Pass a path that is relative (or absolute) in the **host** system.
*
* @return @c true on success
*/
static bool apply( const QString& path, int mode );
/** @brief Do both chmod and chown on @p path
*
* Note that interpreting user- and group- names for applying the
* permissions can be different between the host system and the target
* system; the target might not have a "live" user, for instance, and
* the host won't have the user-entered username for the installation.
*
* For this call, the names are interpreted in the **host** system.
* Pass a path that is relative (or absolute) in the **host** system.
*
* @return @c true on success of **both** operations
*/
static bool apply( const QString& path, const Permissions& p );
/// Convenience method for apply(const QString&, const Permissions& )
bool apply( const QString& path ) const { return apply( path, *this ); }
private:
void parsePermissions( QString const& p );
QString m_username;
QString m_group;
int m_value;
bool m_valid;
};
/**
* @brief Parses a file-mode and returns it as an integer
*
* Returns -1 on error.
*
* Valid forms of @p mode are:
* - octal representation, with an optional leading 0 and at most three
* octal digits (e.g. 0755 or 644).
* - octal representation with a leading 'o' (letter) and at most three
* octal digits (e.g. o755 or o644). Use this in YAML where a string
* of digits would otherwise be interpreted as a (base-10) integer.
* - "rwx" representation with exactly 9 characters like the output of ls.
*/
DLLEXPORT int parseFileMode( const QString& mode );
} // namespace Calamares
#endif // LIBCALAMARES_PERMISSIONS_H

View File

@@ -0,0 +1,113 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_PLUGINFACTORY_H
#define UTILS_PLUGINFACTORY_H
#include "DllMacro.h"
#include <QObject>
#define CalamaresPluginFactory_iid "io.calamares.PluginFactory"
/** @brief Plugin factory for Calamares
*
* A Calamares plugin contains just one kind of plugin -- either
* a job, or a viewstep -- so the factory is straightforward.
* It gets a single CreateInstanceFunction and calls that;
* the function is set when registerPlugin() is called in a subclass.
*
*/
class DLLEXPORT CalamaresPluginFactory : public QObject
{
Q_OBJECT
public:
explicit CalamaresPluginFactory() {}
~CalamaresPluginFactory() override;
typedef QObject* ( *CreateInstanceFunction )( QObject* );
template < class T >
T* create( QObject* parent = nullptr )
{
auto* op = fn ? fn( parent ) : nullptr;
if ( !op )
{
return nullptr;
}
T* tp = qobject_cast< T* >( op );
if ( !tp )
{
delete op;
}
return tp;
}
protected:
CreateInstanceFunction fn = nullptr;
};
/** @brief declare a Calamares Plugin Factory
*
* There should be one declaration -- generally alongside the
* class definition for the Job or ViewStep that the plugin is
* going to provide, in the header -- and one definition -- in
* the corresponding implementation.
*/
#define CALAMARES_PLUGIN_FACTORY_DECLARATION( name ) \
class name : public CalamaresPluginFactory \
{ \
Q_OBJECT \
Q_INTERFACES( CalamaresPluginFactory ) \
Q_PLUGIN_METADATA( IID CalamaresPluginFactory_iid ) \
public: \
explicit name(); \
~name() override; \
template < class T > \
static QObject* createInstance( QObject* parent ) \
{ \
return new T( parent ); \
} \
template < class T > \
void registerPlugin() \
{ \
fn = createInstance< T >; \
} \
};
/** @brief Define a Calamares Plugin Factory
*
* This should be done exactly once, generally in the translation
* unit containing the definitions for the main class of the plugin,
* either the Job or the ViewStep definitions.
*
* The @p name must match the name used in the declaration, while
* @p pluginRegistrations should be a single call to `registerPlugin<T>()`
* where `T` is the type (subclass of Job or ViewStep) defined by the
* plugin, eg.
*
* ```
* CALAMARES_PLUGIN_FACTORY_DEFINITION( MyPlugin, registerPlugin<MyPluginJob>() )
* ```
*
* Leaving out the `()` will lead to generally-weird compiler warnings.
*/
#define CALAMARES_PLUGIN_FACTORY_DEFINITION( name, pluginRegistrations ) \
name::name() \
: CalamaresPluginFactory() \
{ \
pluginRegistrations; \
} \
name::~name() {}
Q_DECLARE_INTERFACE( CalamaresPluginFactory, CalamaresPluginFactory_iid )
#endif

View File

@@ -0,0 +1,90 @@
/* === 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 UTILS_QML_H
#define UTILS_QML_H
#include "DllMacro.h"
#include "modulesystem/InstanceKey.h"
#include "utils/NamedEnum.h"
#include <QDir>
class QQuickItem;
namespace Calamares
{
/// @brief the extra directory where Calamares searches for QML files
UIDLLEXPORT QDir qmlModulesDir();
/// @brief sets specific directory for searching for QML files
UIDLLEXPORT void setQmlModulesDir( const QDir& dir );
/** @brief initialize QML search path with branding directories
*
* Picks a suitable branding directory (from the build-dir in debug mode,
* otherwise based on the branding directory) and adds it to the
* QML modules directory; returns @c false if none is found.
*/
UIDLLEXPORT bool initQmlModulesDir();
/** @brief Sets up global Calamares models for QML
*
* This needs to be called at least once to make the global Calamares
* models (Branding, ViewManager, ...) available to QML.
*
* The following objects are made available globally:
* - `io.calamares.ui.Branding` (an object, see Branding.h)
* - `io.calamares.core.ViewManager` (a model, see ViewManager.h)
* - `io.calamares.core.Global` (an object, see GlobalStorage.h)
* Additionally, modules based on QmlViewStep have a context
* property `config` referring to that module's configuration (if any).
*/
UIDLLEXPORT void registerQmlModels();
/** @brief Calls the QML method @p method on @p qmlObject
*
* Pass in only the name of the method (e.g. onActivate). This function
* checks if the method exists (with no arguments) before trying to
* call it, so that no warnings are printed due to missing methods.
*
* If there is a return value from the QML method, it is logged (but not otherwise used).
*/
UIDLLEXPORT void callQmlFunction( QQuickItem* qmlObject, const char* method );
/** @brief Search modes for loading Qml files.
*
* A QML file could be compiled into QRC, or it could live
* in the branding directory (and, in debug-runs, in
* the current-directory). Modules have some control
* over where the search is done.
*/
enum class QmlSearch
{
QrcOnly,
BrandingOnly,
Both
};
/// @brief Names for the search terms (in config files)
UIDLLEXPORT const NamedEnumTable< QmlSearch >& qmlSearchNames();
/** @brief Find a suitable QML file, given the search method and name hints
*
* Returns QString() if nothing is found (which would mean the module
* is badly configured).
*/
UIDLLEXPORT QString searchQmlFile( QmlSearch method,
const QString& configuredName,
const Calamares::ModuleSystem::InstanceKey& i );
UIDLLEXPORT QString searchQmlFile( QmlSearch method, const QString& fileNameNoSuffix );
} // namespace Calamares
#endif

View File

@@ -0,0 +1,30 @@
/* === 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.
*
*/
/**@file Handle compatibility and deprecations across Qt versions
*
* Since Calamares is supposed to work with Qt 5.15 or Qt 6 or later, it
* covers a lot of changes in the Qt API.
*
* This file adjusts for that by introducing suitable aliases
* and workaround-functions.
*
* For a similar approach for QtCore, see libcalamares/utils/String.h
*/
#ifndef UTILS_QTCOMPAT_H
#define UTILS_QTCOMPAT_H
#include <QPalette>
/* Avoid warnings about QPalette changes */
constexpr static const auto WindowBackground = QPalette::Window;
constexpr static const auto WindowText = QPalette::WindowText;
#endif

View File

@@ -0,0 +1,112 @@
/* === 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 UTILS_RAII_H
#define UTILS_RAII_H
#include <QObject>
#include <QSignalBlocker>
#include <optional>
#include <type_traits>
/** @brief Convenience to zero out and deleteLater of any QObject-derived-class
*
* If, before destruction, preserve is set to @c true, then
* the object is "preserved", and not deleted at all.
*/
template < typename T >
struct cqDeleter
{
T*& p;
bool preserve = false;
~cqDeleter()
{
static_assert( std::is_base_of< QObject, T >::value, "Not a QObject-class" );
if ( !preserve )
{
if ( p )
{
p->deleteLater();
}
p = nullptr;
}
}
};
/// @brief Blocks signals on a QObject until destruction
using cSignalBlocker = QSignalBlocker;
/** @brief Writes a value on destruction to a pointed-to location.
*
* If the pointer is non-null, write the last-given-value if there
* is one to the pointed-to object. This is called the "then-value".
*
*/
template < typename T >
struct cScopedAssignment
{
std::optional< T > m_value;
T* m_pointer;
/** @brief Create a setter with no value set
*
* Until a value is set via operator=(), this pointer-setter
* will do nothing on destruction, leaving the pointed-to
* value unchanged.
*/
cScopedAssignment( T* p )
: m_pointer( p )
{
}
/** @brief Create a setter with a then-value already set
*
* This ensures that on destruction, the value @p v will be written;
* it is equivalent to assigning @p v immediately. The pointed-to
* value is **not** changed (until destruction).
*/
cScopedAssignment( T* p, T then )
: m_value( then )
, m_pointer( p )
{
}
/** @brief Create a setter with a then-value and assign a new value now
*
* As above, but also assign @p now to the thing pointed-to.
*/
cScopedAssignment( T* p, T now, T then )
: m_value( then )
, m_pointer( p )
{
if ( p )
{
*p = now;
}
}
~cScopedAssignment()
{
if ( m_pointer && m_value.has_value() )
{
*m_pointer = m_value.value();
}
}
const T& operator=( const T& then )
{
m_value = then;
return then;
}
};
template < typename T >
cScopedAssignment( T p ) -> cScopedAssignment< decltype( *p ) >;
#endif

View File

@@ -0,0 +1,145 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_RETRANSLATOR_H
#define UTILS_RETRANSLATOR_H
#include "DllMacro.h"
#include "locale/Translation.h"
#include <QObject>
#include <QString>
#include <functional>
class QEvent;
class QLocale;
class QTranslator;
namespace Calamares
{
/** @brief changes the application language.
* @param locale the new locale (names as defined by Calamares).
* @param brandingTranslationsPrefix the branding path prefix, from Calamares::Branding.
*/
DLLEXPORT void installTranslator( const Calamares::Locale::Translation::Id& locale,
const QString& brandingTranslationsPrefix );
/** @brief Initializes the translations with the current system settings
*/
DLLEXPORT void installTranslator();
/** @brief The name of the (locale of the) most recently installed translator
*
* May return something different from the locale.name() of the
* QLocale passed in, because Calamares will munge some names and
* may remap translations.
*/
DLLEXPORT Calamares::Locale::Translation::Id translatorLocaleName();
/** @brief Loads <prefix><locale> translations into the given @p translator
*
* This function is not intended for general use: it is for those special
* cases where modules need their own translator / translations for data
* that is locale to the module. Tries to load a .qm from "sensible"
* locations, which are the same ones that installTranslator() would use.
* Takes local-translations into account.
*
* Note that @p prefix should end with an underscore '_' -- this function
* does not introduce one by itself.
*
* @returns @c true on success
*/
DLLEXPORT bool
loadTranslator( const Calamares::Locale::Translation::Id& locale, const QString& prefix, QTranslator* translator );
/** @brief Set @p allow to true to load translations from current dir.
*
* If false, (or never called) the translations are loaded only from
* system locations (the AppData dir) and from QRC (compiled in).
* Enable local translations to test translations stored in the
* current directory.
*/
DLLEXPORT void setAllowLocalTranslation( bool allow );
/** @brief Handles change-of-language events
*
* There is one single Retranslator object. Use `instance()` to get it.
* The top-level widget of the application should call
* `installEventFilter( Retranslator::instance() )`
* to set up event-handling for translation events. The Retranslator
* will emit signal `languageChanged()` if there is such an event.
*
* Normal consumers should not have to use the Retranslator directly,
* but use the macros `CALAMARES_RETRANSLATE*` to set things up
* in code -- the macros will connect to the Retranslator's signals.
*/
class DLLEXPORT Retranslator : public QObject
{
Q_OBJECT
public:
/// @brief Gets the global (single) Retranslator object
static Retranslator* instance();
/// @brief Helper function for attaching lambdas
static void attach( QObject* o, std::function< void( void ) > f );
signals:
void languageChanged();
protected:
bool eventFilter( QObject* obj, QEvent* e ) override;
private:
explicit Retranslator( QObject* parent );
};
} // namespace Calamares
/** @brief Call code for this object when language changes
*
* @p body should be a code block (it does not need braces) that can be wrapped
* up as a lambda. When the language changes, the lambda is called. Note that
* this macro should be used in constructors or other code that is run only
* once, since otherwise you will end up with multiple calls to @p body.
*
* NOTE: unlike plain QObject::connect(), the body is **also** called
* immediately after setting up the connection. This allows
* setup and translation code to be mixed together.
*/
#define CALAMARES_RETRANSLATE( body ) Calamares::Retranslator::attach( this, [ = ] { body } )
/** @brief Call code for the given object (widget) when language changes
*
* This is identical to CALAMARES_RETRANSLATE, except the @p body is called
* for the given object, not this object.
*
* NOTE: unlike plain QObject::connect(), the body is **also** called
* immediately after setting up the connection. This allows
* setup and translation code to be mixed together.
*/
#define CALAMARES_RETRANSLATE_FOR( object, body ) Calamares::Retranslator::attach( object, [ = ] { body } )
/** @brief Call a slot in this object when language changes
*
* Given a slot (in method-function-pointer notation), call that slot when the
* language changes. This is shorthand for connecting the Retranslator's
* signal to the given slot.
*
* NOTE: unlike plain QObject::connect(), the slot is **also** called
* immediately after setting up the connection. This allows
* setup and translation code to be mixed together.
*/
#define CALAMARES_RETRANSLATE_SLOT( slotfunc ) \
do \
{ \
connect( Calamares::Retranslator::instance(), &Calamares::Retranslator::languageChanged, this, slotfunc ); \
( this->*slotfunc )(); \
} while ( false )
#endif

View File

@@ -0,0 +1,135 @@
/* === 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 UTILS_RUNNER_H
#define UTILS_RUNNER_H
#include "System.h"
#include <QDir>
#include <QObject>
#include <QStringList>
#include <chrono>
#include <memory>
#include <optional>
namespace Calamares
{
namespace Utils
{
using RunLocation = Calamares::System::RunLocation;
using ProcessResult = Calamares::ProcessResult;
/** @brief A Runner wraps a process and handles running it and processing output
*
* This is basically a QProcess, but handles both running in the
* host system (through env(1)) or in the target (by calling chroot(8)).
* It has an output signal that handles output one line at a time
* (unlike QProcess that lets you do the buffering yourself).
* This output processing is only enabled if you do so explicitly.
*
* Use the set*() methods to configure the runner.
*
* If you call enableOutputProcessing(), then you can connect to
* the output() signal to receive each line (including trailing newline!).
*
* Processes are always run with LC_ALL and LANG set to "C".
*/
class DLLEXPORT Runner : public QObject
{
Q_OBJECT
public:
/** @brief Create an empty runner
*
* This is a runner with no commands, nothing; call set*() methods
* to configure it.
*/
Runner();
/** @brief Create a runner with a specified command
*
* Equivalent to Calamares::Utils::Runner::Runner() followed by
* calling setCommand().
*/
Runner( const QStringList& command );
virtual ~Runner() override;
Runner& setCommand( const QStringList& command )
{
m_command = command;
return *this;
}
Runner& setLocation( RunLocation r )
{
m_location = r;
return *this;
}
Runner& setWorkingDirectory( const QDir& directory )
{
m_directory = directory.absolutePath();
return *this;
}
Runner& setWorkingDirectory( const QString& directory )
{
m_directory = directory;
return *this;
}
Runner& setTimeout( std::chrono::seconds timeout )
{
m_timeout = timeout;
return *this;
}
Runner& setInput( const QString& input )
{
m_input = input;
return *this;
}
Runner& setOutputProcessing( bool enable )
{
m_output = enable;
return *this;
}
Runner& enableOutputProcessing()
{
m_output = true;
return *this;
}
ProcessResult run();
/** @brief The executable (argv[0]) that this runner will run
*
* This is the first element of the command; it does not include
* env(1) or chroot(8) which are injected when actually running
* the command.
*/
QString executable() const { return m_command.isEmpty() ? QString() : m_command.first(); }
signals:
void output( QString line );
private:
// What to run, and where.
QStringList m_command;
QString m_directory;
RunLocation m_location { RunLocation::RunInHost };
// Settings for when it actually runs
QString m_input;
std::chrono::milliseconds m_timeout { 0 };
bool m_output = false;
};
} // namespace Utils
} // namespace Calamares
#endif

View File

@@ -0,0 +1,112 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2013-2016 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Originally from Tomahawk, portions:
* SPDX-FileCopyrightText: 2010-2011 Christian Muehlhaeuser <muesli@tomahawk-player.org>
* SPDX-FileCopyrightText: 2010-2011 Leo Franchi <lfranchi@kde.org>
* SPDX-FileCopyrightText: 2010-2012 Jeff Mitchell <jeff@tomahawk-player.org>
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_STRING_H
#define UTILS_STRING_H
#include "DllMacro.h"
#include <QString>
/* Qt 5.14 changed the API to QString::split(), adding new overloads
* that take a different enum, then Qt 5.15 deprecated the old ones.
* To avoid overly-many warnings related to the API change, introduce
* Calamares-specific constants that pull from the correct enum.
*/
constexpr static const auto SplitSkipEmptyParts = Qt::SkipEmptyParts;
constexpr static const auto SplitKeepEmptyParts = Qt::KeepEmptyParts;
namespace Calamares
{
/**
* @brief The Calamares::String namespace
*
* This namespace contains functions related to string-handling,
* string-expansion, etc.
*/
namespace String
{
/**
* @brief removeDiacritics replaces letters with diacritics and ligatures with
* alternative forms and digraphs.
* @param string the string to transform.
* @return the output string with plain characters.
*/
DLLEXPORT QString removeDiacritics( const QString& string );
/**
* @brief obscure is a bidirectional obfuscation function, from KStringHandler.
* @param string the input string.
* @return the obfuscated string.
*/
DLLEXPORT QString obscure( const QString& string );
/** @brief Parameter for counting lines at beginning and end of string
*
* This is used by truncateMultiLine() to indicate how many lines from
* the beginning and how many from the end should be kept.
*/
struct LinesStartEnd
{
int atStart = 0;
int atEnd = 0;
};
/** @brief Parameter for counting characters in truncateMultiLine()
*/
struct CharCount
{
int total = 0;
};
/** @brief Truncate a string to some reasonable length for display
*
* Keep the first few, or last few (or both) lines of a possibly lengthy
* message @p string and reduce it to a displayable size (e.g. for
* pop-up windows that display the message). If the message is longer
* than @p chars, then characters are removed from the front (if
* @p lines.atStart is zero) or end (if @p lines.atEnd is zero) or in the middle
* (if both are nonzero).
*
* Asking for 0 lines will make this behave like QString::truncate().
*
* @param string the input string.
* @param lines number of lines to preserve.
* @param chars maximum number of characters in the returned string.
* @return a string built from parts of the input string.
*/
DLLEXPORT QString truncateMultiLine( const QString& string,
LinesStartEnd lines = LinesStartEnd { 3, 5 },
CharCount chars = CharCount { 812 } );
/** @brief Remove all @p c at the beginning of @p string
*
* Modifies the @p string in-place. If @p c is not the first character
* of @p string, the string is left unchanged; otherwise the first character
* is removed and the process repeats.
*/
DLLEXPORT void removeLeading( QString& string, QChar c );
/** @brief Remove all @p c at the end of @p string
*
* Like removeLeading(), but at the end of the string.
*/
DLLEXPORT void removeTrailing( QString& string, QChar c );
} // namespace String
} // namespace Calamares
#endif

View File

@@ -0,0 +1,77 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2022 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_STRINGEXPANDER_H
#define UTILS_STRINGEXPANDER_H
#include "DllMacro.h"
#include <KMacroExpander>
#include <QString>
#include <QStringList>
#include <memory>
namespace Calamares
{
namespace String
{
/** @brief Expand variables in a string against a dictionary.
*
* This class provides a convenience API for building up a dictionary
* and using it to expand strings. Use the `expand()` method to
* do standard word-based expansion with `$` as macro-symbol.
*
* Unlike straight-up `KMacroExpander::expandMacros()`, this
* provides an API to find out which variables were missing
* from the dictionary during expansion. Use `hasErrors()` and
* `errorNames()` to find out which variables those were.
*
* Call `clearErrors()` to reset the stored errors. Calling
* `expand()` implicitly clears the errors before starting
* a new expansion, as well.
*/
class DLLEXPORT DictionaryExpander : public KWordMacroExpander
{
public:
DictionaryExpander();
DictionaryExpander( DictionaryExpander&& );
virtual ~DictionaryExpander() override;
void insert( const QString& key, const QString& value );
/** @brief As insert(), but supports method-chaining.
*
*/
DictionaryExpander& add( const QString& key, const QString& value )
{
insert( key, value );
return *this;
}
void clearErrors();
bool hasErrors() const;
QStringList errorNames() const;
QString expand( QString s );
protected:
virtual bool expandMacro( const QString& str, QStringList& ret ) override;
private:
struct Private;
std::unique_ptr< Private > d;
};
} // namespace String
} // namespace Calamares
#endif

View File

@@ -0,0 +1,365 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-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 UTILS_CALAMARESUTILSSYSTEM_H
#define UTILS_CALAMARESUTILSSYSTEM_H
#include "DllMacro.h"
#include "Job.h"
#include <QObject>
#include <QPair>
#include <QString>
#include <chrono>
namespace Calamares
{
class ProcessResult : public QPair< int, QString >
{
public:
enum class Code : int
{
Crashed = -1, // Must match special return values from QProcess
FailedToStart = -2, // Must match special return values from QProcess
NoWorkingDirectory = -3,
TimedOut = -4
};
/** @brief Implicit one-argument constructor has no output, only a return code */
ProcessResult( Code r )
: QPair< int, QString >( static_cast< int >( r ), QString() )
{
}
ProcessResult( int r, QString s )
: QPair< int, QString >( r, s )
{
}
int getExitCode() const { return first; }
QString getOutput() const { return second; }
/** @brief Explain a typical external process failure.
*
* @param errorCode Return code from runCommand() or similar
* (negative values get special explanation). The member
* function uses the exit code stored in the ProcessResult
* @param output (error) output from the command, used when there is
* an error to report (exit code > 0). The member
* function uses the output stored in the ProcessResult.
* @param command String or split-up string of the command
* that was invoked.
* @param timeout Timeout passed to the process runner, for explaining
* error code -4 (timeout).
*/
static DLLEXPORT Calamares::JobResult
explainProcess( int errorCode, const QString& command, const QString& output, std::chrono::seconds timeout );
/// @brief Convenience wrapper for explainProcess()
inline Calamares::JobResult explainProcess( const QString& command, std::chrono::seconds timeout ) const
{
return explainProcess( getExitCode(), command, getOutput(), timeout );
}
/// @brief Convenience wrapper for explainProcess()
inline Calamares::JobResult explainProcess( const QStringList& command, std::chrono::seconds timeout ) const
{
return explainProcess( getExitCode(), command.join( ' ' ), getOutput(), timeout );
}
};
/** @brief The result of a create*() action, for status
*
* A CreationResult has a status field, can be converted to bool
* (true only on success) and can report the full pathname of
* the thing created if it was successful.
*/
class CreationResult : public QPair< int, QString >
{
public:
enum class Code : int
{
// These are "not failed", but only OK is a success
OK = 0,
AlreadyExists = 1,
// These are "failed"
Invalid = -1,
Failed = -2
};
CreationResult( Code r )
: QPair< int, QString >( static_cast< int >( r ), QString() )
{
}
explicit CreationResult( const QString& path )
: QPair< int, QString >( 0, path )
{
}
Code code() const { return static_cast< Code >( first ); }
QString path() const { return second; }
bool failed() const { return first < 0; }
operator bool() const { return first == 0; }
};
/**
* @brief The System class is a singleton with utility functions that perform
* system-specific operations.
*/
class DLLEXPORT System : public QObject
{
Q_OBJECT
public:
/**
* @brief System the constructor. Only call this once in a Calamares instance.
* @param doChroot set to true if all external commands should run in the
* target system chroot, otherwise false to run everything on the current system.
* @param parent the QObject parent.
*/
explicit System( bool doChroot, QObject* parent = nullptr );
~System() override;
static System* instance();
/** (Typed) Boolean describing where a particular command should be run,
* whether in the host (live) system or in the (chroot) target system.
*/
enum class RunLocation
{
RunInHost,
RunInTarget
};
/** @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).
* @param stdInput the input string to send to the running process as
* standard input (optional).
* @param timeoutSec the timeout after which the process will be
* killed (optional, default is 0 i.e. no timeout).
*
* @returns the program's exit code and its output (if any). Special
* exit codes (which will never have any output) are:
* Crashed = QProcess crash
* FailedToStart = QProcess cannot start
* NoWorkingDirectory = bad arguments
* TimedOut = QProcess timeout
*/
static DLLEXPORT ProcessResult runCommand( RunLocation location,
const QStringList& args,
const QString& workingPath = QString(),
const QString& stdInput = QString(),
std::chrono::seconds timeoutSec = std::chrono::seconds( 0 ) );
/** @brief Convenience wrapper for runCommand() in the host
*
* 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 )
{
return runCommand( RunLocation::RunInHost, args, QString(), QString(), timeoutSec );
}
/** @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.
*/
inline ProcessResult targetEnvCommand( const QStringList& args,
const QString& workingPath = QString(),
const QString& stdInput = QString(),
std::chrono::seconds timeoutSec = std::chrono::seconds( 0 ) )
{
return runCommand(
m_doChroot ? RunLocation::RunInTarget : RunLocation::RunInHost, args, workingPath, stdInput, timeoutSec );
}
/** @brief Convenience wrapper for targetEnvCommand() which returns only the exit code */
inline int targetEnvCall( const QStringList& args,
const QString& workingPath = QString(),
const QString& stdInput = QString(),
std::chrono::seconds timeoutSec = std::chrono::seconds( 0 ) )
{
return targetEnvCommand( args, workingPath, stdInput, timeoutSec ).first;
}
/** @brief Convenience wrapper for targetEnvCommand() which returns only the exit code */
inline int targetEnvCall( const QString& command,
const QString& workingPath = QString(),
const QString& stdInput = QString(),
std::chrono::seconds timeoutSec = std::chrono::seconds( 0 ) )
{
return targetEnvCall( QStringList { command }, workingPath, stdInput, timeoutSec );
}
/** @brief Convenience wrapper for targetEnvCommand() which returns only the exit code
*
* Places the called program's output in the @p output string.
*/
int targetEnvOutput( const QStringList& args,
QString& output,
const QString& workingPath = QString(),
const QString& stdInput = QString(),
std::chrono::seconds timeoutSec = std::chrono::seconds( 0 ) )
{
auto r = targetEnvCommand( args, workingPath, stdInput, timeoutSec );
output = r.second;
return r.first;
}
/** @brief Convenience wrapper for targetEnvCommand() which returns only the exit code
*
* Places the called program's output in the @p output string.
*/
inline int targetEnvOutput( const QString& command,
QString& output,
const QString& workingPath = QString(),
const QString& stdInput = QString(),
std::chrono::seconds timeoutSec = std::chrono::seconds( 0 ) )
{
return targetEnvOutput( QStringList { command }, output, workingPath, stdInput, timeoutSec );
}
/** @brief Gets a path to a file in the target system, from the host.
*
* @param path Path to the file; this is interpreted
* from the root of the target system (whatever that may be,
* but / in the chroot, or / in OEM modes).
*
* @return The complete path to the target file, from
* the root of the host system, or empty on failure.
*
* For instance, during installation where the target root is
* mounted on /tmp/calamares-something, asking for targetPath("/etc/passwd")
* will give you /tmp/calamares-something/etc/passwd.
*
* No attempt is made to canonicalize anything, since paths might not exist.
*/
DLLEXPORT QString targetPath( const QString& path ) const;
enum class WriteMode
{
KeepExisting,
Overwrite
};
/** @brief Create a (small-ish) file in the target system.
*
* @param path Path to the file; this is interpreted
* from the root of the target system (whatever that may be,
* but / in the chroot, or / in OEM modes).
* @param contents Actual content of the file.
*
* If the target already exists:
* - returns AlreadyExists as a result (and does not overwrite),
* - **unless** @p mode is set to Overwrite, then it tries writing as
* usual and will not return AlreadyExists.
*
* @return The complete canonical path to the target file from the
* root of the host system, or empty on failure. (Here, it is
* possible to be canonical because the file exists).
*/
DLLEXPORT CreationResult createTargetFile( const QString& path,
const QByteArray& contents,
WriteMode mode = WriteMode::KeepExisting ) const;
/** @brief Remove a file from the target system.
*
* @param path Path to the file; this is interpreted from the root
* of the target system (@see targetPath()).
*
* Does no error checking to see if the target file was really removed.
*/
DLLEXPORT void removeTargetFile( const QString& path ) const;
/** @brief Reads a file from the target system.
*
* @param path Path to the file; this is interpreted from the root of
* the target system (@see targetPath()).
*
* Does no error checking, and returns an empty list if the file does
* not exist.
*
* NOTE: This function is now basically the same as QFile::readAll(),
* splitting into lines, but Calamares may need to change
* permissions or raise privileges to actually read the file,
* which is why there is an API.
*
* NOTE: Since this buffers the whole file in memory, reading big files
* is not recommended.
*/
DLLEXPORT QStringList readTargetFile( const QString& path ) const;
/** @brief Ensure that the directory @p path exists
*
* @param path a full pathname to a desired directory.
*
* All the directory components including the last path component are
* created, as needed. Returns true on success.
*
* @see QDir::mkpath
*/
DLLEXPORT bool createTargetDirs( const QString& path ) const;
/** @brief Convenience to create parent directories of a file path.
*
* Creates all the parent directories until the last
* component of @p filePath . @see createTargetDirs()
*/
DLLEXPORT bool createTargetParentDirs( const QString& filePath ) const;
/**
* @brief getTotalMemoryB returns the total main memory, in bytes.
*
* Since it is difficult to get the RAM memory size exactly -- either
* by reading information from the DIMMs, which may fail on virtual hosts
* or from asking the kernel, which doesn't report some memory areas --
* this returns a pair of guessed-size (in bytes) and a "guesstimate factor"
* which says how good the guess is. Generally, assume the *real* memory
* available is size * guesstimate.
*
* If nothing can be found, returns a 0 size and 0 guesstimate.
*
* @return size, guesstimate-factor
*/
DLLEXPORT QPair< quint64, qreal > getTotalMemoryB() const;
/**
* @brief getCpuDescription returns a string describing the CPU.
*
* Returns the value of the "model name" line in /proc/cpuinfo.
*/
DLLEXPORT QString getCpuDescription() const;
/**
* @brief getTotalDiskB returns the total disk attached, in bytes.
*
* If nothing can be found, returns a 0.
*/
DLLEXPORT quint64 getTotalDiskB() const;
DLLEXPORT bool doChroot() const;
private:
static System* s_instance;
bool m_doChroot;
};
} // namespace Calamares
#endif

View 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 UTILS_TRAITS_H
#define UTILS_TRAITS_H
#include <type_traits>
namespace Calamares
{
/** @brief Traits machinery lives in this namespace
*
* The primary purpose of this namespace is to hold machinery that
* is created by the DECLARE_HAS_METHOD macro.
*
* The DECLARE_HAS_METHOD macro builds machinery to check whether
* a class has a particular named method. This can be used to
* specialize templates elsewhere for use with classes with, or without,
* the named method.
*
* To use the machinery (which is not that sophisticated):
*
* - Put `DECLARE_HAS_METHOD(myFunction)` somewhere in file scope.
* This puts together the machinery for detecting if `myFunction`
* is a method of some class.
* - At global scope, `has_myFunction<T>` is now either std::true_type,
* if the type `T` has a method `T::myFunction`, or std::false_type,
* if it does not.
*
* To specialize template methods based on the presence of the named
* method, write **three** overloads:
*
* - `template<class T> myMethod(args ..., const std::true_type& )`
* This is the implementation where class T has `myFunction`.
* - `template<class T> myMethod(args ..., const std::false_type& )`
* This is the implementation without.
* - `template<class T> myMethod(args ...)` is the general implementation,
* which can call the specialized implementations with
* `return myMethod(args ..., has_myFunction<T>{})`
*/
namespace Traits
{
template < class >
struct sfinae_true : std::true_type
{
};
} // namespace Traits
} // namespace Calamares
#define DECLARE_HAS_METHOD( m ) \
namespace Calamares \
{ \
namespace Traits \
{ \
struct has_##m \
{ \
template < class T > \
static auto f( int ) -> sfinae_true< decltype( &T::m ) >; \
template < class T > \
static auto f( long ) -> std::false_type; \
template < class T > \
using t = decltype( f< T >( 0 ) ); \
}; \
} \
} \
template < class T > \
using has_##m = Calamares::Traits::has_##m ::t< T >;
#endif

View File

@@ -0,0 +1,50 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_UMASK_H
#define UTILS_UMASK_H
#include "DllMacro.h"
#include <sys/types.h>
namespace Calamares
{
/** @brief Wrapper for umask(2)
*
* Like umask(2), sets the umask and returns the previous value of the mask.
*/
DLLEXPORT mode_t setUMask( mode_t u );
/** @brief RAII for setting and re-setting umask.
*
* Create an object of this class to set the umask,
* and the umask is reset to its original value when
* the object goes out of scope.
*/
class DLLEXPORT UMask
{
public:
UMask( mode_t u );
~UMask();
/** @brief a "safe" umask
*
* This umask will switch off group- and other- permissions for
* files, so that the file cannot be read, written, or executed
* except by the owner.
*/
static constexpr mode_t Safe = 077; // octal!
private:
mode_t m_mode;
};
} // namespace Calamares
#endif

View File

@@ -0,0 +1,181 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-FileCopyrightText: 2019 Collabora Ltd <arnaud.ferraris@collabora.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_UNITS_H
#define UTILS_UNITS_H
#include <QtCore/QIntegerForSize>
namespace Calamares
{
/// @brief Type for expressing units
using intunit_t = quint64;
namespace Units
{
/** User defined literals, 1_KB is 1 KiloByte (= 10^3 bytes) */
constexpr qint64
operator""_KB( unsigned long long m )
{
return qint64( m ) * 1000;
}
/** User defined literals, 1_KiB is 1 KibiByte (= 2^10 bytes) */
constexpr qint64
operator""_KiB( unsigned long long m )
{
return qint64( m ) * 1024;
}
/** User defined literals, 1_MB is 1 MegaByte (= 10^6 bytes) */
constexpr qint64
operator""_MB( unsigned long long m )
{
return operator""_KB( m ) * 1000;
}
/** User defined literals, 1_MiB is 1 MibiByte (= 2^20 bytes) */
constexpr qint64
operator""_MiB( unsigned long long m )
{
return operator""_KiB( m ) * 1024;
}
/** User defined literals, 1_GB is 1 GigaByte (= 10^9 bytes) */
constexpr qint64
operator""_GB( unsigned long long m )
{
return operator""_MB( m ) * 1000;
}
/** User defined literals, 1_GiB is 1 GibiByte (= 2^30 bytes) */
constexpr qint64
operator""_GiB( unsigned long long m )
{
return operator""_MiB( m ) * 1024;
}
} // namespace Units
constexpr qint64
KBtoBytes( unsigned long long m )
{
return Units::operator""_KB( m );
}
constexpr qint64
KiBtoBytes( unsigned long long m )
{
return Units::operator""_KiB( m );
}
constexpr qint64
MBtoBytes( unsigned long long m )
{
return Units::operator""_MB( m );
}
constexpr qint64
MiBtoBytes( unsigned long long m )
{
return Units::operator""_MiB( m );
}
constexpr qint64
GBtoBytes( unsigned long long m )
{
return Units::operator""_GB( m );
}
constexpr qint64
GiBtoBytes( unsigned long long m )
{
return Units::operator""_GiB( m );
}
constexpr qint64
KBtoBytes( double m )
{
return qint64( m * 1000 );
}
constexpr qint64
KiBtoBytes( double m )
{
return qint64( m * 1024 );
}
constexpr qint64
MBtoBytes( double m )
{
return qint64( m * 1000 * 1000 );
}
constexpr qint64
MiBtoBytes( double m )
{
return qint64( m * 1024 * 1024 );
}
constexpr qint64
GBtoBytes( double m )
{
return qint64( m * 1000 * 1000 * 1000 );
}
constexpr qint64
GiBtoBytes( double m )
{
return qint64( m * 1024 * 1024 * 1024 );
}
constexpr int
BytesToMiB( qint64 b )
{
return int( b / 1024 / 1024 );
}
// TODO: deprecate signed version
constexpr int
BytesToGiB( qint64 b )
{
return int( b / 1024 / 1024 / 1024 );
}
constexpr intunit_t
BytesToGiB( intunit_t b )
{
return b / 1024 / 1024 / 1024;
}
constexpr qint64
alignBytesToBlockSize( qint64 bytes, qint64 blocksize )
{
qint64 blocks = bytes / blocksize;
if ( blocks * blocksize != bytes )
{
++blocks;
}
return blocks * blocksize;
}
constexpr qint64
bytesToSectors( qint64 bytes, qint64 blocksize )
{
return alignBytesToBlockSize( alignBytesToBlockSize( bytes, blocksize ), MiBtoBytes( 1ULL ) ) / blocksize;
}
} // namespace Calamares
#endif

View File

@@ -0,0 +1,78 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2013-2016 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
*
* Calamares is Free Software: see the License-Identifier above.
*
*
*/
#ifndef UTILS_VARIANT_H
#define UTILS_VARIANT_H
#include "DllMacro.h"
#include <QList>
#include <QString>
#include <QVariantMap>
namespace Calamares
{
/**
* Get a bool value from a mapping with a given key; returns @p d if no value.
*/
DLLEXPORT bool getBool( const QVariantMap& map, const QString& key, bool d = false );
/** @brief Get a string value from a mapping with a given key; returns @p d if no value.
*
* The value must be an actual string; numbers are not automatically converted to strings,
* nor are lists flattened or converted.
*/
DLLEXPORT QString getString( const QVariantMap& map, const QString& key, const QString& d = QString() );
/** @brief Get a string list from a mapping with a given key; returns @p d if no value.
*
* This is slightly more lenient than getString(), and a single-string value will
* be returned as a 1-item list.
*/
DLLEXPORT QStringList getStringList( const QVariantMap& map, const QString& key, const QStringList& d = QStringList() );
/**
* Get a list from a mapping with a given key; returns @p d if no value.
*/
DLLEXPORT QList< QVariant >
getList( const QVariantMap& map, const QString& key, const QList< QVariant >& d = QList< QVariant >() );
/**
* Get an integer value from a mapping with a given key; returns @p d if no value.
*/
DLLEXPORT qint64 getInteger( const QVariantMap& map, const QString& key, qint64 d = 0 );
/**
* Get an unsigned integer value from a mapping with a given key; returns @p d if no value.
*/
DLLEXPORT quint64 getUnsignedInteger( const QVariantMap& map, const QString& key, quint64 d = 0 );
/**
* Get a double value from a mapping with a given key (integers are converted); returns @p d if no value.
*/
DLLEXPORT double getDouble( const QVariantMap& map, const QString& key, double d = 0.0 );
/**
* Returns a sub-map (i.e. a nested map) from a given mapping with a
* given key. @p success is set to true if the @p key exists
* in @p map and converts to a map, false otherwise.
*
* Returns @p d if there is no such key or it is not a map-value.
* (e.g. if @p success is false).
*/
DLLEXPORT QVariantMap getSubMap( const QVariantMap& map,
const QString& key,
bool& success,
const QVariantMap& d = QVariantMap() );
} // namespace Calamares
#endif

View File

@@ -0,0 +1,85 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017-2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
/*
* YAML conversions and YAML convenience header.
*
* Includes the system YAMLCPP headers without warnings (by switching off
* the expected warnings) and provides a handful of methods for
* converting between YAML and QVariant.
*/
#ifndef UTILS_YAML_H
#define UTILS_YAML_H
#include "DllMacro.h"
#include <QStringList>
#include <QVariant>
#include <QVariantList>
#include <QVariantMap>
class QByteArray;
class QFileInfo;
// The yaml-cpp headers are not C++11 warning-proof, especially
// with picky compilers like Clang 8. Since we use Clang for the
// find-all-the-warnings case, switch those warnings off for
// the we-can't-change-them system headers.
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG( "-Wzero-as-null-pointer-constant" )
QT_WARNING_DISABLE_CLANG( "-Wshadow" )
QT_WARNING_DISABLE_CLANG( "-Wfloat-equal" )
QT_WARNING_DISABLE_CLANG( "-Wsuggest-destructor-override" )
#include <yaml-cpp/yaml.h>
QT_WARNING_POP
/// @brief Appends all the elements of @p node to the string list @p v
DLLEXPORT void operator>>( const ::YAML::Node& node, QStringList& v );
namespace Calamares
{
namespace YAML
{
/**
* Loads a given @p filename and returns the YAML data
* as a QVariantMap. If filename doesn't exist, or is
* malformed in some way, returns an empty map and sets
* @p *ok to false. Otherwise sets @p *ok to true.
*/
DLLEXPORT QVariantMap load( const QString& filename, bool* ok = nullptr );
/** Convenience overload. */
DLLEXPORT QVariantMap load( const QFileInfo&, bool* ok = nullptr );
DLLEXPORT QVariant toVariant( const ::YAML::Node& node );
DLLEXPORT QVariant scalarToVariant( const ::YAML::Node& scalarNode );
DLLEXPORT QVariantList sequenceToVariant( const ::YAML::Node& sequenceNode );
DLLEXPORT QVariantMap mapToVariant( const ::YAML::Node& mapNode );
/// @brief Returns all the elements of @p listNode in a StringList
DLLEXPORT QStringList toStringList( const ::YAML::Node& listNode );
/// @brief Save a @p map to @p filename as YAML
DLLEXPORT bool save( const QString& filename, const QVariantMap& map );
/**
* Given an exception from the YAML parser library, explain
* what is going on in terms of the data passed to the parser.
* Uses @p label when labeling the data source (e.g. "netinstall data")
*/
DLLEXPORT void explainException( const ::YAML::Exception& e, const QByteArray& data, const char* label );
DLLEXPORT void explainException( const ::YAML::Exception& e, const QByteArray& data, const QString& label );
DLLEXPORT void explainException( const ::YAML::Exception& e, const QByteArray& data );
} // namespace YAML
} // namespace Calamares
#endif

View File

@@ -0,0 +1,35 @@
/* === 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.
*
*
*/
/* @file Turn off warnings on MOC-generated code
*
* This header file exists **only** to reduce warnings during compilation.
* Code generated by Qt's MOC, in combination with Clang (version 6 or later,
* I'm fairly sure) and the plenty-of-warnings settings that Calamares uses,
* triggers tons of warnings. Since those warnings are not something we
* can do anything about, turn them off by `#include`ing this header
* before a MOC file.
*
* Note that not many files in Calamares use MOC directly: mostly CMake's
* automoc does all the work for us.
*/
#ifdef __clang__
#include <qglobal.h>
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG( "-Wextra-semi-stmt" )
QT_WARNING_DISABLE_CLANG( "-Wredundant-parens" )
QT_WARNING_DISABLE_CLANG( "-Wreserved-identifier" )
#if __clang_major__ >= 17
QT_WARNING_DISABLE_CLANG( "-Wunsafe-buffer-usage" )
#endif
QT_WARNING_POP
#endif

View File

@@ -0,0 +1,54 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef BLANKVIEWSTEP_H
#define BLANKVIEWSTEP_H
#include "viewpages/ViewStep.h"
namespace Calamares
{
/** @brief A "blank" view step, used for error and status reporting
*
* This view step never allows navigation (forward or back); it's a trap.
* It displays a title and explanation, and optional details.
*/
class BlankViewStep : public Calamares::ViewStep
{
Q_OBJECT
public:
explicit BlankViewStep( const QString& title,
const QString& description,
const QString& details = QString(),
QObject* parent = nullptr );
~BlankViewStep() override;
QString prettyName() const override;
QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override;
bool isBackEnabled() const override;
bool isAtBeginning() const override;
bool isAtEnd() const override;
Calamares::JobList jobs() const override;
private:
QWidget* m_widget;
};
} // namespace Calamares
#endif // BLANKVIEWSTEP_H

View File

@@ -0,0 +1,80 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef EXECUTIONVIEWSTEP_H
#define EXECUTIONVIEWSTEP_H
#include "ViewStep.h"
#include "modulesystem/InstanceKey.h"
#include "widgets/LogWidget.h"
#include <QStringList>
class QLabel;
class QObject;
class QProgressBar;
class QTabWidget;
namespace Calamares
{
class Slideshow;
/**
* @class
*
* This is the implementation of the special ViewStep "Install"
* which takes care of an *exec* phase in the sequence. It runs
* jobs, shows the slideshow, etc.
*/
class UIDLLEXPORT ExecutionViewStep : public ViewStep
{
Q_OBJECT
public:
explicit ExecutionViewStep( QObject* parent = nullptr );
QString prettyName() const override;
QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override;
bool isBackEnabled() const override;
bool isAtBeginning() const override;
bool isAtEnd() const override;
void onActivate() override;
void onLeave() override;
JobList jobs() const override;
void appendJobModuleInstanceKey( const ModuleSystem::InstanceKey& instanceKey );
private:
QWidget* m_widget;
QProgressBar* m_progressBar;
QLabel* m_label;
Slideshow* m_slideshow;
QTabWidget* m_tab_widget;
LogWidget* m_log_widget;
QList< ModuleSystem::InstanceKey > m_jobInstanceKeys;
void updateFromJobQueue( qreal percent, const QString& message );
void toggleLog();
};
} // namespace Calamares
#endif /* EXECUTIONVIEWSTEP_H */

View File

@@ -0,0 +1,127 @@
/* === 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 QMLVIEWSTEP_H
#define QMLVIEWSTEP_H
#include "DllMacro.h"
#include "utils/Qml.h"
#include "viewpages/ViewStep.h"
class QQmlComponent;
class QQmlEngine;
class QQuickItem;
class QQuickWidget;
class WaitingWidget;
namespace Calamares
{
/** @brief A viewstep that uses QML for the UI
*
* This is generally a **base** class for other view steps, but
* it can be used stand-alone for viewsteps that don't really have
* any functionality.
*
* Most subclasses will override the following methods:
* - prettyName() to provide a meaningful human-readable name
* - jobs() if there is real work to be done during installation
* - getConfig() to return a meaningful configuration object
*
* For details on the interaction between the config object and
* the QML in the module, see the module documentation:
* src/modules/README.md
*/
class UIDLLEXPORT QmlViewStep : public Calamares::ViewStep
{
Q_OBJECT
public:
/** @brief Creates a QML view step
*
* The search behavior for the actial QML depends on a QmlSearch value.
* This is set through common configuration key *qmlSearch*.
* The filename used comes from the module identifier, or can be
* set in the configuration file through *qmlFilename*.
*
* @see Qml.h for available Calamares internals.
*/
QmlViewStep( QObject* parent = nullptr );
~QmlViewStep() override;
virtual QString prettyName() const override;
virtual QWidget* widget() override;
virtual QSize widgetMargins( Qt::Orientations panelSides ) override;
virtual bool isNextEnabled() const override;
virtual bool isBackEnabled() const override;
virtual bool isAtBeginning() const override;
virtual bool isAtEnd() const override;
virtual void onActivate() override;
virtual void onLeave() override;
/// @brief QML widgets don't produce jobs by default
virtual JobList jobs() const override;
/// @brief Configure search paths; subclasses should call this at the **end** of their own implementation
virtual void setConfigurationMap( const QVariantMap& configurationMap ) override;
protected:
/** @brief Gets a pointer to the Config of this view step
*
* Parts of the configuration of the viewstep can be passed to QML
* by placing them in a QObject (as properties). The default
* implementation returns nullptr, for no-config.
*
* Ownership of the config object remains with the ViewStep; it is possible
* to return a pointer to a member variable.
*
* This object is made available as a context-property *config* in QML.
*/
virtual QObject* getConfig();
/** @brief Adds a context property for this QML file
*
* Does not take ownership.
*/
void setContextProperty( const char* name, QObject* property );
private Q_SLOTS:
void loadComplete();
private:
/// @brief Swap out the spinner for the QQuickWidget
void showQml();
/// @brief Show error message in spinner.
void showFailedQml();
/// @brief Controls where m_name is searched
Calamares::QmlSearch m_searchMethod;
QString m_name;
QString m_qmlFileName;
QWidget* m_widget = nullptr;
WaitingWidget* m_spinner = nullptr;
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QQuickWidget* m_qmlWidget = nullptr;
#else
QWidget* m_qmlWidget = nullptr; // Qt6: container for QQuickWindow
#endif
QQmlEngine* m_qmlEngine = nullptr; // Qt5: points to QuickWidget engine, Qt6: separate engine
QQmlComponent* m_qmlComponent = nullptr;
QQuickItem* m_qmlObject = nullptr;
};
} // namespace Calamares
#endif

View File

@@ -0,0 +1,142 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef LIBCALAMARESUI_SLIDESHOW_H
#define LIBCALAMARESUI_SLIDESHOW_H
#include "CalamaresConfig.h"
#include <QMutex>
#include <QStringList>
#include <QWidget>
class QLabel;
class QTimer;
#ifdef WITH_QML
class QQmlComponent;
class QQuickItem;
class QQuickWidget;
#endif
namespace Calamares
{
/** @brief API for Slideshow objects
*
* A Slideshow (subclass) object is created by the ExecutionViewStep
* and needs to manage its own configuration (e.g. from Branding).
* The slideshow is started and stopped when it becomes visible
* and when installation is over, by calling changeSlideShowState()
* as appropriate.
*/
class Slideshow : public QObject
{
Q_OBJECT
public:
/// @brief State-change of the slideshow, for changeSlideShowState()
enum Action
{
Start,
Stop
};
Slideshow( QWidget* parent = nullptr )
: QObject( parent )
{
}
~Slideshow() override;
/// @brief Is the slideshow being shown **right now**?
bool isActive() const { return m_state == Start; }
/** @brief The actual widget to show the user.
*
* Depending on the style of slideshow, this might be a QQuickWidget,
* or a QLabel, or something else entirely.
*/
virtual QWidget* widget() = 0;
/** @brief Tells the slideshow we activated or left the show.
*
* If @p state is @c Slideshow::Start, calls suitable activation procedures.
* If @p state is @c Slideshow::Stop, calls deactivation procedures.
*/
virtual void changeSlideShowState( Action a ) = 0;
protected:
QMutex m_mutex;
Action m_state = Stop;
};
#ifdef WITH_QML
/** @brief Slideshow using a QML file
*
* This is the "classic" slideshow in Calamares, which runs some QML
* while the installation is in progress. It is configured through
* Branding settings *slideshow* and *slideshowAPI*, showing the QML
* file from *slideshow*. The API version influences when and how the
* QML is loaded; version 1 does so only when the slideshow is activated,
* while version 2 does so asynchronously.
*/
class SlideshowQML : public Slideshow
{
Q_OBJECT
public:
SlideshowQML( QWidget* parent );
~SlideshowQML() override;
QWidget* widget() override;
void changeSlideShowState( Action a ) override;
public slots:
void loadQmlV2Complete();
void loadQmlV2(); ///< Loads the slideshow QML (from branding) for API version 2
/// Implementation detail
void startSlideShow();
private:
QQuickWidget* m_qmlShow;
QQmlComponent* m_qmlComponent;
QQuickItem* m_qmlObject; ///< The actual show
};
#endif
/** @brief Slideshow using images
*
* This is an "oldschool" slideshow, but new in Calamares, which
* displays static image files one-by-one. It is for systems that
* do not use QML at all. It is configured through the Branding
* setting *slideshow*. When using this widget, the setting must
* be a list of filenames; the API is set to -1.
*/
class SlideshowPictures : public Slideshow
{
Q_OBJECT
public:
SlideshowPictures( QWidget* parent );
~SlideshowPictures() override;
QWidget* widget() override;
virtual void changeSlideShowState( Action a ) override;
public slots:
void next();
private:
QLabel* m_label;
QTimer* m_timer;
int m_imageIndex;
QStringList m_images;
};
} // namespace Calamares
#endif

View File

@@ -0,0 +1,199 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014-2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef VIEWSTEP_H
#define VIEWSTEP_H
#include "DllMacro.h"
#include "Job.h"
#include "modulesystem/InstanceKey.h"
#include "modulesystem/Requirement.h"
#include <QList>
#include <QObject>
#include <QSize>
namespace Calamares
{
/**
* @brief The ViewStep class is the base class for all view modules.
* A view module is a Calamares module which has at least one UI page (exposed as
* ViewStep::widget), and can optionally create Calamares jobs at runtime.
* As of early 2020, a view module can be implemented by deriving from ViewStep
* in C++ (as a Qt Plugin or a Qml ViewStep).
*
* A ViewStep can describe itself in human-readable format for the SummaryPage
* (which shows all of the things which have been collected to be done in the
* next exec-step) through prettyStatus() and createSummaryWidget().
*/
class UIDLLEXPORT ViewStep : public QObject
{
Q_OBJECT
public:
explicit ViewStep( QObject* parent = nullptr );
~ViewStep() override;
/** @brief Human-readable name of the step
*
* This (translated) string is shown in the sidebar (progress)
* and during installation. There is no default.
*/
virtual QString prettyName() const = 0;
/** @brief Describe what this step will do during install
*
* Optional. May return a non-empty string describing what this
* step is going to do (should be translated). This is also used
* in the summary page to describe what is going to be done.
* Return an empty string to provide no description.
*
* The default implementation returns an empty string, so nothing
* will be displayed for this step when a summary is shown.
*/
virtual QString prettyStatus() const;
/** @brief Return a long description what this step will do during install
*
* Optional. May return a widget which will be inserted in the summary
* page. The caller takes ownership of the widget. Return nullptr to
* provide no widget. In general, this is only used for complicated
* steps where prettyStatus() is not sufficient.
*
* The default implementation returns nullptr, so nothing
* will be displayed for this step when a summary is shown.
*/
virtual QWidget* createSummaryWidget() const;
/** @brief Get (or create) the widget for this view step
*
* While a view step **may** create the widget when it is loaded,
* it is recommended to wait with widget creation until the
* widget is actually asked for: a view step **may** be used
* without a UI.
*/
virtual QWidget* widget() = 0;
/** @brief Get margins for this widget
*
* This is called by the layout manager to find the desired
* margins (width is used for left and right margin, height is
* used for top and bottom margins) for the widget. The
* @p panelSides indicates where there are panels in the overall
* layout: horizontally and / or vertically adjacent (or none!)
* to the view step's widget.
*
* Should return a size based also on QStyle metrics for layout.
* The default implementation just returns the default layout metrics
* (often 11 pixels on a side).
*/
virtual QSize widgetMargins( Qt::Orientations panelSides );
/**
* @brief Multi-page support, go next
*
* Multi-page view steps need to manage the content visible in the widget
* themselves. This method is called when the user clicks the *next*
* button, and should switch to the next of the multiple-pages. It needs
* to be consistent with both isNextEnabled() and isAtEnd().
*
* In particular: when isAtEnd() returns false, next() is called when
* the user clicks the button and a new page should be shown by this
* view step. When isAtEnd() returns true, clicking the button will
* switch to the next view step in sequence, rather than a next page
* in the current view step.
*/
virtual void next();
/// @brief Multi-page support, go back
virtual void back();
/// @brief Can the user click *next* with currently-filled-in data?
virtual bool isNextEnabled() const = 0;
/// @brief Can the user click *previous* with currently-filled-in data?
virtual bool isBackEnabled() const = 0;
/**
* @brief Multi-page support, switch to previous view step?
*
* For a multi-page view step, this indicates that the first (beginning)
* page is showing. Clicking *previous* when at the beginning of a view
* step, switches to the previous step, not the previous page of the
* current view step.
*/
virtual bool isAtBeginning() const = 0;
/// @brief Multi-page support, switch to next view step?
virtual bool isAtEnd() const = 0;
/**
* @brief onActivate called every time a ViewStep is shown, either by going forward
* or backward.
* The default implementation does nothing.
*/
virtual void onActivate();
/**
* @brief onLeave called every time a ViewStep is hidden and control passes to
* another ViewStep, either by going forward or backward.
* The default implementation does nothing.
*/
virtual void onLeave();
/**
* @brief Jobs needed to run this viewstep
*
* When a ViewStep is listed in the exec section, its jobs are executed instead.
* This function returns that list of jobs; an empty list is ok.
*/
virtual JobList jobs() const = 0;
void setModuleInstanceKey( const Calamares::ModuleSystem::InstanceKey& instanceKey );
Calamares::ModuleSystem::InstanceKey moduleInstanceKey() const { return m_instanceKey; }
virtual void setConfigurationMap( const QVariantMap& configurationMap );
/**
* @brief Can this module proceed, on this machine?
*
* This is called asynchronously at startup, and returns a list of
* the requirements that the module has checked, and their status.
* See Calamares::RequirementEntry for details.
*/
virtual RequirementsList checkRequirements();
/**
* @brief Called when the user cancels the installation
*
* View steps are expected to leave the system unchanged when
* the installation is cancelled. The default implementation
* does nothing.
*/
virtual void onCancel();
signals:
/// @brief Tells the viewmanager to enable the *next* button according to @p status
void nextStatusChanged( bool status );
/* Emitted when the viewstep thinks it needs more space than is currently
* available for display. @p size is the requested space, that is needed
* to display the entire page.
*
* This request may be silently ignored.
*/
void ensureSize( QSize enlarge ) const;
protected:
Calamares::ModuleSystem::InstanceKey m_instanceKey;
};
using ViewStepList = QList< ViewStep* >;
} // namespace Calamares
#endif // VIEWSTEP_H

View File

@@ -0,0 +1,51 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef LIBCALAMARESUI_WIDGETS_CLICKABLELABEL_H
#define LIBCALAMARESUI_WIDGETS_CLICKABLELABEL_H
#include <QElapsedTimer>
#include <QLabel>
#include "DllMacro.h"
namespace Calamares
{
namespace Widgets
{
/** @brief A Label where the whole label area is clickable
*
* When clicking anywhere on the Label (text, background, whatever)
* the signal clicked() is emitted. Use this as a buddy for radio
* buttons or other clickable things where you want mouse interaction
* with the label, to be the same as mouse interaction with the control.
*/
class UIDLLEXPORT ClickableLabel : public QLabel
{
Q_OBJECT
public:
explicit ClickableLabel( QWidget* parent = nullptr );
explicit ClickableLabel( const QString& text, QWidget* parent = nullptr );
~ClickableLabel() override;
signals:
void clicked();
protected:
virtual void mousePressEvent( QMouseEvent* event ) override;
virtual void mouseReleaseEvent( QMouseEvent* event ) override;
private:
QElapsedTimer m_time;
};
} // namespace Widgets
} // namespace Calamares
#endif // LIBCALAMARESUI_WIDGETS_CLICKABLELABEL_H

View File

@@ -0,0 +1,83 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2021 Artem Grinev <agrinev@manjaro.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef LIBCALAMARESUI_ERRORDIALOG_H
#define LIBCALAMARESUI_ERRORDIALOG_H
#include <QDialog>
namespace Ui
{
class ErrorDialog;
} // namespace Ui
namespace Calamares
{
class ErrorDialog : public QDialog
{
Q_OBJECT
Q_PROPERTY( QString heading READ heading WRITE setHeading NOTIFY headingChanged )
Q_PROPERTY( QString informativeText READ informativeText WRITE setInformativeText NOTIFY informativeTextChanged )
Q_PROPERTY( QString details READ details WRITE setDetails NOTIFY detailsChanged )
Q_PROPERTY( bool shouldOfferWebPaste READ shouldOfferWebPaste WRITE setShouldOfferWebPaste NOTIFY
shouldOfferWebPasteChanged )
public:
explicit ErrorDialog( QWidget* parent = nullptr );
~ErrorDialog() override;
/** @brief The heading (title) of the error dialog
*
* This is a short (one-line) title. It is human-readable, so should
* be translated at the time it is set.
*/
QString heading() const;
void setHeading( const QString& newHeading );
/** @brief The description of the problem
*
* Longer, human-readable, description of the problem. This text
* is word-wrapped as necessary.
*/
QString informativeText() const;
void setInformativeText( const QString& newInformativeText );
/** @brief Details of the problem
*
* This is generally command-output; it might not be translated
* when set. It should be considered "background to the informative
* text", or maybe "the reasons". Write the informative text for
* the end-user.
*/
QString details() const;
void setDetails( const QString& newDetails );
/** @brief Enable web-paste button
*
* The web-paste button can be configured at a global level,
* but each individual error dialog can be set separately.
*/
bool shouldOfferWebPaste() const;
void setShouldOfferWebPaste( bool newShouldOfferWebPaste );
signals:
void headingChanged();
void informativeTextChanged();
void detailsChanged();
void shouldOfferWebPasteChanged();
private:
Ui::ErrorDialog* ui;
bool m_shouldOfferWebPaste = false;
};
} // namespace Calamares
#endif // LIBCALAMARESUI_ERRORDIALOG_H

View File

@@ -0,0 +1,34 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
* SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef FIXEDASPECTRATIOLABEL_H
#define FIXEDASPECTRATIOLABEL_H
#include "DllMacro.h"
#include <QLabel>
#include <QPixmap>
class UIDLLEXPORT FixedAspectRatioLabel : public QLabel
{
Q_OBJECT
public:
explicit FixedAspectRatioLabel( QWidget* parent = nullptr );
~FixedAspectRatioLabel() override;
public slots:
void setPixmap( const QPixmap& pixmap );
void resizeEvent( QResizeEvent* event ) override;
private:
QPixmap m_pixmap;
};
#endif // FIXEDASPECTRATIOLABEL_H

View File

@@ -0,0 +1,55 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2022 Bob van der Linden <bobvanderlinden@gmail.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef LIBCALAMARESUI_LOGWIDGET_H
#define LIBCALAMARESUI_LOGWIDGET_H
#include <QPlainTextEdit>
#include <QThread>
#include <QWidget>
namespace Calamares
{
class LogThread : public QThread
{
Q_OBJECT
void run() override;
public:
explicit LogThread( QObject* parent = nullptr );
~LogThread() override;
Q_SIGNALS:
void onLogChunk( const QString& logChunk );
};
class LogWidget : public QWidget
{
Q_OBJECT
QPlainTextEdit* m_text;
LogThread m_log_thread;
public:
explicit LogWidget( QWidget* parent = nullptr );
public Q_SLOTS:
/// @brief Called by the thread when there is new data
void handleLogChunk( const QString& logChunk );
/// @brief Stop watching for log data
void stop();
/// @brief Start watching for new log data
void start();
};
} // namespace Calamares
#endif // LOGWIDGET_H

View File

@@ -0,0 +1,79 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef LIBCALAMARESUI_WIDGETS_PRETTYRADIOBUTTON_H
#define LIBCALAMARESUI_WIDGETS_PRETTYRADIOBUTTON_H
#include "DllMacro.h"
#include <QRadioButton>
class QButtonGroup;
class QComboBox;
class QGridLayout;
class QHBoxLayout;
namespace Calamares
{
namespace Widgets
{
class ClickableLabel;
/** @brief A radio button with fancy label next to it.
*
* The fancy label is used so that the text alongside the radio
* button can word-wrap, be multi-line, and support rich text.
*
* The radio button itself can be retrieved with buttonWidget(),
* and the whole behaves a lot like a label. Extra options can be
* added to the display (options are hidden when the button is
* not selected) with addOptionsComboBox().
*/
class UIDLLEXPORT PrettyRadioButton : public QWidget
{
Q_OBJECT
public:
explicit PrettyRadioButton( QWidget* parent = nullptr );
~PrettyRadioButton() override {}
/// @brief Passes @p text on to the ClickableLabel
void setText( const QString& text );
// Icon applies to the radio-button part
void setIconSize( const QSize& size );
QSize iconSize() const;
void setIcon( const QIcon& icon );
// Applies to the radio-button part
void setChecked( bool checked );
bool isChecked() const;
/** @brief Adds the radio-button part to the given @p group
*
* For managing the pretty-radio-button in button groups like normal
* radio buttons, call addToGroup() rather that group->addButton().
*/
void addToGroup( QButtonGroup* group, int id = -1 );
/// @brief Add an options drop-down to this button.
void addOptionsComboBox( QComboBox* );
protected slots:
/// Options are hidden when the radio button is off
void toggleOptions( bool checked );
protected:
ClickableLabel* m_label;
QRadioButton* m_radio;
QGridLayout* m_mainLayout;
QHBoxLayout* m_optionsLayout;
};
} // namespace Widgets
} // namespace Calamares
#endif // LIBCALAMARESUI_WIDGETS_PRETTYRADIOBUTTON_H

View File

@@ -0,0 +1,34 @@
/* === 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 LIBCALAMARESUI_WIDGETS_TRANSLATIONFIX_H
#define LIBCALAMARESUI_WIDGETS_TRANSLATIONFIX_H
#include "DllMacro.h"
class QMessageBox;
class QDialogButtonBox;
namespace Calamares
{
/** @brief Fixes the labels on the standard buttons of the message box
*
* Updates OK / Cancel / Yes / No because there does not
* seem to be a way to do so in the Retranslator code
* (in libcalamares) since the translated strings may come
* from a variety of platform-plugin sources and we can't
* guess the context.
*/
void UIDLLEXPORT fixButtonLabels( QMessageBox* );
void UIDLLEXPORT fixButtonLabels( QDialogButtonBox* );
} // namespace Calamares
#endif

View File

@@ -0,0 +1,78 @@
/* === This file is part of Calamares - <https://calamares.io> ===
*
* SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Calamares is Free Software: see the License-Identifier above.
*
*/
#ifndef WAITINGWIDGET_H
#define WAITINGWIDGET_H
#include "DllMacro.h"
#include "widgets/waitingspinnerwidget.h"
#include <chrono>
#include <memory>
class QLabel;
class QTimer;
/** @brief A spinner and a label below it
*
* The spinner has a fixed size of 4* the font height,
* and the text is displayed centered below it. Use this
* to display a long-term waiting situation with a status report.
*/
class UIDLLEXPORT WaitingWidget : public WaitingSpinnerWidget
{
public:
/// Create a WaitingWidget with initial @p text label.
explicit WaitingWidget( const QString& text, QWidget* parent = nullptr );
~WaitingWidget() override;
protected:
void changeEvent( QEvent* event ) override;
};
/** @brief A spinner and a countdown inside it
*
* The spinner is sized to the text-height and displays a
* numeric countdown iside the spinner. The countdown is updated
* every second. The signal timeout() is sent every time
* the countdown reaches 0.
*/
class UIDLLEXPORT CountdownWaitingWidget : public WaitingSpinnerWidget
{
Q_OBJECT
public:
/// Create a countdown widget with a given @p duration
explicit CountdownWaitingWidget( std::chrono::seconds duration = std::chrono::seconds( 5 ),
QWidget* parent = nullptr );
~CountdownWaitingWidget() override;
/// Changes the duration used and resets the countdown
void setInterval( std::chrono::seconds duration );
/// Start the countdown, resets to the full duration
void start();
/// Stop the countdown
void stop();
Q_SIGNALS:
void timeout();
protected Q_SLOTS:
void tick();
protected:
void changeEvent( QEvent* event ) override;
private:
struct Private;
std::unique_ptr< Private > d;
};
#endif // WAITINGWIDGET_H

View File

@@ -0,0 +1,162 @@
/*
* SPDX-FileCopyrightText: 2012-2014 Alexander Turkin
* SPDX-FileCopyrightText: 2014 William Hallatt
* SPDX-FileCopyrightText: 2015 Jacob Dawid
* SPDX-FileCopyrightText: 2018 huxingyi
* SPDX-License-Identifier: MIT
*/
/* Original Work Copyright (c) 2012-2014 Alexander Turkin
Modified 2014 by William Hallatt
Modified 2015 by Jacob Dawid
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "DllMacro.h"
#include <QColor>
#include <QTimer>
#include <QWidget>
class UIDLLEXPORT WaitingSpinnerWidget : public QWidget
{
Q_OBJECT
public:
/** @brief Constructor for "standard" widget behaviour
*
* Use this constructor if you wish to, e.g. embed your widget in another.
*/
WaitingSpinnerWidget( QWidget* parent = nullptr,
bool centerOnParent = true,
bool disableParentWhenSpinning = true );
/** @brief Constructor
*
* Use this constructor to automatically create a modal
* ("blocking") spinner on top of the calling widget/window. If a valid
* parent widget is provided, "centreOnParent" will ensure that
* QtWaitingSpinner automatically centres itself on it, if not,
* @p centerOnParent is ignored.
*/
WaitingSpinnerWidget( Qt::WindowModality modality,
QWidget* parent = nullptr,
bool centerOnParent = true,
bool disableParentWhenSpinning = true );
WaitingSpinnerWidget( const WaitingSpinnerWidget& ) = delete;
WaitingSpinnerWidget& operator=( const WaitingSpinnerWidget& ) = delete;
void setColor( QColor color );
void setTextColor( QColor color );
void setRoundness( qreal roundness );
void setMinimumTrailOpacity( qreal minimumTrailOpacity );
void setTrailFadePercentage( qreal trail );
void setRevolutionsPerSecond( qreal revolutionsPerSecond );
void setNumberOfLines( int lines );
void setLineLength( int length );
void setLineWidth( int width );
void setInnerRadius( int radius );
/** @brief Sets the text displayed in or below the spinner
*
* If the text is empty, no text is displayed. The text is displayed
* in or below the spinner depending on the value of alignment().
* With AlignBottom, the text is displayed below the spinner,
* centered horizontally relative to the spinner; any other alignment
* will put the text in the middle of the spinner itself.
*
* TODO: this does not support rich text. Rich text could be done
* through a QStaticText, or an HTML document. However, then
* we need to do more alignment calculations ourselves.
*/
void setText( const QString& text );
/** @brief Sets the alignment of text for the spinner
*
* The only meaningful values are AlignBottom and AlignVCenter,
* for text below the spinner and text in the middle.
*/
void setAlignment( Qt::AlignmentFlag align );
/// Convenience to set text-in-the-middle (@c true) or text-at-bottom (@c false)
void setCenteredText( bool centered )
{
setAlignment( centered ? Qt::AlignmentFlag::AlignVCenter : Qt::AlignmentFlag::AlignBottom );
}
QColor color() const;
QColor textColor() const;
QString text() const;
Qt::AlignmentFlag alignment() const { return _alignment; }
qreal roundness() const;
qreal minimumTrailOpacity() const;
qreal trailFadePercentage() const;
qreal revolutionsPersSecond() const;
int numberOfLines() const;
int lineLength() const;
int lineWidth() const;
int innerRadius() const;
bool isSpinning() const;
public Q_SLOTS:
void start();
void stop();
private Q_SLOTS:
void rotate();
protected:
void paintEvent( QPaintEvent* paintEvent ) override;
private:
void updateSize();
void updateTimer();
void updatePosition();
private:
// PI, leading to a full fade in one whole revolution
static constexpr const auto radian = 3.14159265358979323846;
// Spinner-wheel related settings
QColor _color = Qt::black;
qreal _roundness = 100.0; // 0..100
qreal _minimumTrailOpacity = radian;
qreal _trailFadePercentage = 80.0;
qreal _revolutionsPerSecond = radian / 2;
int _numberOfLines = 20;
int _lineLength = 10;
int _lineWidth = 2;
int _innerRadius = 10;
QSize _imageSize;
// Text-related settings
Qt::AlignmentFlag _alignment = Qt::AlignmentFlag::AlignBottom;
QString _text;
QColor _textColor = Qt::black;
// Environment settings
bool _centerOnParent = true;
bool _disableParentWhenSpinning = true;
// Internal bits
QTimer* _timer = nullptr;
int _currentCounter = 0;
bool _isSpinning = false;
};