Merge branch 'issue-1427'

Show failed requirements in one component, with a filter applied,
and with satisfied and mandatory (the latter has an effect on
can-we-continue, not on whether something is satisfied) colors applied.

FIXES #1427
This commit is contained in:
Adriaan de Groot 2020-06-09 12:15:16 +02:00
commit 5126aaae19
8 changed files with 91 additions and 77 deletions

View File

@ -96,13 +96,16 @@ RequirementsModel::roleNames() const
void void
RequirementsModel::describe() const RequirementsModel::describe() const
{ {
cDebug() << "Requirements model has" << m_requirements.count() << "items";
bool acceptable = true; bool acceptable = true;
int count = 0; int count = 0;
for ( const auto& r : m_requirements ) for ( const auto& r : m_requirements )
{ {
cDebug() << Logger::SubEntry << "requirement" << count << r.name
<< "satisfied?" << r.satisfied
<< "mandatory?" << r.mandatory;
if ( r.mandatory && !r.satisfied ) if ( r.mandatory && !r.satisfied )
{ {
cDebug() << Logger::SubEntry << "requirement" << count << r.name << "is not satisfied.";
acceptable = false; acceptable = false;
} }
++count; ++count;

View File

@ -32,6 +32,7 @@
Config::Config( QObject* parent ) Config::Config( QObject* parent )
: QObject( parent ) : QObject( parent )
, m_languages( CalamaresUtils::Locale::availableTranslations() ) , m_languages( CalamaresUtils::Locale::availableTranslations() )
, m_filtermodel( std::make_unique< QSortFilterProxyModel >() )
{ {
initLanguages(); initLanguages();
@ -97,6 +98,18 @@ Config::requirementsModel() const
return Calamares::ModuleManager::instance()->requirementsModel(); return Calamares::ModuleManager::instance()->requirementsModel();
} }
QAbstractItemModel*
Config::unsatisfiedRequirements() const
{
if ( !m_filtermodel->sourceModel() )
{
m_filtermodel->setFilterRole( Calamares::RequirementsModel::Roles::Satisfied );
m_filtermodel->setFilterFixedString( QStringLiteral( "false" ) );
m_filtermodel->setSourceModel( requirementsModel() );
}
return m_filtermodel.get();
}
QString QString
Config::languageIcon() const Config::languageIcon() const
@ -336,7 +349,7 @@ setCountry( Config* config, const QString& countryCode, CalamaresUtils::GeoIP::H
} }
static inline void static inline void
setGeoIP( Config* c, const QVariantMap& configurationMap ) setGeoIP( Config* config, const QVariantMap& configurationMap )
{ {
bool ok = false; bool ok = false;
QVariantMap geoip = CalamaresUtils::getSubMap( configurationMap, "geoip", ok ); QVariantMap geoip = CalamaresUtils::getSubMap( configurationMap, "geoip", ok );
@ -350,12 +363,12 @@ setGeoIP( Config* c, const QVariantMap& configurationMap )
if ( handler->type() != CalamaresUtils::GeoIP::Handler::Type::None ) if ( handler->type() != CalamaresUtils::GeoIP::Handler::Type::None )
{ {
auto* future = new FWString(); auto* future = new FWString();
QObject::connect( future, &FWString::finished, [config = c, f = future, h = handler]() { QObject::connect( future, &FWString::finished, [config, future, handler]() {
QString countryResult = f->future().result(); QString countryResult = future->future().result();
cDebug() << "GeoIP result for welcome=" << countryResult; cDebug() << "GeoIP result for welcome=" << countryResult;
::setCountry( config, countryResult, h ); ::setCountry( config, countryResult, handler );
f->deleteLater(); future->deleteLater();
delete h; delete handler;
} ); } );
future->setFuture( handler->queryRaw() ); future->setFuture( handler->queryRaw() );
} }

View File

@ -23,13 +23,37 @@
#include "modulesystem/RequirementsModel.h" #include "modulesystem/RequirementsModel.h"
#include <QObject> #include <QObject>
#include <QSortFilterProxyModel>
#include <QUrl> #include <QUrl>
#include <memory>
class Config : public QObject class Config : public QObject
{ {
Q_OBJECT Q_OBJECT
/** @brief The languages available in Calamares.
*
* This is a list-model, with names and descriptions for the translations
* available to Calamares.
*/
Q_PROPERTY( CalamaresUtils::Locale::LabelModel* languagesModel READ languagesModel CONSTANT FINAL ) Q_PROPERTY( CalamaresUtils::Locale::LabelModel* languagesModel READ languagesModel CONSTANT FINAL )
/** @brief The requirements (from modules) and their checked-status
*
* The model grows rows over time as each module is checked and its
* requirements are taken into account. The model **as a whole**
* has properties *satisfiedRequirements* and *satisfiedMandatory*
* to say if all of the requirements held in the model have been
* satisfied. See the model documentation for details.
*/
Q_PROPERTY( Calamares::RequirementsModel* requirementsModel READ requirementsModel CONSTANT FINAL ) Q_PROPERTY( Calamares::RequirementsModel* requirementsModel READ requirementsModel CONSTANT FINAL )
/** @brief The requirements (from modules) that are **unsatisfied**
*
* This is the same as requirementsModel(), except filtered so
* that only those requirements that are not satisfied are exposed.
* Note that the type is different, so you should still use the
* requirementsModel() for overall status like *satisfiedMandatory*.
*/
Q_PROPERTY( QAbstractItemModel* unsatisfiedRequirements READ unsatisfiedRequirements CONSTANT FINAL )
Q_PROPERTY( QString languageIcon READ languageIcon CONSTANT FINAL ) Q_PROPERTY( QString languageIcon READ languageIcon CONSTANT FINAL )
@ -83,6 +107,8 @@ public slots:
///@brief The **global** requirements model, from ModuleManager ///@brief The **global** requirements model, from ModuleManager
Calamares::RequirementsModel* requirementsModel() const; Calamares::RequirementsModel* requirementsModel() const;
QAbstractItemModel* unsatisfiedRequirements() const;
signals: signals:
void countryCodeChanged( QString countryCode ); void countryCodeChanged( QString countryCode );
void localeIndexChanged( int localeIndex ); void localeIndexChanged( int localeIndex );
@ -99,7 +125,8 @@ signals:
private: private:
void initLanguages(); void initLanguages();
CalamaresUtils::Locale::LabelModel* m_languages; CalamaresUtils::Locale::LabelModel* m_languages = nullptr;
std::unique_ptr< QSortFilterProxyModel > m_filtermodel;
QString m_languageIcon; QString m_languageIcon;
QString m_countryCode; QString m_countryCode;

View File

@ -67,6 +67,14 @@ requirements:
# Also, note the analogous feature in `src/modules/locale/locale.conf`, # Also, note the analogous feature in `src/modules/locale/locale.conf`,
# which is where you will find complete documentation. # which is where you will find complete documentation.
# #
# For testing, the *style* may be set to `fixed`, any URL that
# returns data (e.g. `http://example.com`) and then *selector*
# sets the data that is actually returned (e.g. "DE" to simulate
# the machine being in Germany).
#
# NOTE: the *selector* must pick the country code from the GeoIP
# data. Timezone, city, or other data will not be recognized.
#
geoip: geoip:
style: "none" style: "none"
url: "https://geoip.kde.org/v1/ubiquity" # extended XML format url: "https://geoip.kde.org/v1/ubiquity" # extended XML format

View File

@ -17,6 +17,8 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* THIS COMPONENT IS UNUSED -- from the default welcomeq.qml at least */
import io.calamares.core 1.0 import io.calamares.core 1.0
import io.calamares.ui 1.0 import io.calamares.ui 1.0

View File

@ -44,8 +44,12 @@ Rectangle {
activeFocusOnPress: false activeFocusOnPress: false
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: qsTr("<p>This computer does not satisfy the minimum requirements for installing %1.<br/> property var requirementsText: qsTr("<p>This computer does not satisfy the minimum requirements for installing %1.<br/>
Installation cannot continue.</p>").arg(Branding.string(Branding.VersionedName)) Installation cannot continue.</p>").arg(Branding.string(Branding.VersionedName))
property var recommendationsText: qsTr("<p>This computer does not satisfy some of the recommended requirements for setting up %1.<br/>
Setup can continue, but some features might be disabled.</p>").arg(Branding.string(Branding.VersionedName))
text: config.requirementsModel.satisfiedMandatory ? recommendationsText : requirementsText
} }
Rectangle { Rectangle {
@ -61,6 +65,7 @@ Rectangle {
Item { Item {
width: 640 width: 640
height: 35 height: 35
visible: true
Column { Column {
anchors.centerIn: parent anchors.centerIn: parent
@ -68,18 +73,22 @@ Rectangle {
Rectangle { Rectangle {
implicitWidth: 640 implicitWidth: 640
implicitHeight: 35 implicitHeight: 35
border.color: mandatory ? "#228b22" : "#ff0000" // Colors and images based on the two satisfied-bools:
color: mandatory ? "#f0fff0" : "#ffc0cb" // - if satisfied, then green / ok
// - otherwise if mandatory, then red / stop
// - otherwise, then yellow / warning
border.color: satisfied ? "#228b22" : (mandatory ? "#ff0000" : "#ffa411")
color: satisfied ? "#f0fff0" : (mandatory ? "#ffc0cb" : "#ffefd5")
Image { Image {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right anchors.right: parent.right
anchors.margins: 20 anchors.margins: 20
source: mandatory ? "qrc:/data/images/yes.svgz" : "qrc:/data/images/no.svgz" source: satisfied ? "qrc:/data/images/yes.svgz" : (mandatory ? "qrc:/data/images/no.svgz" : "qrc:/data/images/information.svgz")
} }
Text { Text {
text: mandatory ? details : negatedText text: satisfied ? details : negatedText
anchors.centerIn: parent anchors.centerIn: parent
font.pointSize: 11 font.pointSize: 11
} }
@ -89,9 +98,13 @@ Rectangle {
} }
ListView { ListView {
id: requirementsList
anchors.fill: parent anchors.fill: parent
spacing: 5 spacing: 5
model: config.requirementsModel // This uses the filtered model, so that only unsatisfied
// requirements are ever shown. You could use *requirementsModel*
// to get all of them.
model: config.unsatisfiedRequirements
delegate: requirementsDelegate delegate: requirementsDelegate
} }
} }

View File

@ -1,52 +1,23 @@
# Configuration for the welcome module. The welcome page # Configuration for the welcomeq module.
# displays some information from the branding file.
# Which parts it displays can be configured through
# the show* variables.
# #
# In addition to displaying the welcome page, this module # The configuration for welcomeq is exactly the same
# can check requirements for installation. # as the welcome module, with the one exception of
# *qmlSearch* which governs QML loading.
#
# No documentation is given here: look in the welcome module.
--- ---
# Setting for QML loading # Setting for QML loading: use QRC, branding, or both sources of files
qmlSearch: both qmlSearch: both
# Display settings for various buttons on the welcome page.
# The URLs themselves come from branding.desc is the setting # Everythin below here is documented in `welcome.conf`
# here is "true". If the setting is false, the button is hidden.
# The setting can also be a full URL which will then be used
# instead of the one from the branding file, or empty or not-set
# which will hide the button.
showSupportUrl: true showSupportUrl: true
showKnownIssuesUrl: true showKnownIssuesUrl: true
showReleaseNotesUrl: true showReleaseNotesUrl: true
# If this Url is set to something non-empty, a "donate"
# button is added to the welcome page alongside the
# others (see settings, above). Clicking the button opens
# the corresponding link. (This button has no corresponding
# branding.desc string)
#
# showDonateUrl: https://kde.org/community/donations/
# Requirements checking. These are general, generic, things
# that are checked. They may not match with the actual requirements
# imposed by other modules in the system.
requirements: requirements:
# Amount of available disk, in GiB. Floating-point is allowed here.
# Note that this does not account for *usable* disk, so it is possible
# to pass this requirement, yet have no space to install to.
requiredStorage: 5.5 requiredStorage: 5.5
# Amount of available RAM, in GiB. Floating-point is allowed here.
requiredRam: 1.0 requiredRam: 1.0
# To check for internet connectivity, Calamares does a HTTP GET
# on this URL; on success (e.g. HTTP code 200) internet is OK.
internetCheckUrl: http://google.com internetCheckUrl: http://google.com
# List conditions to check. Each listed condition will be
# probed in some way, and yields true or false according to
# the host system satisfying the condition.
#
# This sample file lists all the conditions that are known.
check: check:
- storage - storage
- ram - ram
@ -54,28 +25,9 @@ requirements:
- internet - internet
- root - root
- screen - screen
# List conditions that **must** be satisfied (from the list
# of conditions, above) for installation to proceed.
# If any of these conditions are not met, the user cannot
# continue past the welcome page.
required: required:
# - storage
- ram - ram
# - root
# GeoIP checking
#
# This can be used to pre-select a language based on the country
# the user is currently in. It *assumes* that there's internet
# connectivity, though. Configuration is like in the locale module,
# but remember to use a URL that returns full data **and** to
# use a selector that will pick the country, not the timezone.
#
# To disable GeoIP checking, either comment-out the entire geoip section,
# or set the *style* key to an unsupported format (e.g. `none`).
# Also, note the analogous feature in `src/modules/locale/locale.conf`,
# which is where you will find complete documentation.
#
geoip: geoip:
style: "none" style: "none"
url: "https://geoip.kde.org/v1/ubiquity" # extended XML format url: "https://geoip.kde.org/v1/ubiquity" # extended XML format

View File

@ -56,12 +56,8 @@ Page
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
} }
Recommended {
visible: !config.requirementsModel.satisfiedRequirements
}
Requirements { Requirements {
visible: !config.requirementsModel.satisfiedMandatory visible: !config.requirementsModel.satisfiedRequirements
} }
RowLayout { RowLayout {