diff --git a/CHANGES b/CHANGES index 22dac3dd2..d6f5de059 100644 --- a/CHANGES +++ b/CHANGES @@ -3,7 +3,19 @@ contributors are listed. Note that Calamares does not have a historical changelog -- this log starts with version 3.2.0. The release notes on the website will have to do for older versions. -# 3.2.24 (unreleased) # +# 3.2.25 (unreleased) # + +This release contains contributions from (alphabetically by first name): + - No external contributors yet + +## Core ## + - No core changes yet + +## Modules ## + - No module changes yet + + +# 3.2.24 (2020-05-11) # This release contains contributions from (alphabetically by first name): - Bill Auger @@ -18,6 +30,9 @@ This release contains contributions from (alphabetically by first name): - GlobalStorage is available to QML modules as `Global`. - The height of the navigation bar in QML can be set within the QML code for the navigation; if not set, try something sensible. + - A regression in the requirements-checker which could block the + installer from proceeding without telling the user **why** it + was blocked, has been resolved. ## Modules ## - The *bootloader* module can force a UEFI-based machine to boot into diff --git a/CMakeLists.txt b/CMakeLists.txt index 8603099db..5ead0b7c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ cmake_minimum_required( VERSION 3.3 FATAL_ERROR ) project( CALAMARES - VERSION 3.2.24 + VERSION 3.2.25 LANGUAGES C CXX ) set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development @@ -54,7 +54,7 @@ option( BUILD_TESTING "Build the testing tree." ON ) option( WITH_PYTHON "Enable Python modules API (requires Boost.Python)." ON ) option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." OFF ) option( WITH_KF5Crash "Enable crash reporting with KCrash." ON ) -option( WITH_KF5DBus "Use DBus service for unique-application." ON ) +option( WITH_KF5DBus "Use DBus service for unique-application." OFF ) # Possible debugging flags are: # - DEBUG_TIMEZONES draws latitude and longitude lines on the timezone diff --git a/src/libcalamares/modulesystem/RequirementsChecker.cpp b/src/libcalamares/modulesystem/RequirementsChecker.cpp index 97a4c912f..d59ccb602 100644 --- a/src/libcalamares/modulesystem/RequirementsChecker.cpp +++ b/src/libcalamares/modulesystem/RequirementsChecker.cpp @@ -20,6 +20,7 @@ #include "modulesystem/Module.h" #include "modulesystem/Requirement.h" +#include "modulesystem/RequirementsModel.h" #include "utils/Logger.h" #include @@ -32,47 +33,15 @@ namespace Calamares { -static void -registerMetatypes() -{ - static bool done = false; - - if ( !done ) - { - qRegisterMetaType< RequirementEntry >( "RequirementEntry" ); - // It's sensitive to the names of types in parameters; in particular - // althrough QList is the same as RequirementsList, - // because we *name* the type as RequirementsList in the parameters, - // we need to register that (as well). Here, be safe and register - // both names. - qRegisterMetaType< QList< RequirementEntry > >( "QList" ); - qRegisterMetaType< RequirementsList >( "RequirementsList" ); - done = true; - } -} - -static void -check( Module* const& m, RequirementsChecker* c ) -{ - RequirementsList l = m->checkRequirements(); - if ( l.count() > 0 ) - { - c->addCheckedRequirements( l ); - } - c->requirementsProgress( - QObject::tr( "Requirements checking for module %1 is complete." ).arg( m->name() ) ); -} - -RequirementsChecker::RequirementsChecker( QVector< Module* > modules, QObject* parent ) +RequirementsChecker::RequirementsChecker( QVector< Module* > modules, RequirementsModel* model, QObject* parent ) : QObject( parent ) , m_modules( std::move( modules ) ) + , m_model( model ) , m_progressTimer( nullptr ) , m_progressTimeouts( 0 ) { m_watchers.reserve( m_modules.count() ); - m_collectedRequirements.reserve( m_modules.count() ); - - registerMetatypes(); + connect( this, &RequirementsChecker::requirementsProgress, model, &RequirementsModel::setProgressMessage ); } RequirementsChecker::~RequirementsChecker() {} @@ -87,7 +56,7 @@ RequirementsChecker::run() for ( const auto& module : m_modules ) { Watcher* watcher = new Watcher( this ); - watcher->setFuture( QtConcurrent::run( check, module, this ) ); + watcher->setFuture( QtConcurrent::run( this, &RequirementsChecker::addCheckedRequirements, module ) ); watcher->setObjectName( module->name() ); m_watchers.append( watcher ); connect( watcher, &Watcher::finished, this, &RequirementsChecker::finished ); @@ -114,33 +83,23 @@ RequirementsChecker::finished() m_progressTimer = nullptr; } - bool acceptable = true; - int count = 0; - for ( const auto& r : m_collectedRequirements ) - { - if ( r.mandatory && !r.satisfied ) - { - cDebug() << Logger::SubEntry << "requirement" << count << r.name << "is not satisfied."; - acceptable = false; - } - ++count; - } - - emit requirementsComplete( acceptable ); + m_model->describe(); + m_model->changeRequirementsList(); QTimer::singleShot( 0, this, &RequirementsChecker::done ); } } void -RequirementsChecker::addCheckedRequirements( RequirementsList l ) +RequirementsChecker::addCheckedRequirements( Module* m ) { - static QMutex addMutex; + RequirementsList l = m->checkRequirements(); + cDebug() << "Got" << l.count() << "requirement results from" << m->name(); + if ( l.count() > 0 ) { - QMutexLocker lock( &addMutex ); - m_collectedRequirements.append( l ); + m_model->addRequirementsList( l ); } - cDebug() << "Added" << l.count() << "requirement results"; - emit requirementsResult( l ); + + requirementsProgress( tr( "Requirements checking for module %1 is complete." ).arg( m->name() ) ); } void diff --git a/src/libcalamares/modulesystem/RequirementsChecker.h b/src/libcalamares/modulesystem/RequirementsChecker.h index 450495dc1..21c86f0a6 100644 --- a/src/libcalamares/modulesystem/RequirementsChecker.h +++ b/src/libcalamares/modulesystem/RequirementsChecker.h @@ -29,6 +29,7 @@ namespace Calamares { class Module; +class RequirementsModel; /** @brief A manager-class that checks all the module requirements * @@ -40,7 +41,7 @@ class RequirementsChecker : public QObject Q_OBJECT public: - RequirementsChecker( QVector< Module* > modules, QObject* parent = nullptr ); + RequirementsChecker( QVector< Module* > modules, RequirementsModel* model, QObject* parent = nullptr ); virtual ~RequirementsChecker() override; public Q_SLOTS: @@ -48,7 +49,7 @@ public Q_SLOTS: void run(); /// @brief Called when requirements are reported by a module - void addCheckedRequirements( RequirementsList ); + void addCheckedRequirements( Module* ); /// @brief Called when all requirements have been checked void finished(); @@ -59,13 +60,6 @@ public Q_SLOTS: signals: /// @brief Human-readable progress message void requirementsProgress( const QString& ); - /// @brief Requirements from a single module - void requirementsResult( RequirementsList ); - /** @brief When all requirements are collected - * - * The argument indicates if all mandatory requirements are satisfied. - */ - void requirementsComplete( bool ); /// @brief Emitted after requirementsComplete void done(); @@ -75,7 +69,7 @@ private: using Watcher = QFutureWatcher< void >; QVector< Watcher* > m_watchers; - RequirementsList m_collectedRequirements; + RequirementsModel* m_model; QTimer* m_progressTimer; unsigned m_progressTimeouts; diff --git a/src/libcalamares/modulesystem/RequirementsModel.cpp b/src/libcalamares/modulesystem/RequirementsModel.cpp index 4001d2d81..eed3b8b3b 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.cpp +++ b/src/libcalamares/modulesystem/RequirementsModel.cpp @@ -18,15 +18,24 @@ #include "RequirementsModel.h" +#include "utils/Logger.h" + namespace Calamares { void -RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requirements ) +RequirementsModel::addRequirementsList( const Calamares::RequirementsList& requirements ) { + QMutexLocker l( &m_addLock ); emit beginResetModel(); - m_requirements = requirements; + m_requirements.append( requirements ); + changeRequirementsList(); + emit endResetModel(); +} +void +RequirementsModel::changeRequirementsList() +{ auto isUnSatisfied = []( const Calamares::RequirementEntry& e ) { return !e.satisfied; }; auto isMandatoryAndUnSatisfied = []( const Calamares::RequirementEntry& e ) { return e.mandatory && !e.satisfied; }; @@ -35,7 +44,6 @@ RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requi emit satisfiedRequirementsChanged( m_satisfiedRequirements ); emit satisfiedMandatoryChanged( m_satisfiedMandatory ); - emit endResetModel(); } int @@ -61,6 +69,8 @@ RequirementsModel::data( const QModelIndex& index, int role ) const return requirement.satisfied; case Roles::Mandatory: return requirement.mandatory; + case Roles::HasDetails: + return requirement.hasDetails(); default: return QVariant(); } @@ -75,7 +85,31 @@ RequirementsModel::roleNames() const roles[ Roles::NegatedText ] = "negatedText"; roles[ Roles::Satisfied ] = "satisfied"; roles[ Roles::Mandatory ] = "mandatory"; + roles[ Roles::HasDetails ] = "hasDetails"; return roles; } +void +RequirementsModel::describe() const +{ + bool acceptable = true; + int count = 0; + for ( const auto& r : m_requirements ) + { + if ( r.mandatory && !r.satisfied ) + { + cDebug() << Logger::SubEntry << "requirement" << count << r.name << "is not satisfied."; + acceptable = false; + } + ++count; + } +} + +void +RequirementsModel::setProgressMessage( const QString& m ) +{ + m_progressMessage = m; + emit progressMessageChanged( m_progressMessage ); +} + } // namespace Calamares diff --git a/src/libcalamares/modulesystem/RequirementsModel.h b/src/libcalamares/modulesystem/RequirementsModel.h index 2acf785e7..2318421c4 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.h +++ b/src/libcalamares/modulesystem/RequirementsModel.h @@ -24,15 +24,29 @@ #include "DllMacro.h" #include +#include 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 { + friend class RequirementsChecker; + 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; @@ -48,32 +62,44 @@ public: }; // 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; } - const Calamares::RequirementEntry& getEntry( int index ) const - { - return m_requirements.at( index ); - } - - void setRequirementsList( const Calamares::RequirementsList& requirements ); QVariant data( const QModelIndex& index, int role ) const override; int rowCount( const QModelIndex& ) const override; int count() const { return m_requirements.count(); } + ///@brief Debugging tool, describe the checking-state + void describe() const; + signals: void satisfiedRequirementsChanged( bool value ); void satisfiedMandatoryChanged( bool value ); + void progressMessageChanged( QString message ); protected: QHash< int, QByteArray > roleNames() const override; + ///@brief Append some requirements; resets the model + void addRequirementsList( const Calamares::RequirementsList& requirements ); + + ///@brief Update progress message (called by the checker) + void setProgressMessage( const QString& m ); + private: - Calamares::RequirementsList m_requirements; + ///@brief Implementation for {set,add}RequirementsList + void changeRequirementsList(); + + QString m_progressMessage; + QMutex m_addLock; + RequirementsList m_requirements; bool m_satisfiedRequirements = false; bool m_satisfiedMandatory = false; - }; } // namespace Calamares diff --git a/src/libcalamaresui/modulesystem/ModuleManager.cpp b/src/libcalamaresui/modulesystem/ModuleManager.cpp index 8d4b2342f..3a3174935 100644 --- a/src/libcalamaresui/modulesystem/ModuleManager.cpp +++ b/src/libcalamaresui/modulesystem/ModuleManager.cpp @@ -24,6 +24,7 @@ #include "Settings.h" #include "modulesystem/Module.h" #include "modulesystem/RequirementsChecker.h" +#include "modulesystem/RequirementsModel.h" #include "utils/Logger.h" #include "utils/Yaml.h" #include "viewpages/ExecutionViewStep.h" @@ -46,6 +47,7 @@ ModuleManager::instance() ModuleManager::ModuleManager( const QStringList& paths, QObject* parent ) : QObject( parent ) , m_paths( paths ) + , m_requirementsModel( new RequirementsModel( this ) ) { Q_ASSERT( !s_instance ); s_instance = this; @@ -355,11 +357,9 @@ ModuleManager::checkRequirements() modules[ count++ ] = module; } - RequirementsChecker* rq = new RequirementsChecker( modules, this ); - connect( rq, &RequirementsChecker::requirementsResult, this, &ModuleManager::requirementsResult ); - connect( rq, &RequirementsChecker::requirementsComplete, this, &ModuleManager::requirementsComplete ); - connect( rq, &RequirementsChecker::requirementsProgress, this, &ModuleManager::requirementsProgress ); + RequirementsChecker* rq = new RequirementsChecker( modules, m_requirementsModel, this ); connect( rq, &RequirementsChecker::done, rq, &RequirementsChecker::deleteLater ); + connect( rq, &RequirementsChecker::done, this, [=](){ this->requirementsComplete( m_requirementsModel->satisfiedMandatory() ); } ); QTimer::singleShot( 0, rq, &RequirementsChecker::run ); } diff --git a/src/libcalamaresui/modulesystem/ModuleManager.h b/src/libcalamaresui/modulesystem/ModuleManager.h index fdb63cd87..0c8a4bdaf 100644 --- a/src/libcalamaresui/modulesystem/ModuleManager.h +++ b/src/libcalamaresui/modulesystem/ModuleManager.h @@ -32,7 +32,7 @@ namespace Calamares { class Module; -struct RequirementEntry; // from Requirement.h +class RequirementsModel; /** * @brief The ModuleManager class is a singleton which manages Calamares modules. @@ -87,18 +87,19 @@ public: /** * @brief Starts asynchronous requirements checking for each module. - * When this is done, the signal modulesChecked is emitted. + * 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: void initDone(); void modulesLoaded(); /// All of the modules were loaded successfully void modulesFailed( QStringList ); /// .. or not // Below, see RequirementsChecker documentation void requirementsComplete( bool ); - void requirementsResult( RequirementsList ); - void requirementsProgress( const QString& ); private slots: void doInit(); @@ -130,6 +131,7 @@ private: QMap< QString, QString > m_moduleDirectoriesByModuleName; QMap< ModuleSystem::InstanceKey, Module* > m_loadedModulesByInstanceKey; const QStringList m_paths; + RequirementsModel* m_requirementsModel; static ModuleManager* s_instance; }; diff --git a/src/modules/localeq/CMakeLists.txt b/src/modules/localeq/CMakeLists.txt index ff5292f3a..280c95c62 100644 --- a/src/modules/localeq/CMakeLists.txt +++ b/src/modules/localeq/CMakeLists.txt @@ -6,6 +6,17 @@ if( DEBUG_TIMEZONES ) add_definitions( -DDEBUG_TIMEZONES ) endif() +find_package(Qt5Location CONFIG) +set_package_properties(Qt5Location PROPERTIES + DESCRIPTION "Used for rendering the map" + TYPE RUNTIME +) +find_package(Qt5Positioning CONFIG) +set_package_properties(Qt5Positioning PROPERTIES + DESCRIPTION "Used for GeoLocation and GeoCoding" + TYPE RUNTIME +) + # Because we're sharing sources with the regular locale module set( _locale ${CMAKE_CURRENT_SOURCE_DIR}/../locale ) diff --git a/src/modules/localeq/Map.qml b/src/modules/localeq/Map.qml new file mode 100644 index 000000000..023de6d1b --- /dev/null +++ b/src/modules/localeq/Map.qml @@ -0,0 +1,243 @@ +/* === This file is part of Calamares - === + * + * Copyright 2020, Anke Boersma + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +import QtQuick 2.10 +import QtQuick.Controls 2.10 +import QtQuick.Window 2.14 +import QtQuick.Layouts 1.3 + +import org.kde.kirigami 2.7 as Kirigami + +import QtLocation 5.14 +import QtPositioning 5.14 + +Column { + width: parent.width + + //Needs to come from .conf/geoip + property var configCity: "New York" + property var configCountry: "USA" + property var configTimezone: "America/New York" + property var geoipCity: "" //"Amsterdam" + property var geoipCountry: "" //"Netherlands" + property var geoipTimezone: "" //"Europe/Amsterdam" + // vars that will stay once connected + property var cityName: (geoipCity != "") ? geoipCity : configCity + property var countryName: (geoipCountry != "") ? geoipCountry : configCountry + property var timeZone: (geoipTimezone != "") ? geoipTimezone : configTimezone + + function getIp() { + var xhr = new XMLHttpRequest + + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + var responseJSON = JSON.parse(xhr.responseText) + var tz = responseJSON.timezone + var ct = responseJSON.city + var cy = responseJSON.country + + tzText.text = "Timezone: " + tz + cityName = ct + countryName = cy + } + } + + // Define the target of the request + xhr.open("GET", "https://get.geojs.io/v1/ip/geo.json") + // Execute the request + xhr.send() + } + + function getTz() { + var xhr = new XMLHttpRequest + var latC = map.center.latitude + var lonC = map.center.longitude + + xhr.onreadystatechange = function() { + if (xhr.readyState === XMLHttpRequest.DONE) { + var responseJSON = JSON.parse(xhr.responseText) + var tz2 = responseJSON.timezoneId + + tzText.text = "Timezone: " + tz2 + } + } + + // Needs to move to localeq.conf, each distribution will need their own account + xhr.open("GET", "http://api.geonames.org/timezoneJSON?lat=" + latC + "&lng=" + lonC + "&username=SOME_USERNAME") + xhr.send() + } + + Rectangle { + width: parent.width + height: parent.height / 1.28 + + Plugin { + id: mapPlugin + name: "esri" // "esri", "here", "itemsoverlay", "mapbox", "mapboxgl", "osm" + } + + Map { + id: map + anchors.fill: parent + plugin: mapPlugin + activeMapType: supportedMapTypes[0] + //might be desirable to set zoom level configurable? + zoomLevel: 5 + bearing: 0 + tilt: 0 + copyrightsVisible : true + fieldOfView : 0 + + GeocodeModel { + id: geocodeModel + plugin: mapPlugin + autoUpdate: true + query: Address { + id: address + city: cityName + country: countryName + } + + onLocationsChanged: { + if (count == 1) { + map.center.latitude = get(0).coordinate.latitude + map.center.longitude = get(0).coordinate.longitude + } + } + } + + MapQuickItem { + id: marker + anchorPoint.x: image.width/4 + anchorPoint.y: image.height + coordinate: QtPositioning.coordinate( + map.center.latitude, + map.center.longitude) + //coordinate: QtPositioning.coordinate(40.730610, -73.935242) // New York + + sourceItem: Image { + id: image + width: 32 + height: 32 + source: "img/pin.svg" + } + } + + MouseArea { + acceptedButtons: Qt.LeftButton + anchors.fill: map + hoverEnabled: true + property var coordinate: map.toCoordinate(Qt.point(mouseX, mouseY)) + Label { + x: parent.mouseX - width + y: parent.mouseY - height - 5 + text: "%1, %2".arg( + parent.coordinate.latitude).arg(parent.coordinate.longitude) + } + + onClicked: { + marker.coordinate = coordinate + map.center.latitude = coordinate.latitude + map.center.longitude = coordinate.longitude + + getTz(); + + console.log(coordinate.latitude, coordinate.longitude) + } + } + } + + Column { + anchors.bottom: parent.bottom + anchors.right: parent.right + anchors.bottomMargin: 5 + anchors.rightMargin: 10 + + MouseArea { + width: 32 + height:32 + cursorShape: Qt.PointingHandCursor + Image { + source: "img/plus.png" + anchors.centerIn: parent + width: 36 + height: 36 + } + + onClicked: map.zoomLevel++ + } + + MouseArea { + width: 32 + height:32 + cursorShape: Qt.PointingHandCursor + Image { + source: "img/minus.png" + anchors.centerIn: parent + width: 32 + height: 32 + } + + onClicked: map.zoomLevel-- + } + } + } + + Rectangle { + width: parent.width + height: 100 + anchors.horizontalCenter: parent.horizontalCenter + + Item { + id: location + Kirigami.Theme.inherit: false + Kirigami.Theme.colorSet: Kirigami.Theme.Complementary + anchors.horizontalCenter: parent.horizontalCenter + + Rectangle { + anchors.centerIn: parent + width: 300 + height: 30 + color: Kirigami.Theme.backgroundColor + + Text { + id: tzText + text: tzText.text + //text: qsTr("Timezone: %1").arg(timeZone) + color: Kirigami.Theme.textColor + anchors.centerIn: parent + } + + Component.onCompleted: getIp(); + } + } + + Text { + anchors.top: location.bottom + anchors.topMargin: 20 + padding: 10 + width: parent.width + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + Kirigami.Theme.backgroundColor: Kirigami.Theme.backgroundColor + text: qsTr("Please select your preferred location on the map so the installer can suggest the locale + and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging + to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming.") + } + } +} diff --git a/src/modules/localeq/Offline.qml b/src/modules/localeq/Offline.qml new file mode 100644 index 000000000..8e9d91280 --- /dev/null +++ b/src/modules/localeq/Offline.qml @@ -0,0 +1,80 @@ +/* === This file is part of Calamares - === + * + * Copyright 2020, Anke Boersma + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +import QtQuick 2.10 +import QtQuick.Controls 2.10 +import QtQuick.Window 2.14 +import QtQuick.Layouts 1.3 + +import org.kde.kirigami 2.7 as Kirigami + +Column { + width: parent.width + + //Needs to come from localeq.conf + property var configTimezone: "America/New York" + + Rectangle { + width: parent.width + height: parent.height / 1.28 + + Image { + id: image + anchors.fill: parent + source: "img/worldmap.png" + width: parent.width + } + } + + Rectangle { + width: parent.width + height: 100 + anchors.horizontalCenter: parent.horizontalCenter + + Item { + id: location + Kirigami.Theme.inherit: false + Kirigami.Theme.colorSet: Kirigami.Theme.Complementary + anchors.horizontalCenter: parent.horizontalCenter + + Rectangle { + anchors.centerIn: parent + width: 300 + height: 30 + color: Kirigami.Theme.backgroundColor + + Text { + text: qsTr("Timezone: %1").arg(configTimezone) + color: Kirigami.Theme.textColor + anchors.centerIn: parent + } + } + } + + Text { + anchors.top: location.bottom + anchors.topMargin: 20 + padding: 10 + width: parent.width + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + Kirigami.Theme.backgroundColor: Kirigami.Theme.backgroundColor + text: qsTr("To be able to select a timezone, make sure you are connected to the internet. Restart the installer after connecting. You can fine-tune Language and Locale settings below.") + } + } +} diff --git a/src/modules/localeq/i18n.qml b/src/modules/localeq/i18n.qml new file mode 100644 index 000000000..a806d0174 --- /dev/null +++ b/src/modules/localeq/i18n.qml @@ -0,0 +1,189 @@ +/* === This file is part of Calamares - === + * + * Copyright 2020, Anke Boersma + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + +import io.calamares.ui 1.0 + +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +import org.kde.kirigami 2.7 as Kirigami + +Item { + width: parent.width + height: parent.height + focus: true + MouseArea { + anchors.fill: parent + } + + //Needs to come from Locale config + property var confLang: "en_US.UTF8" + property var confLocale: "nl_NL.UTF8" + + Rectangle { + id: textArea + x: 28 + y: 14 + anchors.fill: parent + Kirigami.Theme.backgroundColor: Kirigami.Theme.backgroundColor + + Column { + id: languages + x: 130 + y: 40 + + Rectangle { + width: 250 + height: 140 + color: "#d3d3d3" + Text { + anchors.top: parent.top + width: 240 + wrapMode: Text.WordWrap + text: qsTr("

Languages


+ The system locale setting affects the language and character set for some command line user interface elements. The current setting is %1.").arg(confLang) + font.pointSize: 10 + } + } + + Rectangle { + width: 250 + height: 300 + + ScrollView { + id: scroll1 + anchors.fill: parent + contentHeight: 800 + clip: true + + ListView { + id: list1 + focus: true + + // bogus entries, need to come from Locale config + model: ["en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8"] + + currentIndex: 1 + highlight: Rectangle { + color: Kirigami.Theme.highlightColor + } + delegate: Text { + text: modelData + + MouseArea { + hoverEnabled: true + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onEntered: { + color: "#0000ff" + } + onClicked: { + list1.currentIndex = index + confLang = list1.currentIndex + } + } + } + } + } + } + } + + Column { + id: i18n + x: 430 + y: 40 + + Rectangle { + width: 250 + height: 140 + color: "#d3d3d3" + Text { + anchors.top: parent.top + width: 240 + wrapMode: Text.WordWrap + text: qsTr("

Locales


+ The system locale setting affects the language and character set for some command line user interface elements. The current setting is %1.").arg(confLocale) + font.pointSize: 10 + } + } + + Rectangle { + width: 250 + height: 300 + + ScrollView { + id: scroll2 + anchors.fill: parent + contentHeight: 800 + clip: true + + ListView { + id: list2 + width: 180; height: 200 + focus: true + + // bogus entries, need to come from Locale config + model: ["en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8", "en_GB.UTF-8 UTF-8", "en_US.UTF-8 UTF-8 ", "nl_NL.UTF-8 UTF-8"] + + currentIndex: 2 + highlight: Rectangle { + color: Kirigami.Theme.highlightColor + } + delegate: Text { + text: modelData + + MouseArea { + hoverEnabled: true + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: { + list2.currentIndex = index + confLocale = list1.currentIndex + } + } + } + onCurrentItemChanged: console.debug(currentIndex) + } + } + } + + } + + ToolButton { + id: toolButton + x: 19 + y: 29 + width: 105 + height: 48 + text: qsTr("Back") + hoverEnabled: true + onClicked: load.source = "" + + Image { + id: image1 + x: 0 + y: 13 + width: 22 + height: 22 + source: "img/chevron-left-solid.svg" + fillMode: Image.PreserveAspectFit + } + } + } +} diff --git a/src/modules/localeq/img/chevron-left-solid.svg b/src/modules/localeq/img/chevron-left-solid.svg new file mode 100644 index 000000000..41061c287 --- /dev/null +++ b/src/modules/localeq/img/chevron-left-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/modules/localeq/img/minus.png b/src/modules/localeq/img/minus.png new file mode 100644 index 000000000..be122dff2 Binary files /dev/null and b/src/modules/localeq/img/minus.png differ diff --git a/src/modules/localeq/img/pin.svg b/src/modules/localeq/img/pin.svg new file mode 100644 index 000000000..b4185d1af --- /dev/null +++ b/src/modules/localeq/img/pin.svg @@ -0,0 +1,60 @@ + +image/svg+xml + + \ No newline at end of file diff --git a/src/modules/localeq/img/plus.png b/src/modules/localeq/img/plus.png new file mode 100644 index 000000000..3bd5d832c Binary files /dev/null and b/src/modules/localeq/img/plus.png differ diff --git a/src/modules/localeq/img/worldmap.png b/src/modules/localeq/img/worldmap.png new file mode 100644 index 000000000..c5c181985 Binary files /dev/null and b/src/modules/localeq/img/worldmap.png differ diff --git a/src/modules/localeq/localeq.qml b/src/modules/localeq/localeq.qml index 0e00d1b1b..0abdebfc9 100644 --- a/src/modules/localeq/localeq.qml +++ b/src/modules/localeq/localeq.qml @@ -1,3 +1,22 @@ +/* === This file is part of Calamares - === + * + * Copyright 2020, Adriaan de Groot + * Copyright 2020, Anke Boersma + * + * Calamares is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Calamares is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Calamares. If not, see . + */ + import io.calamares.core 1.0 import io.calamares.ui 1.0 @@ -5,35 +24,77 @@ import QtQuick 2.10 import QtQuick.Controls 2.10 import QtQuick.Layouts 1.3 import org.kde.kirigami 2.7 as Kirigami -import QtGraphicalEffects 1.0 -RowLayout -{ - Rectangle { - width: parent.width / 3 - Layout.fillWidth: true - ColumnLayout { - id: regions - Repeater { - model: config.regionModel - Text { - text: label - } - } - } +Page { + width: 800 + height: 550 + + property var confLang: "American English" + property var confLocale: "Nederland" + //Needs to come from .conf/geoip + property var hasInternet: true + + Loader { + id: image + anchors.horizontalCenter: parent.horizontalCenter + width: parent.width + height: parent.height / 1.28 + source: (hasInternet) ? "Map.qml" : "Offline.qml" } - Rectangle { - width: parent.width / 3 - Layout.fillWidth: true - ColumnLayout { - id: zones - ListView { - model: config.zonesModel - delegate: Text { - text: label + + RowLayout { + anchors.bottom: parent.bottom + anchors.bottomMargin : 20 + width: parent.width + + Kirigami.FormLayout { + id: lang + + GridLayout { + anchors { + left: parent.left + top: parent.top + right: parent.right + } + rowSpacing: Kirigami.Units.largeSpacing + columnSpacing: Kirigami.Units.largeSpacing + + Kirigami.Icon { + source: "application-x-gettext-translation" + Layout.fillHeight: true + Layout.maximumHeight: Kirigami.Units.iconSizes.medium + Layout.preferredWidth: height + } + ColumnLayout { + Label { + Layout.fillWidth: true + wrapMode: Text.WordWrap + text: qsTr("System language set to %1").arg(confLang) + } + Kirigami.Separator { + Layout.fillWidth: true + } + Label { + Layout.fillWidth: true + wrapMode: Text.WordWrap + text: qsTr("Numbers and dates locale set to %1").arg(confLocale) + } + } + Button { + Layout.alignment: Qt.AlignRight|Qt.AlignVCenter + Layout.columnSpan: 2 + text: qsTr("Change") + //onClicked: console.log("Adjust Language clicked"); + onClicked: { + onClicked: load.source = "i18n.qml" + } } } } + + } + Loader { + id:load + anchors.fill: parent } } - diff --git a/src/modules/localeq/localeq.qrc b/src/modules/localeq/localeq.qrc index e2bf12636..591b83452 100644 --- a/src/modules/localeq/localeq.qrc +++ b/src/modules/localeq/localeq.qrc @@ -1,47 +1,13 @@ - - ../locale/images/bg.png - ../locale/images/pin.png - ../locale/images/timezone_0.0.png - ../locale/images/timezone_1.0.png - ../locale/images/timezone_2.0.png - ../locale/images/timezone_3.0.png - ../locale/images/timezone_3.5.png - ../locale/images/timezone_4.0.png - ../locale/images/timezone_4.5.png - ../locale/images/timezone_5.0.png - ../locale/images/timezone_5.5.png - ../locale/images/timezone_5.75.png - ../locale/images/timezone_6.0.png - ../locale/images/timezone_6.5.png - ../locale/images/timezone_7.0.png - ../locale/images/timezone_8.0.png - ../locale/images/timezone_9.0.png - ../locale/images/timezone_9.5.png - ../locale/images/timezone_10.0.png - ../locale/images/timezone_10.5.png - ../locale/images/timezone_11.0.png - ../locale/images/timezone_11.5.png - ../locale/images/timezone_12.0.png - ../locale/images/timezone_12.75.png - ../locale/images/timezone_13.0.png - ../locale/images/timezone_-1.0.png - ../locale/images/timezone_-2.0.png - ../locale/images/timezone_-3.0.png - ../locale/images/timezone_-3.5.png - ../locale/images/timezone_-4.0.png - ../locale/images/timezone_-4.5.png - ../locale/images/timezone_-5.0.png - ../locale/images/timezone_-5.5.png - ../locale/images/timezone_-6.0.png - ../locale/images/timezone_-7.0.png - ../locale/images/timezone_-8.0.png - ../locale/images/timezone_-9.0.png - ../locale/images/timezone_-9.5.png - ../locale/images/timezone_-10.0.png - ../locale/images/timezone_-11.0.png - + i18n.qml localeq.qml + Map.qml + Offline.qml + img/minus.png + img/pin.svg + img/plus.png + img/chevron-left-solid.svg + img/worldmap.png diff --git a/src/modules/welcome/Config.cpp b/src/modules/welcome/Config.cpp index 8ca20af7e..71d6de9bb 100644 --- a/src/modules/welcome/Config.cpp +++ b/src/modules/welcome/Config.cpp @@ -22,6 +22,7 @@ #include "Settings.h" #include "geoip/Handler.h" #include "locale/Lookup.h" +#include "modulesystem/ModuleManager.h" #include "utils/Logger.h" #include "utils/Retranslator.h" #include "utils/Variant.h" @@ -30,14 +31,8 @@ Config::Config( QObject* parent ) : QObject( parent ) - , m_requirementsModel( new Calamares::RequirementsModel( this ) ) , m_languages( CalamaresUtils::Locale::availableTranslations() ) { - connect( m_requirementsModel, - &Calamares::RequirementsModel::satisfiedRequirementsChanged, - this, - &Config::setIsNextEnabled ); - initLanguages(); CALAMARES_RETRANSLATE_SLOT( &Config::retranslate ) @@ -49,12 +44,13 @@ Config::retranslate() m_genericWelcomeMessage = genericWelcomeMessage().arg( Calamares::Branding::instance()->versionedName() ); emit genericWelcomeMessageChanged( m_genericWelcomeMessage ); - if ( !m_requirementsModel->satisfiedRequirements() ) + const auto* r = requirementsModel(); + if ( !r->satisfiedRequirements() ) { QString message; const bool setup = Calamares::Settings::instance()->isSetupMode(); - if ( !m_requirementsModel->satisfiedMandatory() ) + if ( !r->satisfiedMandatory() ) { message = setup ? tr( "This computer does not satisfy the minimum " "requirements for setting up %1.
" @@ -95,6 +91,13 @@ Config::languagesModel() const return m_languages; } +Calamares::RequirementsModel* +Config::requirementsModel() const +{ + return Calamares::ModuleManager::instance()->requirementsModel(); +} + + QString Config::languageIcon() const { @@ -183,12 +186,6 @@ Config::setLocaleIndex( int index ) emit localeIndexChanged( m_localeIndex ); } -Calamares::RequirementsModel& -Config::requirementsModel() const -{ - return *m_requirementsModel; -} - void Config::setIsNextEnabled( bool isNextEnabled ) { diff --git a/src/modules/welcome/Config.h b/src/modules/welcome/Config.h index 0123482f3..7fe6fa04e 100644 --- a/src/modules/welcome/Config.h +++ b/src/modules/welcome/Config.h @@ -20,7 +20,6 @@ #define WELCOME_CONFIG_H #include "locale/LabelModel.h" -#include "modulesystem/Requirement.h" #include "modulesystem/RequirementsModel.h" #include @@ -30,7 +29,7 @@ class Config : public QObject { Q_OBJECT Q_PROPERTY( CalamaresUtils::Locale::LabelModel* languagesModel READ languagesModel CONSTANT FINAL ) - Q_PROPERTY( Calamares::RequirementsModel* requirementsModel MEMBER m_requirementsModel CONSTANT FINAL ) + Q_PROPERTY( Calamares::RequirementsModel* requirementsModel READ requirementsModel CONSTANT FINAL ) Q_PROPERTY( QString languageIcon READ languageIcon CONSTANT FINAL ) @@ -52,8 +51,6 @@ public: void setConfigurationMap( const QVariantMap& ); - Calamares::RequirementsModel& requirementsModel() const; - void setCountryCode( const QString& countryCode ); QString languageIcon() const; @@ -83,6 +80,9 @@ public slots: CalamaresUtils::Locale::LabelModel* languagesModel() const; void retranslate(); + ///@brief The **global** requirements model, from ModuleManager + Calamares::RequirementsModel* requirementsModel() const; + signals: void countryCodeChanged( QString countryCode ); void localeIndexChanged( int localeIndex ); @@ -99,7 +99,6 @@ signals: private: void initLanguages(); - Calamares::RequirementsModel* m_requirementsModel; CalamaresUtils::Locale::LabelModel* m_languages; QString m_languageIcon; diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp index dc955613c..0c4f44c95 100644 --- a/src/modules/welcome/WelcomePage.cpp +++ b/src/modules/welcome/WelcomePage.cpp @@ -31,6 +31,7 @@ #include "locale/LabelModel.h" #include "modulesystem/ModuleManager.h" +#include "modulesystem/RequirementsModel.h" #include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" #include "utils/NamedEnum.h" @@ -47,7 +48,7 @@ WelcomePage::WelcomePage( Config* conf, QWidget* parent ) : QWidget( parent ) , ui( new Ui::WelcomePage ) - , m_checkingWidget( new CheckerContainer( conf->requirementsModel(), this ) ) + , m_checkingWidget( new CheckerContainer( *(conf->requirementsModel()), this ) ) , m_languages( nullptr ) , m_conf( conf ) { @@ -90,8 +91,8 @@ WelcomePage::WelcomePage( Config* conf, QWidget* parent ) &Calamares::ModuleManager::requirementsComplete, m_checkingWidget, &CheckerContainer::requirementsComplete ); - connect( Calamares::ModuleManager::instance(), - &Calamares::ModuleManager::requirementsProgress, + connect( Calamares::ModuleManager::instance()->requirementsModel(), + &Calamares::RequirementsModel::progressMessageChanged, m_checkingWidget, &CheckerContainer::requirementsProgress ); } diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index e4e56c44c..cad5349a9 100644 --- a/src/modules/welcome/WelcomeViewStep.cpp +++ b/src/modules/welcome/WelcomeViewStep.cpp @@ -32,16 +32,14 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeViewStepFactory, registerPlugin< Wel WelcomeViewStep::WelcomeViewStep( QObject* parent ) : Calamares::ViewStep( parent ) - , m_requirementsChecker( new GeneralRequirements( this ) ) , m_conf( new Config( this ) ) + , m_widget( new WelcomePage( m_conf ) ) + , m_requirementsChecker( new GeneralRequirements( this ) ) { connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsComplete, this, &WelcomeViewStep::nextStatusChanged ); - - // the instance of the qqc2 or qwidgets page - m_widget = new WelcomePage( m_conf ); connect( m_conf, &Config::localeIndexChanged, m_widget, &WelcomePage::externallySelectedLanguage ); } @@ -111,12 +109,12 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap ) && configurationMap.value( "requirements" ).type() == QVariant::Map ) { m_requirementsChecker->setConfigurationMap( configurationMap.value( "requirements" ).toMap() ); - - m_conf->requirementsModel().setRequirementsList( checkRequirements() ); } else + { cWarning() << "no valid requirements map found in welcome " "module configuration."; + } //here init the qml or qwidgets needed bits m_widget->init(); diff --git a/src/modules/welcome/WelcomeViewStep.h b/src/modules/welcome/WelcomeViewStep.h index 3265395fc..f4874dc16 100644 --- a/src/modules/welcome/WelcomeViewStep.h +++ b/src/modules/welcome/WelcomeViewStep.h @@ -73,9 +73,9 @@ public: Calamares::RequirementsList checkRequirements() override; private: + Config* m_conf; WelcomePage* m_widget; GeneralRequirements* m_requirementsChecker; - Config* m_conf; }; CALAMARES_PLUGIN_FACTORY_DECLARATION( WelcomeViewStepFactory ) diff --git a/src/modules/welcome/checker/CheckerContainer.cpp b/src/modules/welcome/checker/CheckerContainer.cpp index 53e65fa04..11ae9c7c3 100644 --- a/src/modules/welcome/checker/CheckerContainer.cpp +++ b/src/modules/welcome/checker/CheckerContainer.cpp @@ -55,6 +55,17 @@ CheckerContainer::~CheckerContainer() void CheckerContainer::requirementsComplete( bool ok ) { + if ( !ok ) + { + cDebug() << "Requirements not satisfied" << m_model.count() << "entries:"; + for ( int i = 0; i < m_model.count(); ++i ) + { + auto index = m_model.index( i ); + cDebug() << Logger::SubEntry << i << m_model.data( index, Calamares::RequirementsModel::Name ).toString() + << "set?" << m_model.data( index, Calamares::RequirementsModel::Satisfied ).toBool() << "req?" + << m_model.data( index, Calamares::RequirementsModel::Mandatory ).toBool(); + } + } layout()->removeWidget( m_waitingWidget ); m_waitingWidget->deleteLater(); diff --git a/src/modules/welcome/checker/GeneralRequirements.cpp b/src/modules/welcome/checker/GeneralRequirements.cpp index fc9fe5ce6..f30950da2 100644 --- a/src/modules/welcome/checker/GeneralRequirements.cpp +++ b/src/modules/welcome/checker/GeneralRequirements.cpp @@ -70,16 +70,49 @@ biggestSingleScreen() return s; } +/** @brief Distinguish has-not-been-checked-at-all from false. + * + */ +struct MaybeChecked +{ + bool hasBeenChecked = false; + bool value = false; + + MaybeChecked& operator=( bool b ) + { + cDebug() << "Assigning" << b; + hasBeenChecked = true; + value = b; + return *this; + } + + operator bool() const { return value; } +}; + +QDebug& +operator<<( QDebug& s, const MaybeChecked& c ) +{ + if ( c.hasBeenChecked ) + { + s << c.value; + } + else + { + s << "unchecked"; + } + return s; +} + Calamares::RequirementsList GeneralRequirements::checkRequirements() { QSize availableSize = biggestSingleScreen(); - bool enoughStorage = false; - bool enoughRam = false; - bool hasPower = false; - bool hasInternet = false; - bool isRoot = false; + MaybeChecked enoughStorage; + MaybeChecked enoughRam; + MaybeChecked hasPower; + MaybeChecked hasInternet; + MaybeChecked isRoot; bool enoughScreen = availableSize.isValid() && ( availableSize.width() >= CalamaresUtils::windowMinimumWidth ) && ( availableSize.height() >= CalamaresUtils::windowMinimumHeight ); @@ -112,7 +145,7 @@ GeneralRequirements::checkRequirements() isRoot = checkIsRoot(); } - using TR = Logger::DebugRow< const char*, bool >; + using TR = Logger::DebugRow< const char*, MaybeChecked >; cDebug() << "GeneralRequirements output:" << TR( "enoughStorage", enoughStorage ) << TR( "enoughRam", enoughRam ) << TR( "hasPower", hasPower ) << TR( "hasInternet", hasInternet ) << TR( "isRoot", isRoot ); diff --git a/src/modules/welcome/checker/ResultsListWidget.cpp b/src/modules/welcome/checker/ResultsListWidget.cpp index 2554f907b..afde9f08d 100644 --- a/src/modules/welcome/checker/ResultsListWidget.cpp +++ b/src/modules/welcome/checker/ResultsListWidget.cpp @@ -48,27 +48,29 @@ static void createResultWidgets( QLayout* layout, QList< ResultWidget* >& resultWidgets, const Calamares::RequirementsModel& model, - std::function< bool( const Calamares::RequirementEntry& ) > predicate ) + std::function< bool( const Calamares::RequirementsModel&, QModelIndex ) > predicate ) { resultWidgets.clear(); resultWidgets.reserve( model.count() ); for ( auto i = 0; i < model.count(); i++ ) { - const auto& entry = model.getEntry( i ); - if ( !predicate( entry ) ) + const auto& index = model.index( i ); + if ( !predicate( model, index ) ) { resultWidgets.append( nullptr ); continue; } - ResultWidget* ciw = new ResultWidget( entry.satisfied, entry.mandatory ); + const bool is_satisfied = model.data( index, Calamares::RequirementsModel::Satisfied ).toBool(); + const bool is_mandatory = model.data( index, Calamares::RequirementsModel::Mandatory ).toBool(); + ResultWidget* ciw = new ResultWidget( is_satisfied, is_mandatory ); layout->addWidget( ciw ); ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); ciw->setAutoFillBackground( true ); QPalette pal( ciw->palette() ); QColor bgColor = pal.window().color(); - int bgHue = ( entry.satisfied ) ? bgColor.hue() : ( entry.mandatory ) ? 0 : 60; + int bgHue = ( is_satisfied ) ? bgColor.hue() : ( is_mandatory ) ? 0 : 60; bgColor.setHsv( bgHue, 64, bgColor.value() ); pal.setColor( QPalette::Window, bgColor ); ciw->setPalette( pal ); @@ -114,7 +116,9 @@ ResultsListDialog::ResultsListDialog( const Calamares::RequirementsModel& model, m_title = new QLabel( this ); createResultWidgets( - entriesLayout, m_resultWidgets, model, []( const Calamares::RequirementEntry& e ) { return e.hasDetails(); } ); + entriesLayout, m_resultWidgets, model, []( const Calamares::RequirementsModel& m, QModelIndex i ) { + return m.data( i, Calamares::RequirementsModel::HasDetails ).toBool(); + } ); QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Close, Qt::Horizontal, this ); @@ -130,7 +134,7 @@ ResultsListDialog::ResultsListDialog( const Calamares::RequirementsModel& model, retranslate(); // Do it now to fill in the texts } -ResultsListDialog::~ResultsListDialog() { } +ResultsListDialog::~ResultsListDialog() {} void ResultsListDialog::retranslate() @@ -140,10 +144,10 @@ ResultsListDialog::retranslate() for ( auto i = 0; i < m_model.count(); i++ ) { - const auto& entry = m_model.getEntry( i ); if ( m_resultWidgets[ i ] ) { - m_resultWidgets[ i ]->setText( entry.enumerationText() ); + m_resultWidgets[ i ]->setText( + m_model.data( m_model.index( i ), Calamares::RequirementsModel::Details ).toString() ); } } } @@ -180,7 +184,9 @@ ResultsListWidget::ResultsListWidget( const Calamares::RequirementsModel& model, // all *mandatory* entries are satisfied (gives errors if not). const bool requirementsSatisfied = m_model.satisfiedRequirements(); - auto isUnSatisfied = []( const Calamares::RequirementEntry& e ) { return !e.satisfied; }; + auto isUnSatisfied = []( const Calamares::RequirementsModel& m, QModelIndex i ) { + return !m.data( i, Calamares::RequirementsModel::Satisfied ).toBool(); + }; createResultWidgets( entriesLayout, m_resultWidgets, model, isUnSatisfied ); @@ -240,10 +246,10 @@ ResultsListWidget::retranslate() { for ( auto i = 0; i < m_model.count(); i++ ) { - const auto& entry = m_model.getEntry( i ); if ( m_resultWidgets[ i ] ) { - m_resultWidgets[ i ]->setText( entry.negatedText() ); + m_resultWidgets[ i ]->setText( + m_model.data( m_model.index( i ), Calamares::RequirementsModel::NegatedText ).toString() ); } } diff --git a/src/modules/welcomeq/WelcomeQmlViewStep.cpp b/src/modules/welcomeq/WelcomeQmlViewStep.cpp index 4869673bb..42944f20d 100644 --- a/src/modules/welcomeq/WelcomeQmlViewStep.cpp +++ b/src/modules/welcomeq/WelcomeQmlViewStep.cpp @@ -22,9 +22,9 @@ #include "checker/GeneralRequirements.h" #include "locale/LabelModel.h" +#include "utils/Dirs.h" #include "utils/Logger.h" #include "utils/Variant.h" -#include "utils/Dirs.h" #include "Branding.h" #include "modulesystem/ModuleManager.h" @@ -33,62 +33,57 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeQmlViewStepFactory, registerPlugin< WelcomeQmlViewStep >(); ) WelcomeQmlViewStep::WelcomeQmlViewStep( QObject* parent ) -: Calamares::QmlViewStep(parent ) - , m_config( new Config( this ) ) // the qml singleton takes ownership and deletes it -// , m_nextEnabled( false ) + : Calamares::QmlViewStep( parent ) + , m_config( new Config( this ) ) , m_requirementsChecker( new GeneralRequirements( this ) ) - { -// connect( m_config, -// &Config::isNextEnabledChanged, -// this, -// &WelcomeQmlViewStep::nextStatusChanged ); -// emit nextStatusChanged(true); + connect( Calamares::ModuleManager::instance(), + &Calamares::ModuleManager::requirementsComplete, + this, + &WelcomeQmlViewStep::nextStatusChanged ); } QString WelcomeQmlViewStep::prettyName() const { - return tr( "Welcome" ); + return tr( "Welcome" ); } bool WelcomeQmlViewStep::isNextEnabled() const { - // TODO: should return true -// return m_config->property("isNextEnabled").toBool(); - return true; + return m_config->requirementsModel()->satisfiedMandatory(); } bool WelcomeQmlViewStep::isBackEnabled() const { - // TODO: should return true (it's weird that you are not allowed to have welcome *after* anything - return false; + // TODO: should return true (it's weird that you are not allowed to have welcome *after* anything + return false; } bool WelcomeQmlViewStep::isAtBeginning() const { - // TODO: adjust to "pages" in the QML - return true; + // TODO: adjust to "pages" in the QML + return true; } bool WelcomeQmlViewStep::isAtEnd() const { - // TODO: adjust to "pages" in the QML - return true; + // TODO: adjust to "pages" in the QML + return true; } Calamares::JobList WelcomeQmlViewStep::jobs() const { - return Calamares::JobList(); + return Calamares::JobList(); } void @@ -96,32 +91,29 @@ WelcomeQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap ) { m_config->setConfigurationMap( configurationMap ); - // TODO: figure out how the requirements (held by ModuleManager) should be accessible - // to QML as a model. //will be model as a qvariantmap containing a alert level and the message string - if ( configurationMap.contains( "requirements" ) - && configurationMap.value( "requirements" ).type() == QVariant::Map ) - { - m_requirementsChecker->setConfigurationMap( configurationMap.value( "requirements" ).toMap() ); + if ( configurationMap.contains( "requirements" ) + && configurationMap.value( "requirements" ).type() == QVariant::Map ) + { + m_requirementsChecker->setConfigurationMap( configurationMap.value( "requirements" ).toMap() ); + } + else + { + cWarning() << "no valid requirements map found in welcomeq " + "module configuration."; + } - m_config->requirementsModel().setRequirementsList( checkRequirements() ); - } - else - cWarning() << "no valid requirements map found in welcome " - "module configuration."; - - Calamares::QmlViewStep::setConfigurationMap( configurationMap ); // call parent implementation last + Calamares::QmlViewStep::setConfigurationMap( configurationMap ); // call parent implementation last setContextProperty( "Welcome", m_config ); } Calamares::RequirementsList WelcomeQmlViewStep::checkRequirements() { - return m_requirementsChecker->checkRequirements(); + return m_requirementsChecker->checkRequirements(); } QObject* WelcomeQmlViewStep::getConfig() { - return m_config; + return m_config; } - diff --git a/src/modules/welcomeq/WelcomeQmlViewStep.h b/src/modules/welcomeq/WelcomeQmlViewStep.h index 8e163083d..78999986c 100644 --- a/src/modules/welcomeq/WelcomeQmlViewStep.h +++ b/src/modules/welcomeq/WelcomeQmlViewStep.h @@ -47,7 +47,6 @@ class PLUGINDLLEXPORT WelcomeQmlViewStep : public Calamares::QmlViewStep Q_OBJECT public: - explicit WelcomeQmlViewStep( QObject* parent = nullptr ); QString prettyName() const override; @@ -74,8 +73,7 @@ public: QObject* getConfig() override; private: - // TODO: a generic QML viewstep should return a config object from a method - Config *m_config; + Config* m_config; GeneralRequirements* m_requirementsChecker; }; diff --git a/src/modules/welcomeq/welcomeq.qml b/src/modules/welcomeq/welcomeq.qml index 910274fe2..2a29c5d9a 100644 --- a/src/modules/welcomeq/welcomeq.qml +++ b/src/modules/welcomeq/welcomeq.qml @@ -60,14 +60,14 @@ Page property var required: "yes" //requirementsModel property var satisfied: "yes" //satisfiedRequirements property var requiredMet: (required != satisfied) ? true : false - visible: requiredMet + visible: !config.requirementsModel.satisfiedRequirements } Requirements { property var required: "yes" //requirementsModel property var mandatory: "yes" //satisfiedMandatory property var mandatoryMet: (required != mandatory) ? true : false - visible: mandatoryMet + visible: !config.requirementsModel.satisfiedMandatory } RowLayout {