From 34e7b06cc9d6a6518f87254f08780e8a65d3cb14 Mon Sep 17 00:00:00 2001 From: demmm Date: Sat, 9 May 2020 14:01:21 +0200 Subject: [PATCH 01/24] [localeq] move to QtLocation map based module fully implemented: * loading of a live map, ESRI based, zooming & dragging possible * IP address is translated to map coordinates * loading of the map centers to the obtained coordinates, with a marker set * coordinates are translated to a timezone, label visible at bottom of the map * mouse movement will show changing coordinates * clicking on new location will center map there, marker moved too, timezone label adjusted * hasInternet switch set to either load Map.qml or Offline.qml not done: * get hasInternet status * fill the fine-tune 181n.qml with proper locale & language data * connect the obtained timezone to globalstorage comments are left in the various files for what needs attention/changes --- src/modules/localeq/CMakeLists.txt | 11 + src/modules/localeq/Map.qml | 243 ++++++++++++++++++ src/modules/localeq/Offline.qml | 80 ++++++ src/modules/localeq/i18n.qml | 189 ++++++++++++++ .../localeq/img/chevron-left-solid.svg | 1 + src/modules/localeq/img/minus.png | Bin 0 -> 177 bytes src/modules/localeq/img/pin.svg | 60 +++++ src/modules/localeq/img/plus.png | Bin 0 -> 483 bytes src/modules/localeq/img/worldmap.png | Bin 0 -> 102062 bytes src/modules/localeq/localeq.qml | 111 ++++++-- src/modules/localeq/localeq.qrc | 50 +--- 11 files changed, 678 insertions(+), 67 deletions(-) create mode 100644 src/modules/localeq/Map.qml create mode 100644 src/modules/localeq/Offline.qml create mode 100644 src/modules/localeq/i18n.qml create mode 100644 src/modules/localeq/img/chevron-left-solid.svg create mode 100644 src/modules/localeq/img/minus.png create mode 100644 src/modules/localeq/img/pin.svg create mode 100644 src/modules/localeq/img/plus.png create mode 100644 src/modules/localeq/img/worldmap.png 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..1d46cea42 --- /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=demm") + 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 0000000000000000000000000000000000000000..be122dff24d8f51868e75d1249794d9073fcc1e4 GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGooCO|{#S9F5M?jcysy3fAP%zok z#WAE}&fAL@IU5WFSPy3Ww>>V_BO#Xh?Eiy8YmjbaP;>I*gS3779>q_qt9lo8(3a^4 tO9!Wbu!5R{Ps0obL&hYa0J3@zTP#L;AEU&El#Jsbo~Nsy%Q~loCICDuEh+#2 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3bd5d832c21a5dddebf6c0d2a3df7281259dc388 GIT binary patch literal 483 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 K!IbG=kNQ8gy&jJM literal 0 HcmV?d00001 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 From 54b211daa4b8471517c6a214123d2bbf8aede821 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 10 May 2020 17:36:04 +0200 Subject: [PATCH 02/24] CMake: switch back to kdsingleapplicationguard - Reports from downstream Manjaro that the DBus activation doesn't work at all. Switch the default back to the old way, until it can be debugged more. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8603099db..667ec2231 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 From 32ae0a7bf657b596a36b1df3143b5989fbe51c99 Mon Sep 17 00:00:00 2001 From: demmm Date: Sun, 10 May 2020 17:59:52 +0200 Subject: [PATCH 03/24] set a bogus username in Map.qml --- src/modules/localeq/Map.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/localeq/Map.qml b/src/modules/localeq/Map.qml index 1d46cea42..023de6d1b 100644 --- a/src/modules/localeq/Map.qml +++ b/src/modules/localeq/Map.qml @@ -78,7 +78,7 @@ Column { } // 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=demm") + xhr.open("GET", "http://api.geonames.org/timezoneJSON?lat=" + latC + "&lng=" + lonC + "&username=SOME_USERNAME") xhr.send() } From 616fbb08f3098fb06432de4d580652d71bc560a3 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 11:19:08 +0200 Subject: [PATCH 04/24] [libcalamares] Improve docs of RequirementsModel --- src/libcalamares/modulesystem/RequirementsModel.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/libcalamares/modulesystem/RequirementsModel.h b/src/libcalamares/modulesystem/RequirementsModel.h index 2acf785e7..b288b9d49 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.h +++ b/src/libcalamares/modulesystem/RequirementsModel.h @@ -27,7 +27,15 @@ namespace Calamares { - +/** @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 @@ -70,10 +78,9 @@ protected: QHash< int, QByteArray > roleNames() const override; private: - Calamares::RequirementsList m_requirements; + RequirementsList m_requirements; bool m_satisfiedRequirements = false; bool m_satisfiedMandatory = false; - }; } // namespace Calamares From 0f5db0ba5ed475404cd6ddd9d89c06cabbd76d96 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 11:34:02 +0200 Subject: [PATCH 05/24] [libcalamares] Remove direct access to model internals - This was just for the ResultsListWidget, which can also use normal role-based model access. --- .../modulesystem/RequirementsModel.h | 5 ---- .../welcome/checker/ResultsListWidget.cpp | 30 +++++++++++-------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/libcalamares/modulesystem/RequirementsModel.h b/src/libcalamares/modulesystem/RequirementsModel.h index b288b9d49..7722707a3 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.h +++ b/src/libcalamares/modulesystem/RequirementsModel.h @@ -59,11 +59,6 @@ public: bool satisfiedRequirements() const { return m_satisfiedRequirements; } bool satisfiedMandatory() const { return m_satisfiedMandatory; } - 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; 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() ); } } From d87d714b8dc6e9d9ffc61ebf0462888e38a57ed2 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 11:41:42 +0200 Subject: [PATCH 06/24] [libcalamares] Make the requirements model more adaptable - Either replace the list of results, or add to them - Lock model while adding rows --- .../modulesystem/RequirementsModel.cpp | 18 +++++++++++++++++- .../modulesystem/RequirementsModel.h | 10 ++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/libcalamares/modulesystem/RequirementsModel.cpp b/src/libcalamares/modulesystem/RequirementsModel.cpp index 4001d2d81..4a776b3eb 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.cpp +++ b/src/libcalamares/modulesystem/RequirementsModel.cpp @@ -24,9 +24,26 @@ namespace Calamares void RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requirements ) { + QMutexLocker l( &m_addLock ); emit beginResetModel(); m_requirements = requirements; + changeRequirementsList(); + emit endResetModel(); +} +void +RequirementsModel::addRequirementsList( const Calamares::RequirementsList& requirements ) +{ + QMutexLocker l( &m_addLock ); + emit beginResetModel(); + 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 +52,6 @@ RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requi emit satisfiedRequirementsChanged( m_satisfiedRequirements ); emit satisfiedMandatoryChanged( m_satisfiedMandatory ); - emit endResetModel(); } int diff --git a/src/libcalamares/modulesystem/RequirementsModel.h b/src/libcalamares/modulesystem/RequirementsModel.h index 7722707a3..e34dd02c2 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.h +++ b/src/libcalamares/modulesystem/RequirementsModel.h @@ -24,6 +24,7 @@ #include "DllMacro.h" #include +#include namespace Calamares { @@ -56,10 +57,15 @@ 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 Replace the entire list of requirements; resets the model void setRequirementsList( const Calamares::RequirementsList& requirements ); + ///@brief Append some requirements; resets the model + void addRequirementsList( const Calamares::RequirementsList& requirements ); QVariant data( const QModelIndex& index, int role ) const override; int rowCount( const QModelIndex& ) const override; @@ -73,6 +79,10 @@ protected: QHash< int, QByteArray > roleNames() const override; private: + ///@brief Implementation for {set,add}RequirementsList + void changeRequirementsList(); + + QMutex m_addLock; RequirementsList m_requirements; bool m_satisfiedRequirements = false; bool m_satisfiedMandatory = false; From 8306de731a84b44c0f3aac420957bba782e53393 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 14:21:57 +0200 Subject: [PATCH 07/24] [welcome] Setting requirements from own reqs is totally wrong - The requirements are collected by ModuleManager, checked by an internal RequirementsChecker and changes to the requirements state are all signalled from ModuleManager. By connecting the requirements in the welcome modules' Config only to their own configs -- and immediately checking them, which is bad on its own -- we end up with a disconnect between what the ModuleManager says about requirements, and what the welcome modules report on. --- src/modules/welcome/WelcomeViewStep.cpp | 4 ++-- src/modules/welcomeq/WelcomeQmlViewStep.cpp | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index e4e56c44c..0ed887fa9 100644 --- a/src/modules/welcome/WelcomeViewStep.cpp +++ b/src/modules/welcome/WelcomeViewStep.cpp @@ -111,12 +111,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/welcomeq/WelcomeQmlViewStep.cpp b/src/modules/welcomeq/WelcomeQmlViewStep.cpp index 4869673bb..f520a9953 100644 --- a/src/modules/welcomeq/WelcomeQmlViewStep.cpp +++ b/src/modules/welcomeq/WelcomeQmlViewStep.cpp @@ -102,8 +102,6 @@ WelcomeQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap ) && configurationMap.value( "requirements" ).type() == QVariant::Map ) { m_requirementsChecker->setConfigurationMap( configurationMap.value( "requirements" ).toMap() ); - - m_config->requirementsModel().setRequirementsList( checkRequirements() ); } else cWarning() << "no valid requirements map found in welcome " From 039065ee4ae788fdc01997cb56a972100b4053f1 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 15:21:07 +0200 Subject: [PATCH 08/24] [libcalamares] Minor debugging support in RequirementsModel --- .../modulesystem/RequirementsModel.cpp | 18 ++++++++++++++++++ .../modulesystem/RequirementsModel.h | 3 +++ 2 files changed, 21 insertions(+) diff --git a/src/libcalamares/modulesystem/RequirementsModel.cpp b/src/libcalamares/modulesystem/RequirementsModel.cpp index 4a776b3eb..50d70b150 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.cpp +++ b/src/libcalamares/modulesystem/RequirementsModel.cpp @@ -18,6 +18,8 @@ #include "RequirementsModel.h" +#include "utils/Logger.h" + namespace Calamares { @@ -94,4 +96,20 @@ RequirementsModel::roleNames() const 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; + } +} + } // namespace Calamares diff --git a/src/libcalamares/modulesystem/RequirementsModel.h b/src/libcalamares/modulesystem/RequirementsModel.h index e34dd02c2..eaf597509 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.h +++ b/src/libcalamares/modulesystem/RequirementsModel.h @@ -71,6 +71,9 @@ public: 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 ); From b7c60cec66c290f615599eaad5cace0397e24a11 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 15:35:03 +0200 Subject: [PATCH 09/24] [libcalamares] Re-vamp RequirementsChecker - Give the ModuleManager a RequirementsModel -- that is the source of truth about the module-requirements of the modules managed by that particular ModuleManager. - Let the RequirementsChecker operate on a given RequirementsModel. --- .../modulesystem/RequirementsChecker.cpp | 26 +++++-------------- .../modulesystem/RequirementsChecker.h | 5 ++-- .../modulesystem/RequirementsModel.cpp | 10 ------- .../modulesystem/RequirementsModel.h | 12 +++++---- .../modulesystem/ModuleManager.cpp | 4 ++- .../modulesystem/ModuleManager.h | 3 ++- 6 files changed, 21 insertions(+), 39 deletions(-) diff --git a/src/libcalamares/modulesystem/RequirementsChecker.cpp b/src/libcalamares/modulesystem/RequirementsChecker.cpp index 97a4c912f..6617fa6d5 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 @@ -63,14 +64,14 @@ check( Module* const& m, RequirementsChecker* c ) 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(); } @@ -114,19 +115,8 @@ 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(); + emit requirementsComplete( m_model->satisfiedMandatory() ); QTimer::singleShot( 0, this, &RequirementsChecker::done ); } } @@ -134,11 +124,7 @@ RequirementsChecker::finished() void RequirementsChecker::addCheckedRequirements( RequirementsList l ) { - static QMutex addMutex; - { - QMutexLocker lock( &addMutex ); - m_collectedRequirements.append( l ); - } + m_model->addRequirementsList( l ); cDebug() << "Added" << l.count() << "requirement results"; emit requirementsResult( l ); } diff --git a/src/libcalamares/modulesystem/RequirementsChecker.h b/src/libcalamares/modulesystem/RequirementsChecker.h index 450495dc1..b4651be21 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: @@ -75,7 +76,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 50d70b150..dc1c3c3cb 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.cpp +++ b/src/libcalamares/modulesystem/RequirementsModel.cpp @@ -23,16 +23,6 @@ namespace Calamares { -void -RequirementsModel::setRequirementsList( const Calamares::RequirementsList& requirements ) -{ - QMutexLocker l( &m_addLock ); - emit beginResetModel(); - m_requirements = requirements; - changeRequirementsList(); - emit endResetModel(); -} - void RequirementsModel::addRequirementsList( const Calamares::RequirementsList& requirements ) { diff --git a/src/libcalamares/modulesystem/RequirementsModel.h b/src/libcalamares/modulesystem/RequirementsModel.h index eaf597509..ce9f23168 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.h +++ b/src/libcalamares/modulesystem/RequirementsModel.h @@ -28,6 +28,8 @@ 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 @@ -39,6 +41,8 @@ namespace Calamares */ 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 ) @@ -62,11 +66,6 @@ public: ///@brief Are all the **mandatory** requirements satisfied? bool satisfiedMandatory() const { return m_satisfiedMandatory; } - ///@brief Replace the entire list of requirements; resets the model - void setRequirementsList( const Calamares::RequirementsList& requirements ); - ///@brief Append some requirements; resets the model - void addRequirementsList( 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(); } @@ -81,6 +80,9 @@ signals: protected: QHash< int, QByteArray > roleNames() const override; + ///@brief Append some requirements; resets the model + void addRequirementsList( const Calamares::RequirementsList& requirements ); + private: ///@brief Implementation for {set,add}RequirementsList void changeRequirementsList(); diff --git a/src/libcalamaresui/modulesystem/ModuleManager.cpp b/src/libcalamaresui/modulesystem/ModuleManager.cpp index 8d4b2342f..4734838ca 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,7 +357,7 @@ ModuleManager::checkRequirements() modules[ count++ ] = module; } - RequirementsChecker* rq = new RequirementsChecker( modules, this ); + RequirementsChecker* rq = new RequirementsChecker( modules, m_requirementsModel, this ); connect( rq, &RequirementsChecker::requirementsResult, this, &ModuleManager::requirementsResult ); connect( rq, &RequirementsChecker::requirementsComplete, this, &ModuleManager::requirementsComplete ); connect( rq, &RequirementsChecker::requirementsProgress, this, &ModuleManager::requirementsProgress ); diff --git a/src/libcalamaresui/modulesystem/ModuleManager.h b/src/libcalamaresui/modulesystem/ModuleManager.h index fdb63cd87..b0e537d9c 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. @@ -130,6 +130,7 @@ private: QMap< QString, QString > m_moduleDirectoriesByModuleName; QMap< ModuleSystem::InstanceKey, Module* > m_loadedModulesByInstanceKey; const QStringList m_paths; + RequirementsModel* m_requirementsModel; static ModuleManager* s_instance; }; From 9b0ea3f63dcedff7754850d632a4a7e889849697 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 15:42:27 +0200 Subject: [PATCH 10/24] [libcalamares] Remove runaround through free function - Call into a method directly to do the work of adding results from a single module. --- .../modulesystem/RequirementsChecker.cpp | 27 ++++++++----------- .../modulesystem/RequirementsChecker.h | 2 +- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/libcalamares/modulesystem/RequirementsChecker.cpp b/src/libcalamares/modulesystem/RequirementsChecker.cpp index 6617fa6d5..9fa9a72f8 100644 --- a/src/libcalamares/modulesystem/RequirementsChecker.cpp +++ b/src/libcalamares/modulesystem/RequirementsChecker.cpp @@ -52,18 +52,6 @@ registerMetatypes() } } -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, RequirementsModel* model, QObject* parent ) : QObject( parent ) , m_modules( std::move( modules ) ) @@ -88,7 +76,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 ); @@ -122,10 +110,17 @@ RequirementsChecker::finished() } void -RequirementsChecker::addCheckedRequirements( RequirementsList l ) +RequirementsChecker::addCheckedRequirements( Module* m ) { - m_model->addRequirementsList( l ); - cDebug() << "Added" << l.count() << "requirement results"; + RequirementsList l = m->checkRequirements(); + cDebug() << "Got" << l.count() << "requirement results from" << m->name(); + if ( l.count() > 0 ) + { + m_model->addRequirementsList( l ); + } + + requirementsProgress( + tr( "Requirements checking for module %1 is complete." ).arg( m->name() ) ); emit requirementsResult( l ); } diff --git a/src/libcalamares/modulesystem/RequirementsChecker.h b/src/libcalamares/modulesystem/RequirementsChecker.h index b4651be21..45aa4fc4f 100644 --- a/src/libcalamares/modulesystem/RequirementsChecker.h +++ b/src/libcalamares/modulesystem/RequirementsChecker.h @@ -49,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(); From 153757933a0b21dc305696bfdbf560a830c40ed3 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 15:53:29 +0200 Subject: [PATCH 11/24] [libcalamares] Stop emitting signals with RequirementsList - The architecture of letting someone build up a list of requirements from data emitted by the ModuleManager is broken: if it gets loaded later, it will miss data; passing around complicated objects is no fun anyway. Get rid of it, on the way to "ModuleManager has its own model of requirements". --- .../modulesystem/RequirementsChecker.cpp | 23 ------------------- .../modulesystem/RequirementsChecker.h | 7 ------ .../modulesystem/ModuleManager.cpp | 3 +-- .../modulesystem/ModuleManager.h | 1 - 4 files changed, 1 insertion(+), 33 deletions(-) diff --git a/src/libcalamares/modulesystem/RequirementsChecker.cpp b/src/libcalamares/modulesystem/RequirementsChecker.cpp index 9fa9a72f8..92e194818 100644 --- a/src/libcalamares/modulesystem/RequirementsChecker.cpp +++ b/src/libcalamares/modulesystem/RequirementsChecker.cpp @@ -33,25 +33,6 @@ 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; - } -} - RequirementsChecker::RequirementsChecker( QVector< Module* > modules, RequirementsModel* model, QObject* parent ) : QObject( parent ) , m_modules( std::move( modules ) ) @@ -60,8 +41,6 @@ RequirementsChecker::RequirementsChecker( QVector< Module* > modules, Requiremen , m_progressTimeouts( 0 ) { m_watchers.reserve( m_modules.count() ); - - registerMetatypes(); } RequirementsChecker::~RequirementsChecker() {} @@ -104,7 +83,6 @@ RequirementsChecker::finished() } m_model->describe(); - emit requirementsComplete( m_model->satisfiedMandatory() ); QTimer::singleShot( 0, this, &RequirementsChecker::done ); } } @@ -121,7 +99,6 @@ RequirementsChecker::addCheckedRequirements( Module* m ) requirementsProgress( tr( "Requirements checking for module %1 is complete." ).arg( m->name() ) ); - emit requirementsResult( l ); } void diff --git a/src/libcalamares/modulesystem/RequirementsChecker.h b/src/libcalamares/modulesystem/RequirementsChecker.h index 45aa4fc4f..21c86f0a6 100644 --- a/src/libcalamares/modulesystem/RequirementsChecker.h +++ b/src/libcalamares/modulesystem/RequirementsChecker.h @@ -60,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(); diff --git a/src/libcalamaresui/modulesystem/ModuleManager.cpp b/src/libcalamaresui/modulesystem/ModuleManager.cpp index 4734838ca..b6040371b 100644 --- a/src/libcalamaresui/modulesystem/ModuleManager.cpp +++ b/src/libcalamaresui/modulesystem/ModuleManager.cpp @@ -358,10 +358,9 @@ ModuleManager::checkRequirements() } RequirementsChecker* rq = new RequirementsChecker( modules, m_requirementsModel, this ); - connect( rq, &RequirementsChecker::requirementsResult, this, &ModuleManager::requirementsResult ); - connect( rq, &RequirementsChecker::requirementsComplete, this, &ModuleManager::requirementsComplete ); connect( rq, &RequirementsChecker::requirementsProgress, this, &ModuleManager::requirementsProgress ); 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 b0e537d9c..871a03a2a 100644 --- a/src/libcalamaresui/modulesystem/ModuleManager.h +++ b/src/libcalamaresui/modulesystem/ModuleManager.h @@ -97,7 +97,6 @@ signals: void modulesFailed( QStringList ); /// .. or not // Below, see RequirementsChecker documentation void requirementsComplete( bool ); - void requirementsResult( RequirementsList ); void requirementsProgress( const QString& ); private slots: From fabe5ec43917e32a5bbaacc4a5dba2ee7758ba7d Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 16:18:55 +0200 Subject: [PATCH 12/24] [welcome] Config should not have its own RequirementsModel - Use the one from ModuleManager --- .../modulesystem/ModuleManager.h | 5 +++- src/modules/welcome/Config.cpp | 25 ++++++++----------- src/modules/welcome/Config.h | 9 +++---- src/modules/welcome/WelcomePage.cpp | 2 +- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/libcalamaresui/modulesystem/ModuleManager.h b/src/libcalamaresui/modulesystem/ModuleManager.h index 871a03a2a..2c2685a3a 100644 --- a/src/libcalamaresui/modulesystem/ModuleManager.h +++ b/src/libcalamaresui/modulesystem/ModuleManager.h @@ -87,10 +87,13 @@ 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 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..2c6b4cc0e 100644 --- a/src/modules/welcome/WelcomePage.cpp +++ b/src/modules/welcome/WelcomePage.cpp @@ -47,7 +47,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 ) { From 7d00f7e0dc2cc2e156e74b86520b45398d4bc1e9 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 16:26:38 +0200 Subject: [PATCH 13/24] [welcome] Explain in the debug log what failed --- src/modules/welcome/checker/CheckerContainer.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/modules/welcome/checker/CheckerContainer.cpp b/src/modules/welcome/checker/CheckerContainer.cpp index 53e65fa04..f98b5b3d3 100644 --- a/src/modules/welcome/checker/CheckerContainer.cpp +++ b/src/modules/welcome/checker/CheckerContainer.cpp @@ -55,6 +55,16 @@ 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() + << m_model.data( index, Calamares::RequirementsModel::Satisfied ).toBool(); + } + } layout()->removeWidget( m_waitingWidget ); m_waitingWidget->deleteLater(); From 09b73dce0640760bfe8df088546c6932b48d00c0 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 17:10:03 +0200 Subject: [PATCH 14/24] [libcalamares] Implement the HasDetails role --- src/libcalamares/modulesystem/RequirementsModel.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libcalamares/modulesystem/RequirementsModel.cpp b/src/libcalamares/modulesystem/RequirementsModel.cpp index dc1c3c3cb..eb2f892be 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.cpp +++ b/src/libcalamares/modulesystem/RequirementsModel.cpp @@ -69,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(); } @@ -83,6 +85,7 @@ RequirementsModel::roleNames() const roles[ Roles::NegatedText ] = "negatedText"; roles[ Roles::Satisfied ] = "satisfied"; roles[ Roles::Mandatory ] = "mandatory"; + roles[ Roles::HasDetails ] = "hasDetails"; return roles; } From c0fa212fa968a16012b34acce0f33bacde52bfe5 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 20:45:47 +0200 Subject: [PATCH 15/24] [welcome] Be slightly more verbose in reporting missed req's --- src/modules/welcome/checker/CheckerContainer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/welcome/checker/CheckerContainer.cpp b/src/modules/welcome/checker/CheckerContainer.cpp index f98b5b3d3..11ae9c7c3 100644 --- a/src/modules/welcome/checker/CheckerContainer.cpp +++ b/src/modules/welcome/checker/CheckerContainer.cpp @@ -62,7 +62,8 @@ CheckerContainer::requirementsComplete( bool ok ) { auto index = m_model.index( i ); cDebug() << Logger::SubEntry << i << m_model.data( index, Calamares::RequirementsModel::Name ).toString() - << m_model.data( index, Calamares::RequirementsModel::Satisfied ).toBool(); + << "set?" << m_model.data( index, Calamares::RequirementsModel::Satisfied ).toBool() << "req?" + << m_model.data( index, Calamares::RequirementsModel::Mandatory ).toBool(); } } From 0d6e10311c7a15805a134166f0b35f0c3c127cab Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 11 May 2020 20:53:23 +0200 Subject: [PATCH 16/24] Changes: pre-release housekeeping --- CHANGES | 5 ++++- CMakeLists.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 22dac3dd2..7f748ef51 100644 --- a/CHANGES +++ b/CHANGES @@ -3,7 +3,7 @@ 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.24 (2020-05-11) # This release contains contributions from (alphabetically by first name): - Bill Auger @@ -18,6 +18,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 667ec2231..62cf971c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ project( CALAMARES VERSION 3.2.24 LANGUAGES C CXX ) -set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development +set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during development ### OPTIONS # From ab6c6a67483fcf429463bad839fbe3943da6ea42 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 12 May 2020 10:53:35 +0200 Subject: [PATCH 17/24] Changes: post-release housekeeping --- CHANGES | 12 ++++++++++++ CMakeLists.txt | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 7f748ef51..d6f5de059 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,18 @@ 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.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): diff --git a/CMakeLists.txt b/CMakeLists.txt index 62cf971c4..5ead0b7c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,10 +40,10 @@ 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 0 ) # Set to 0 during release cycle, 1 during development +set( CALAMARES_VERSION_RC 1 ) # Set to 0 during release cycle, 1 during development ### OPTIONS # From e930c74e851f0e20012adf000643746f674604cf Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 12 May 2020 14:47:31 +0200 Subject: [PATCH 18/24] [welcomeq] Coding style - Apply coding style tool - Remove commented-out cruft - Drop TODO's that don't apply anymore --- src/modules/welcomeq/WelcomeQmlViewStep.cpp | 60 +++++++++------------ src/modules/welcomeq/WelcomeQmlViewStep.h | 3 +- 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/modules/welcomeq/WelcomeQmlViewStep.cpp b/src/modules/welcomeq/WelcomeQmlViewStep.cpp index f520a9953..1f173563b 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,55 @@ 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); } QString WelcomeQmlViewStep::prettyName() const { - return tr( "Welcome" ); + return tr( "Welcome" ); } bool WelcomeQmlViewStep::isNextEnabled() const { - // TODO: should return true -// return m_config->property("isNextEnabled").toBool(); + // TODO: should return true + // return m_config->property("isNextEnabled").toBool(); return true; } 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,30 +89,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() ); - } - else - cWarning() << "no valid requirements map found in welcome " - "module configuration."; + 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."; + } - 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..7fb31502f 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; @@ -75,7 +74,7 @@ public: private: // TODO: a generic QML viewstep should return a config object from a method - Config *m_config; + Config* m_config; GeneralRequirements* m_requirementsChecker; }; From 9e0aa76375118ff9832f2c1f62393fd2f1789425 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 12 May 2020 14:54:18 +0200 Subject: [PATCH 19/24] [welcome] Order member pointers - Create config before the page - .. and in doing so, create the page in the initializer list instead --- src/modules/welcome/WelcomeViewStep.cpp | 6 ++---- src/modules/welcome/WelcomeViewStep.h | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/modules/welcome/WelcomeViewStep.cpp b/src/modules/welcome/WelcomeViewStep.cpp index 0ed887fa9..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 ); } 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 ) From 90f8e748efb17e19af6d1937eebea01d90077264 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 12 May 2020 15:29:16 +0200 Subject: [PATCH 20/24] [welcome] Improve debugging of general requirements - distinguish 'this has not been checked' from 'checked and failed' --- .../welcome/checker/GeneralRequirements.cpp | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) 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 ); From f856c07b04a7245999742b6a19e4fe713f34a69c Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 12 May 2020 16:09:13 +0200 Subject: [PATCH 21/24] [libcalamares] Move progress signal to RequirementsModel - It is the requirements model (checking) that reports progress, and now the model is accessible (ask for it with requirementsModel(), make the messages come from there. --- src/libcalamares/modulesystem/RequirementsChecker.cpp | 4 ++-- src/libcalamares/modulesystem/RequirementsModel.cpp | 7 +++++++ src/libcalamares/modulesystem/RequirementsModel.h | 9 +++++++++ src/libcalamaresui/modulesystem/ModuleManager.cpp | 1 - src/libcalamaresui/modulesystem/ModuleManager.h | 1 - 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/libcalamares/modulesystem/RequirementsChecker.cpp b/src/libcalamares/modulesystem/RequirementsChecker.cpp index 92e194818..0904d0c36 100644 --- a/src/libcalamares/modulesystem/RequirementsChecker.cpp +++ b/src/libcalamares/modulesystem/RequirementsChecker.cpp @@ -41,6 +41,7 @@ RequirementsChecker::RequirementsChecker( QVector< Module* > modules, Requiremen , m_progressTimeouts( 0 ) { m_watchers.reserve( m_modules.count() ); + connect( this, &RequirementsChecker::requirementsProgress, model, &RequirementsModel::setProgressMessage ); } RequirementsChecker::~RequirementsChecker() {} @@ -97,8 +98,7 @@ RequirementsChecker::addCheckedRequirements( Module* m ) m_model->addRequirementsList( l ); } - requirementsProgress( - tr( "Requirements checking for module %1 is complete." ).arg( m->name() ) ); + requirementsProgress( tr( "Requirements checking for module %1 is complete." ).arg( m->name() ) ); } void diff --git a/src/libcalamares/modulesystem/RequirementsModel.cpp b/src/libcalamares/modulesystem/RequirementsModel.cpp index eb2f892be..eed3b8b3b 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.cpp +++ b/src/libcalamares/modulesystem/RequirementsModel.cpp @@ -105,4 +105,11 @@ RequirementsModel::describe() const } } +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 ce9f23168..2318421c4 100644 --- a/src/libcalamares/modulesystem/RequirementsModel.h +++ b/src/libcalamares/modulesystem/RequirementsModel.h @@ -46,6 +46,7 @@ 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; @@ -65,6 +66,9 @@ public: 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; @@ -76,6 +80,7 @@ public: signals: void satisfiedRequirementsChanged( bool value ); void satisfiedMandatoryChanged( bool value ); + void progressMessageChanged( QString message ); protected: QHash< int, QByteArray > roleNames() const override; @@ -83,10 +88,14 @@ protected: ///@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: ///@brief Implementation for {set,add}RequirementsList void changeRequirementsList(); + QString m_progressMessage; QMutex m_addLock; RequirementsList m_requirements; bool m_satisfiedRequirements = false; diff --git a/src/libcalamaresui/modulesystem/ModuleManager.cpp b/src/libcalamaresui/modulesystem/ModuleManager.cpp index b6040371b..3a3174935 100644 --- a/src/libcalamaresui/modulesystem/ModuleManager.cpp +++ b/src/libcalamaresui/modulesystem/ModuleManager.cpp @@ -358,7 +358,6 @@ ModuleManager::checkRequirements() } RequirementsChecker* rq = new RequirementsChecker( modules, m_requirementsModel, this ); - connect( rq, &RequirementsChecker::requirementsProgress, this, &ModuleManager::requirementsProgress ); connect( rq, &RequirementsChecker::done, rq, &RequirementsChecker::deleteLater ); connect( rq, &RequirementsChecker::done, this, [=](){ this->requirementsComplete( m_requirementsModel->satisfiedMandatory() ); } ); diff --git a/src/libcalamaresui/modulesystem/ModuleManager.h b/src/libcalamaresui/modulesystem/ModuleManager.h index 2c2685a3a..0c8a4bdaf 100644 --- a/src/libcalamaresui/modulesystem/ModuleManager.h +++ b/src/libcalamaresui/modulesystem/ModuleManager.h @@ -100,7 +100,6 @@ signals: void modulesFailed( QStringList ); /// .. or not // Below, see RequirementsChecker documentation void requirementsComplete( bool ); - void requirementsProgress( const QString& ); private slots: void doInit(); From 5c8a99c77b77a2d30156883a25264ab41c55f9db Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 12 May 2020 17:06:16 +0200 Subject: [PATCH 22/24] [libcalamares] After running the checker, re-compute satisfaction - If nothing is added to the model (e.g. it is empty) then the satisfaction still needs to be re-calculated (to true). --- src/libcalamares/modulesystem/RequirementsChecker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcalamares/modulesystem/RequirementsChecker.cpp b/src/libcalamares/modulesystem/RequirementsChecker.cpp index 0904d0c36..d59ccb602 100644 --- a/src/libcalamares/modulesystem/RequirementsChecker.cpp +++ b/src/libcalamares/modulesystem/RequirementsChecker.cpp @@ -84,6 +84,7 @@ RequirementsChecker::finished() } m_model->describe(); + m_model->changeRequirementsList(); QTimer::singleShot( 0, this, &RequirementsChecker::done ); } } From 1a1fde188519edd690b0ba4b929d1fa40fbb7b51 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 12 May 2020 17:07:15 +0200 Subject: [PATCH 23/24] [welcome] [welcomeq] Chase API change for requirements progress --- src/modules/welcome/WelcomePage.cpp | 5 +++-- src/modules/welcomeq/WelcomeQmlViewStep.cpp | 8 +++++--- src/modules/welcomeq/WelcomeQmlViewStep.h | 1 - 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/modules/welcome/WelcomePage.cpp b/src/modules/welcome/WelcomePage.cpp index 2c6b4cc0e..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" @@ -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/welcomeq/WelcomeQmlViewStep.cpp b/src/modules/welcomeq/WelcomeQmlViewStep.cpp index 1f173563b..42944f20d 100644 --- a/src/modules/welcomeq/WelcomeQmlViewStep.cpp +++ b/src/modules/welcomeq/WelcomeQmlViewStep.cpp @@ -37,6 +37,10 @@ WelcomeQmlViewStep::WelcomeQmlViewStep( QObject* parent ) , m_config( new Config( this ) ) , m_requirementsChecker( new GeneralRequirements( this ) ) { + connect( Calamares::ModuleManager::instance(), + &Calamares::ModuleManager::requirementsComplete, + this, + &WelcomeQmlViewStep::nextStatusChanged ); } @@ -49,9 +53,7 @@ WelcomeQmlViewStep::prettyName() const bool WelcomeQmlViewStep::isNextEnabled() const { - // TODO: should return true - // return m_config->property("isNextEnabled").toBool(); - return true; + return m_config->requirementsModel()->satisfiedMandatory(); } bool diff --git a/src/modules/welcomeq/WelcomeQmlViewStep.h b/src/modules/welcomeq/WelcomeQmlViewStep.h index 7fb31502f..78999986c 100644 --- a/src/modules/welcomeq/WelcomeQmlViewStep.h +++ b/src/modules/welcomeq/WelcomeQmlViewStep.h @@ -73,7 +73,6 @@ public: QObject* getConfig() override; private: - // TODO: a generic QML viewstep should return a config object from a method Config* m_config; GeneralRequirements* m_requirementsChecker; }; From 3f9878afc119856612924bf70f8e4c4b90aff459 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 12 May 2020 17:07:50 +0200 Subject: [PATCH 24/24] [welcomeq] Use the model properties to show recommendations and requirements --- src/modules/welcomeq/welcomeq.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 {