Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
46ab3ac277 | ||
![]() |
f9a8a9f588 | ||
![]() |
108e227eec | ||
![]() |
b30bb7ae0b | ||
![]() |
24e129a413 | ||
![]() |
d3acc39d2d | ||
![]() |
a4682db987 | ||
![]() |
5af614daf7 | ||
![]() |
ec4b6752d6 | ||
![]() |
76a2791b12 | ||
![]() |
7d024cf72b | ||
![]() |
9d6d8ecaea | ||
![]() |
288fe5b274 | ||
![]() |
40961f21a7 | ||
![]() |
f0aa515c8b | ||
![]() |
9c8194402b | ||
![]() |
cdbf45b5d3 | ||
![]() |
3a4dcb6913 | ||
![]() |
7e6c3a2309 | ||
![]() |
49f4e7b8e1 | ||
![]() |
ce6fae900f | ||
![]() |
6bf82e9c65 | ||
![]() |
d0a65641e2 | ||
![]() |
112b51756b | ||
![]() |
f15a599bbd | ||
![]() |
e49f0cf3ba | ||
![]() |
f045e4f00e | ||
![]() |
fc034828c7 | ||
![]() |
84240683f5 | ||
![]() |
cb4248e56d | ||
![]() |
c82b802f4e | ||
![]() |
4ae3a7af61 | ||
![]() |
f8385d2cb8 | ||
![]() |
13181a52ee |
@@ -1,4 +1,4 @@
|
||||
name: ci-debian-10
|
||||
name: nightly-debian-10
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -89,7 +89,7 @@ jobs:
|
||||
server: chat.freenode.net
|
||||
nickname: cala-ci
|
||||
channel: "#calamares"
|
||||
message: "SCHEDULED ${{ github.workflow }} OK ${{ steps.pre_build.outputs.message }}"
|
||||
message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"
|
||||
- name: "notify: fail"
|
||||
uses: rectalogic/notify-irc@v1
|
||||
if: ${{ failure() && github.repository == 'calamares/calamares' }}
|
||||
@@ -97,4 +97,4 @@ jobs:
|
||||
server: chat.freenode.net
|
||||
nickname: cala-ci
|
||||
channel: "#calamares"
|
||||
message: "SCHEDULED ${{ github.workflow }} FAIL ${{ steps.pre_build.outputs.message }}"
|
||||
message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"
|
99
.github/workflows/nightly-neon.yml
vendored
Normal file
99
.github/workflows/nightly-neon.yml
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
name: nightly-neon
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "52 23 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BUILDDIR: /build
|
||||
SRCDIR: ${{ github.workspace }}
|
||||
CMAKE_ARGS: |
|
||||
-DWEBVIEW_FORCE_WEBKIT=1
|
||||
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON
|
||||
-DWITH_PYTHONQT=OFF"
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: docker://kdeneon/plasma:user
|
||||
options: --tmpfs /build:rw --user 0:0
|
||||
steps:
|
||||
- name: "prepare env"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install git-core
|
||||
sudo apt-get -y install \
|
||||
build-essential \
|
||||
cmake \
|
||||
extra-cmake-modules \
|
||||
gettext \
|
||||
kio-dev \
|
||||
libatasmart-dev \
|
||||
libboost-python-dev \
|
||||
libkf5config-dev \
|
||||
libkf5coreaddons-dev \
|
||||
libkf5i18n-dev \
|
||||
libkf5iconthemes-dev \
|
||||
libkf5parts-dev \
|
||||
libkf5service-dev \
|
||||
libkf5solid-dev \
|
||||
libkpmcore-dev \
|
||||
libparted-dev \
|
||||
libpolkit-qt5-1-dev \
|
||||
libqt5svg5-dev \
|
||||
libqt5webkit5-dev \
|
||||
libyaml-cpp-dev \
|
||||
os-prober \
|
||||
pkg-config \
|
||||
python3-dev \
|
||||
qtbase5-dev \
|
||||
qtdeclarative5-dev \
|
||||
qttools5-dev \
|
||||
qttools5-dev-tools
|
||||
- name: "prepare source"
|
||||
uses: actions/checkout@v2
|
||||
- name: "prepare build"
|
||||
id: pre_build
|
||||
run: |
|
||||
test -n "$BUILDDIR" || { echo "! \$BUILDDIR not set" ; exit 1 ; }
|
||||
mkdir -p $BUILDDIR
|
||||
test -f $SRCDIR/CMakeLists.txt || { echo "! Missing $SRCDIR/CMakeLists.txt" ; exit 1 ; }
|
||||
echo "::set-output name=message::"`git log -1 --abbrev-commit --pretty=oneline --no-decorate ${{ github.event.head_commit.id }}`
|
||||
- name: "Calamares: cmake"
|
||||
working-directory: ${{ env.BUILDDIR }}
|
||||
run: cmake $CMAKE_ARGS $SRCDIR
|
||||
- name: "Calamares: make"
|
||||
working-directory: ${{ env.BUILDDIR }}
|
||||
run: make -j2 VERBOSE=1
|
||||
- name: "Calamares: install"
|
||||
working-directory: ${{ env.BUILDDIR }}
|
||||
run: make install VERBOSE=1 DESTDIR=${{ env.BUILDDIR }}/stage
|
||||
- name: "Calamares: archive"
|
||||
working-directory: ${{ env.BUILDDIR }}
|
||||
run: tar czf calamares.tar.gz stage
|
||||
- name: "upload"
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: calamares-tarball
|
||||
path: ${{ env.BUILDDIR }}/calamares.tar.gz
|
||||
if-no-files-found: error
|
||||
retention-days: 3
|
||||
- name: "notify: ok"
|
||||
uses: rectalogic/notify-irc@v1
|
||||
if: ${{ success() && github.repository == 'calamares/calamares' }}
|
||||
with:
|
||||
server: chat.freenode.net
|
||||
nickname: cala-ci
|
||||
channel: "#calamares"
|
||||
message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"
|
||||
- name: "notify: fail"
|
||||
uses: rectalogic/notify-irc@v1
|
||||
if: ${{ failure() && github.repository == 'calamares/calamares' }}
|
||||
with:
|
||||
server: chat.freenode.net
|
||||
nickname: cala-ci
|
||||
channel: "#calamares"
|
||||
message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"
|
@@ -1,4 +1,4 @@
|
||||
name: ci-opensuse
|
||||
name: nightly-opensuse
|
||||
|
||||
on:
|
||||
schedule:
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
server: chat.freenode.net
|
||||
nickname: cala-ci
|
||||
channel: "#calamares"
|
||||
message: "SCHEDULED ${{ github.workflow }} OK ${{ steps.pre_build.outputs.message }}"
|
||||
message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"
|
||||
- name: "notify: fail"
|
||||
uses: rectalogic/notify-irc@v1
|
||||
if: ${{ failure() && github.repository == 'calamares/calamares' }}
|
||||
@@ -95,4 +95,4 @@ jobs:
|
||||
server: chat.freenode.net
|
||||
nickname: cala-ci
|
||||
channel: "#calamares"
|
||||
message: "SCHEDULED ${{ github.workflow }} FAIL ${{ steps.pre_build.outputs.message }}"
|
||||
message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"
|
@@ -1,4 +1,4 @@
|
||||
name: ci-neon
|
||||
name: ci-push
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
server: chat.freenode.net
|
||||
nickname: cala-ci
|
||||
channel: "#calamares"
|
||||
message: "PUSH ${{ github.workflow }} OK ${{ github.actor }} on ${{ github.event.ref }}\n.. ${{ steps.pre_build.outputs.message }}"
|
||||
message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ github.actor }} on ${{ github.event.ref }}\n.. ${{ steps.pre_build.outputs.message }}"
|
||||
- name: "notify: fail"
|
||||
uses: rectalogic/notify-irc@v1
|
||||
if: ${{ failure() && github.repository == 'calamares/calamares' }}
|
||||
@@ -92,4 +92,4 @@ jobs:
|
||||
server: chat.freenode.net
|
||||
nickname: cala-ci
|
||||
channel: "#calamares"
|
||||
message: "PUSH ${{ github.workflow }} FAIL ${{ github.actor }} on ${{ github.event.ref }}\n.. ${{ steps.pre_build.outputs.message }}\n.. DIFF ${{ github.event.compare }}"
|
||||
message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ github.actor }} on ${{ github.event.ref }}\n.. ${{ steps.pre_build.outputs.message }}\n.. DIFF ${{ github.event.compare }}"
|
32
CHANGES
32
CHANGES
@@ -7,6 +7,38 @@ 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.37 (2021-02-23) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
- benne-dee
|
||||
|
||||
## Core ##
|
||||
- Calamares has a table of 'best guess' languages for each country
|
||||
and when GeoIP is enabled, it will automatically select that
|
||||
country's language as default -- the user can of course pick
|
||||
a different one. The 'best guess' is based on Unicode / ISO
|
||||
data, which is sometimes dubious. Based on some personal notes,
|
||||
the 'best guess' language for Belarus has been changed to Russian.
|
||||
- Calamares has a table of 'best guess' keyboard mappings,
|
||||
allowing native language input. However, usernames and
|
||||
passwords should be in US-ASCII (this is a limitation of
|
||||
the login system -- **some** parts of the system will support
|
||||
non-ASCII input, but it's better safe than sorry).
|
||||
Add Greek to the list of languages that needs US-ASCII
|
||||
in addition to native input.
|
||||
- The CI infrastructure now builds Calamares and Calamares-extensions
|
||||
on a nightly basis.
|
||||
|
||||
## Modules ##
|
||||
- The *netinstall* module has a YAML schema, allowing packagers
|
||||
to validate and verify their netinstall configurations before
|
||||
shipping an ISO (or writing bug reports). Thanks benne-dee.
|
||||
- The *finished* module has been heavily refactored, opening
|
||||
the way to a QML-based version of the same module. This is
|
||||
also preparatory work for allowing packagers (e.g. PostmarketOS)
|
||||
to customize the messages on the finished page.
|
||||
|
||||
|
||||
# 3.2.36 (2021-02-03) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
|
@@ -41,7 +41,7 @@
|
||||
# TODO:3.3: Require CMake 3.12
|
||||
cmake_minimum_required( VERSION 3.3 FATAL_ERROR )
|
||||
project( CALAMARES
|
||||
VERSION 3.2.36
|
||||
VERSION 3.2.37
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
|
@@ -7,6 +7,8 @@
|
||||
#
|
||||
# Release script for Calamares
|
||||
#
|
||||
# NOTE: this script contains Linuxisms (in particular, expects GNU mktemp(1))
|
||||
#
|
||||
# This attempts to perform the different steps of the RELEASE.md
|
||||
# document automatically. It's not tested on other machines or
|
||||
# setups other than [ade]'s development VM.
|
||||
|
@@ -145,7 +145,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamares/JobQueue.cpp" line="196"/>
|
||||
<source>Done</source>
|
||||
<translation>בוצע</translation>
|
||||
<translation>סיום</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2504,7 +2504,7 @@ The installer will quit and all changes will be lost.</source>
|
||||
<location filename="../src/modules/partition/core/PartitionModel.cpp" line="159"/>
|
||||
<location filename="../src/modules/partition/core/PartitionModel.cpp" line="199"/>
|
||||
<source>Free Space</source>
|
||||
<translation>זכרון פנוי</translation>
|
||||
<translation>שטח פנוי</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/core/PartitionModel.cpp" line="163"/>
|
||||
@@ -2931,7 +2931,7 @@ Output:
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/PartitionLabelsView.cpp" line="41"/>
|
||||
<source>Unpartitioned space or unknown partition table</source>
|
||||
<translation>הזכרון לא מחולק למחיצות או שטבלת המחיצות אינה מוכרת</translation>
|
||||
<translation>השטח לא מחולק למחיצות או שטבלת המחיצות אינה מוכרת</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2991,7 +2991,7 @@ Output:
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/ReplaceWidget.cpp" line="157"/>
|
||||
<source>%1 cannot be installed on empty space. Please select an existing partition.</source>
|
||||
<translation>לא ניתן להתקין את %1 על זכרון ריק. אנא בחר מחיצה קיימת.</translation>
|
||||
<translation>לא ניתן להתקין את %1 על שטח ריק. נא לבחור מחיצה קיימת.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/ReplaceWidget.cpp" line="167"/>
|
||||
|
@@ -5,7 +5,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Eli Shleifer <eligator@gmail.com>, 2017
|
||||
# Omeritzics Games <omeritzicschwartz@gmail.com>, 2020
|
||||
# Omer I.S. <omeritzicschwartz@gmail.com>, 2020
|
||||
# Yaron Shahrabani <sh.yaron@gmail.com>, 2020
|
||||
#
|
||||
#, fuzzy
|
||||
|
@@ -59,7 +59,7 @@ dumpWidgetTree( QDebug& deb, const QWidget* widget, int depth )
|
||||
{
|
||||
deb << ' ';
|
||||
}
|
||||
deb << widget->objectName();
|
||||
deb << widget->metaObject()->className() << widget->objectName();
|
||||
|
||||
for ( const auto* w : widget->findChildren< QWidget* >( QString(), Qt::FindDirectChildrenOnly ) )
|
||||
{
|
||||
|
@@ -29,7 +29,8 @@
|
||||
/* MODIFICATIONS
|
||||
*
|
||||
* Edited anyway:
|
||||
* 20191211 India changed to AnyLanguage, since Hindi doesn't make sense. #1284
|
||||
* 20191211 India (IN) changed to AnyLanguage, since Hindi doesn't make sense. #1284
|
||||
* 20210207 Belarus (BY) changed to Russian, as the more-common-language. #1634
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -77,7 +78,7 @@ static const CountryData country_data_table[] = {
|
||||
{ QLocale::Language::Portuguese, QLocale::Country::Brazil, 'B', 'R' },
|
||||
{ QLocale::Language::Dzongkha, QLocale::Country::Bhutan, 'B', 'T' },
|
||||
{ QLocale::Language::AnyLanguage, QLocale::Country::BouvetIsland, 'B', 'V' },
|
||||
{ QLocale::Language::Belarusian, QLocale::Country::Belarus, 'B', 'Y' },
|
||||
{ QLocale::Language::Russian, QLocale::Country::Belarus, 'B', 'Y' },
|
||||
{ QLocale::Language::Swahili, QLocale::Country::CongoKinshasa, 'C', 'D' },
|
||||
{ QLocale::Language::French, QLocale::Country::CentralAfricanRepublic, 'C', 'F' },
|
||||
{ QLocale::Language::French, QLocale::Country::CongoBrazzaville, 'C', 'G' },
|
||||
|
@@ -11,11 +11,13 @@
|
||||
|
||||
/** @brief Support for "named" enumerations
|
||||
*
|
||||
* For tables which map string names to enum values, provide a NamedEnumTable
|
||||
* which hangs on to an initializer_list of pairs of names and values.
|
||||
* This table can be used with find() to map names to values, or
|
||||
* values to names. A convenience function smash() is provided to help
|
||||
* in printing integer (underlying) values of an enum.
|
||||
* When a string needs to be one specific string out of a set of
|
||||
* alternatives -- one "name" from an enumerated set -- then it
|
||||
* is useful to have an **enum type** for the enumeration so that
|
||||
* C++ code can work with the (strong) type of the enum, while
|
||||
* the string can be used for human-readable interaction.
|
||||
* The `NamedEnumTable<E>` template provides support for naming
|
||||
* values of an enum.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_NAMEDENUM_H
|
||||
@@ -27,7 +29,100 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
/** @brief Type for collecting parts of a named enum. */
|
||||
/** @brief Type for collecting parts of a named enum.
|
||||
*
|
||||
* The `NamedEnumTable<E>` template provides support for naming
|
||||
* values of an enum. It supports mapping strings to enum values
|
||||
* and mapping enum values to strings.
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* Suppose we have code where there are three alternatives; it is
|
||||
* useful to have a strong type to make the alternatives visible
|
||||
* in that code, so the compiler can help check:
|
||||
*
|
||||
* ```
|
||||
* enum class MilkshakeSize { None, Small, Large };
|
||||
* ```
|
||||
*
|
||||
* In a switch() statement, the compiler will check that all kinds
|
||||
* of milkshakes are dealt with; we can pass a MilkshakeSize to
|
||||
* a function and rest assured that nobody will call that function
|
||||
* with a silly value, like `1`.
|
||||
*
|
||||
* There is no relation between the C++ identifiers used, and
|
||||
* any I/O related to that enumeration. In other words,
|
||||
*
|
||||
* ```
|
||||
* std::cout << MilkshakeSize::Small;
|
||||
* ```
|
||||
*
|
||||
* Will **not** print out "Small", or "small", or 1. It won't even
|
||||
* compile, because there is no mapping of the enum values to
|
||||
* something that can be output.
|
||||
*
|
||||
* By making a `NamedEnumTable<MilkshakeSize>` we can define a mapping
|
||||
* between strings (names) and enum values, so that we can easily
|
||||
* output the human-readable name, and also take string input
|
||||
* and convert it to an enum value. Suppose we have a function
|
||||
* `milkshakeSizeNames()` that returns a reference to such a table,
|
||||
* then we can use `find()` to map enums-to-names and names-to-enums.
|
||||
*
|
||||
* ```
|
||||
* const auto& names = milkshakeSizeNames();
|
||||
* MilkshakeSize sz{ MilkshakeSize::Large };
|
||||
* std::cout << names.find(sz); // Probably "large"
|
||||
*
|
||||
* bool ok;
|
||||
* sz = names.find( "small", ok ); // Probably MilkshakeSize::Small
|
||||
* ```
|
||||
*
|
||||
* ## Usage
|
||||
*
|
||||
* It is recommended to use a static const declaration for the table;
|
||||
* typical use will define a function that returns a reference to
|
||||
* the table, for shared use.
|
||||
*
|
||||
* The constructor for a table takes an initializer_list; each element
|
||||
* of the initializer_list is a **pair** consisting of a name and
|
||||
* an associated enum value. The names should be QStrings. For each enum
|
||||
* value that is listed, the canonical name should come **first** in the
|
||||
* table, so that printing the enum values gives the canonical result.
|
||||
*
|
||||
* ```
|
||||
* static const NamedEnumTable<MilkshakeSize>& milkshakeSizeNames()
|
||||
* {
|
||||
* static NamedEnumTable<MilkshakeSize> n { // Initializer list for n
|
||||
* { "large", MilkshakeSize::Large }, // One pair of name-and-value
|
||||
* { "small", MilkshakeSize::Small },
|
||||
* { "big", MilkshakeSize::Large }
|
||||
* };
|
||||
* return n;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The function `eNames()`, above, returns a reference to a name table
|
||||
* for the enum (presumably an enum class) `E`. It is possible to have
|
||||
* more than one table for an enum, or to make the table locally,
|
||||
* but **usually** you want one definitive table of names and values.
|
||||
* The `eNames()` function gives you that definitive table. In Calamres
|
||||
* code, such functions are usually named after the underlying enum.
|
||||
*
|
||||
* Using this particular table, looking up "large" will return `MilkshakeSize::Large`,
|
||||
* looking up "big" will **also** return `MilkshakeSize::Large`, looking up "derp"
|
||||
* will return `MilkshakeSize::Large` (because that is the first value in the table)
|
||||
* but will set the boolean `ok` parameter to false. Conversely, looking
|
||||
* up `MilkshakeSize::Large` will return "large" (never "big").
|
||||
*
|
||||
* Note that this particular table does **not** name MilkshakeSize::None,
|
||||
* so it is probably wrong: you can't get a string for that enum
|
||||
* value, and no string will map to MilkshakeSize::None either.
|
||||
* In general, tables should cover all of the enum values.
|
||||
*
|
||||
* Passing an empty initializer_list to the constructor is supported,
|
||||
* but will cause UB if the table is ever used for looking up a string.
|
||||
*
|
||||
*/
|
||||
template < typename T >
|
||||
struct NamedEnumTable
|
||||
{
|
||||
@@ -43,7 +138,9 @@ struct NamedEnumTable
|
||||
* Use braced-initialisation for NamedEnum, and remember that the
|
||||
* elements of the list are **pairs**, e.g.
|
||||
*
|
||||
* ```
|
||||
* static const NamedEnumTable<Colors> c{ {"red", Colors::Red } };
|
||||
* ```
|
||||
*/
|
||||
NamedEnumTable( const std::initializer_list< pair_t >& v )
|
||||
: table( v )
|
||||
@@ -55,10 +152,12 @@ struct NamedEnumTable
|
||||
*
|
||||
* Searches case-insensitively.
|
||||
*
|
||||
* If the name @p s is not found, @p ok is set to false and
|
||||
* If the name @p s is not found, @p ok is set to @c false and
|
||||
* the first enum value in the table is returned. Otherwise,
|
||||
* @p ok is set to true and the corresponding value is returned.
|
||||
*
|
||||
* @p ok is set to @c true and the corresponding value is returned.
|
||||
* Use the output value of @p ok to determine if the lookup was
|
||||
* successful: there is otherwise no sensible way to distinguish
|
||||
* found-the-name-of-the-first-item from not-found.
|
||||
*/
|
||||
enum_t find( const string_t& s, bool& ok ) const
|
||||
{
|
||||
@@ -75,11 +174,17 @@ struct NamedEnumTable
|
||||
return table.begin()->second;
|
||||
}
|
||||
|
||||
/** @brief Find a value @p s in the table.
|
||||
/** @brief Find a value @p s in the table and return its name.
|
||||
*
|
||||
* If the value @p s is not found, @p ok is set to false and
|
||||
* an empty string is returned. Otherwise, @p is set to true
|
||||
* and the corresponding name is returned.
|
||||
* If @p s is an enum value in the table, return the corresponding
|
||||
* name (the first name with that value, if there are aliases)
|
||||
* and set @p ok to @c true.
|
||||
*
|
||||
* If the value @p s is not found, @p ok is set to @c false and
|
||||
* an empty string is returned. This indicates that the table does
|
||||
* not cover all of the values * in `enum_t` (and @p s is one
|
||||
* of them), **or** that the passed-in value of @p s is
|
||||
* not a legal value, e.g. via a static_cast<enum_t>.
|
||||
*/
|
||||
string_t find( enum_t s, bool& ok ) const
|
||||
{
|
||||
@@ -98,7 +203,10 @@ struct NamedEnumTable
|
||||
|
||||
/** @brief Find a value @p s in the table and return its name.
|
||||
*
|
||||
* Returns emptry string if the value is not found.
|
||||
* Returns an empty string if the value @p s is not found (this
|
||||
* indicates that the table does not cover all of the values
|
||||
* in `enum_t`, **or** that the passed-in value of @p s is
|
||||
* not a legal value, e.g. via a static_cast<enum_t>).
|
||||
*/
|
||||
string_t find( enum_t s ) const
|
||||
{
|
||||
@@ -107,7 +215,24 @@ struct NamedEnumTable
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief Smashes an enum value to its underlying type. */
|
||||
/** @brief Smashes an enum value to its underlying type.
|
||||
*
|
||||
* While an enum **class** is not an integral type, and its values can't be
|
||||
* printed or treated like an integer (like an old-style enum can),
|
||||
* the underlying type **is** integral. This template function
|
||||
* returns the value of an enum value, in its underlying type.
|
||||
* This can be useful for debugging purposes, e.g.
|
||||
*
|
||||
* ```
|
||||
* MilkshakeSize sz{ MilkshakeSize::None };
|
||||
* std::cout << milkshakeSizeNames().find( sz ) << smash( sz );
|
||||
* ```
|
||||
*
|
||||
* This will print both the name and the underlying integer for the
|
||||
* value; assuming the table from the example is used, there is
|
||||
* no name for MilkshakeSize::None, so it will print an empty string,
|
||||
* followed by the integral representation -- probably a 0.
|
||||
*/
|
||||
template < typename E >
|
||||
constexpr typename std::underlying_type< E >::type
|
||||
smash( const E e )
|
||||
|
@@ -24,7 +24,6 @@
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/Dirs.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Qml.h"
|
||||
#include "utils/Retranslator.h"
|
||||
|
||||
#include <QDir>
|
||||
@@ -62,6 +61,10 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent )
|
||||
, m_label( new QLabel )
|
||||
, m_slideshow( makeSlideshow( m_widget ) )
|
||||
{
|
||||
m_widget->setObjectName( "slideshow" );
|
||||
m_progressBar->setObjectName( "exec-progress" );
|
||||
m_label->setObjectName( "exec-message" );
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout( m_widget );
|
||||
QVBoxLayout* innerLayout = new QVBoxLayout;
|
||||
|
||||
|
@@ -43,6 +43,8 @@ SlideshowQML::SlideshowQML( QWidget* parent )
|
||||
, m_qmlComponent( nullptr )
|
||||
, m_qmlObject( nullptr )
|
||||
{
|
||||
m_qmlShow->setObjectName("qml");
|
||||
|
||||
CalamaresUtils::registerQmlModels();
|
||||
|
||||
m_qmlShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
||||
@@ -203,6 +205,8 @@ SlideshowPictures::SlideshowPictures( QWidget* parent )
|
||||
, m_imageIndex( 0 )
|
||||
, m_images( Branding::instance()->slideshowImages() )
|
||||
{
|
||||
m_label->setObjectName("image");
|
||||
|
||||
m_label->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
||||
m_label->setAlignment( Qt::AlignCenter );
|
||||
m_timer->setInterval( std::chrono::milliseconds( 2000 ) );
|
||||
|
@@ -11,6 +11,7 @@ calamares_add_plugin( finished
|
||||
TYPE viewmodule
|
||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||
SOURCES
|
||||
Config.cpp
|
||||
FinishedViewStep.cpp
|
||||
FinishedPage.cpp
|
||||
UI
|
||||
|
201
src/modules/finished/Config.cpp
Normal file
201
src/modules/finished/Config.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
#include "Branding.h"
|
||||
#include "Settings.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QtDBus/QDBusReply>
|
||||
|
||||
const NamedEnumTable< Config::RestartMode >&
|
||||
restartModes()
|
||||
{
|
||||
using M = Config::RestartMode;
|
||||
static const NamedEnumTable< M > table { { "never", M::Never },
|
||||
{ "user-unchecked", M::UserDefaultUnchecked },
|
||||
{ "unchecked", M::UserDefaultUnchecked },
|
||||
{ "user-checked", M::UserDefaultChecked },
|
||||
{ "checked", M::UserDefaultChecked },
|
||||
{ "always", M::Always }
|
||||
|
||||
};
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
Config::Config( QObject* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Config::setRestartNowMode( Config::RestartMode m )
|
||||
{
|
||||
// Can only go "down" in state (Always > UserDefaultChecked > .. > Never)
|
||||
if ( m > m_restartNowMode )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If changing to an unconditional mode, also set other flag
|
||||
if ( m == RestartMode::Always || m == RestartMode::Never )
|
||||
{
|
||||
setRestartNowWanted( m == RestartMode::Always );
|
||||
}
|
||||
|
||||
if ( m != m_restartNowMode )
|
||||
{
|
||||
m_restartNowMode = m;
|
||||
emit restartModeChanged( m );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Config::setRestartNowWanted( bool w )
|
||||
{
|
||||
// Follow the mode which may affect @p w
|
||||
if ( m_restartNowMode == RestartMode::Always )
|
||||
{
|
||||
w = true;
|
||||
}
|
||||
if ( m_restartNowMode == RestartMode::Never )
|
||||
{
|
||||
w = false;
|
||||
}
|
||||
|
||||
if ( w != m_userWantsRestart )
|
||||
{
|
||||
m_userWantsRestart = w;
|
||||
emit restartNowWantedChanged( w );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Config::doRestart()
|
||||
{
|
||||
if ( restartNowMode() != RestartMode::Never && restartNowWanted() )
|
||||
{
|
||||
cDebug() << "Running restart command" << m_restartNowCommand;
|
||||
QProcess::execute( "/bin/sh", { "-c", m_restartNowCommand } );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Config::doNotify( bool hasFailed )
|
||||
{
|
||||
if ( !notifyOnFinished() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusInterface notify(
|
||||
"org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications" );
|
||||
if ( notify.isValid() )
|
||||
{
|
||||
cDebug() << "Sending notification of completion. Failed?" << hasFailed;
|
||||
|
||||
QString title;
|
||||
QString message;
|
||||
if ( hasFailed )
|
||||
{
|
||||
title = Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Failed" ) : tr( "Installation Failed" );
|
||||
message = Calamares::Settings::instance()->isSetupMode()
|
||||
? tr( "The setup of %1 did not complete successfully." )
|
||||
: tr( "The installation of %1 did not complete successfully." );
|
||||
}
|
||||
else
|
||||
{
|
||||
title = Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Complete" )
|
||||
: tr( "Installation Complete" );
|
||||
message = Calamares::Settings::instance()->isSetupMode() ? tr( "The setup of %1 is complete." )
|
||||
: tr( "The installation of %1 is complete." );
|
||||
}
|
||||
|
||||
const auto* branding = Calamares::Branding::instance();
|
||||
QDBusReply< uint > r = notify.call( "Notify",
|
||||
QString( "Calamares" ),
|
||||
QVariant( 0U ),
|
||||
QString( "calamares" ),
|
||||
title,
|
||||
message.arg( branding->versionedName() ),
|
||||
QStringList(),
|
||||
QVariantMap(),
|
||||
QVariant( 0 ) );
|
||||
if ( !r.isValid() )
|
||||
{
|
||||
cWarning() << "Could not call org.freedesktop.Notifications.Notify at end of installation." << r.error();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Could not get dbus interface for notifications at end of installation." << notify.lastError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
RestartMode mode = RestartMode::Never;
|
||||
|
||||
//TODO:3.3 remove deprecated restart settings
|
||||
QString restartMode = CalamaresUtils::getString( configurationMap, "restartNowMode" );
|
||||
if ( restartMode.isEmpty() )
|
||||
{
|
||||
if ( configurationMap.contains( "restartNowEnabled" ) )
|
||||
{
|
||||
cWarning() << "Configuring the finished module with deprecated restartNowEnabled settings";
|
||||
}
|
||||
|
||||
bool restartNowEnabled = CalamaresUtils::getBool( configurationMap, "restartNowEnabled", false );
|
||||
bool restartNowChecked = CalamaresUtils::getBool( configurationMap, "restartNowChecked", false );
|
||||
|
||||
if ( !restartNowEnabled )
|
||||
{
|
||||
mode = RestartMode::Never;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = restartNowChecked ? RestartMode::UserDefaultChecked : RestartMode::UserDefaultUnchecked;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool ok = false;
|
||||
mode = restartModes().find( restartMode, ok );
|
||||
if ( !ok )
|
||||
{
|
||||
cWarning() << "Configuring the finished module with bad restartNowMode" << restartMode;
|
||||
}
|
||||
}
|
||||
|
||||
m_restartNowMode = mode;
|
||||
m_userWantsRestart = ( mode == RestartMode::Always || mode == RestartMode::UserDefaultChecked );
|
||||
emit restartModeChanged( m_restartNowMode );
|
||||
emit restartNowWantedChanged( m_userWantsRestart );
|
||||
|
||||
if ( mode != RestartMode::Never )
|
||||
{
|
||||
QString restartNowCommand = CalamaresUtils::getString( configurationMap, "restartNowCommand" );
|
||||
if ( restartNowCommand.isEmpty() )
|
||||
{
|
||||
restartNowCommand = QStringLiteral( "shutdown -r now" );
|
||||
}
|
||||
m_restartNowCommand = restartNowCommand;
|
||||
}
|
||||
|
||||
m_notifyOnFinished = CalamaresUtils::getBool( configurationMap, "notifyOnFinished", false );
|
||||
}
|
81
src/modules/finished/Config.h
Normal file
81
src/modules/finished/Config.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef FINISHED_CONFIG_H
|
||||
#define FINISHED_CONFIG_H
|
||||
|
||||
#include "utils/NamedEnum.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Config : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( RestartMode restartNowMode READ restartNowMode WRITE setRestartNowMode NOTIFY restartModeChanged )
|
||||
Q_PROPERTY( bool restartNowWanted READ restartNowWanted WRITE setRestartNowWanted NOTIFY restartNowWantedChanged )
|
||||
|
||||
Q_PROPERTY( QString restartNowCommand READ restartNowCommand CONSTANT FINAL )
|
||||
Q_PROPERTY( bool notifyOnFinished READ notifyOnFinished CONSTANT FINAL )
|
||||
|
||||
public:
|
||||
Config( QObject* parent = nullptr );
|
||||
|
||||
enum class RestartMode
|
||||
{
|
||||
Never,
|
||||
UserDefaultUnchecked,
|
||||
UserDefaultChecked,
|
||||
Always
|
||||
};
|
||||
Q_ENUM( RestartMode )
|
||||
|
||||
RestartMode restartNowMode() const { return m_restartNowMode; }
|
||||
bool restartNowWanted() const { return m_userWantsRestart; }
|
||||
|
||||
QString restartNowCommand() const { return m_restartNowCommand; }
|
||||
bool notifyOnFinished() const { return m_notifyOnFinished; }
|
||||
|
||||
void setConfigurationMap( const QVariantMap& configurationMap );
|
||||
|
||||
public slots:
|
||||
void setRestartNowMode( RestartMode m );
|
||||
void setRestartNowWanted( bool w );
|
||||
|
||||
/** @brief Run the restart command, if desired.
|
||||
*
|
||||
* This should generally not be called somewhere during the
|
||||
* application's execution, but only in response to QApplication::quit()
|
||||
* or something like that when the user expects the system to restart.
|
||||
*/
|
||||
void doRestart();
|
||||
|
||||
/** @brief Send DBus notification, if desired.
|
||||
*
|
||||
* This takes notifyOnFinished() into account.
|
||||
*
|
||||
* At the end of installation (when the FinishedViewStep is activated),
|
||||
* send a desktop notification via DBus that the install is done.
|
||||
*/
|
||||
void doNotify( bool hasFailed = false );
|
||||
|
||||
signals:
|
||||
void restartModeChanged( RestartMode m );
|
||||
void restartNowWantedChanged( bool w );
|
||||
|
||||
private:
|
||||
QString m_restartNowCommand;
|
||||
RestartMode m_restartNowMode = RestartMode::Never;
|
||||
bool m_userWantsRestart = false;
|
||||
bool m_notifyOnFinished = false;
|
||||
};
|
||||
|
||||
const NamedEnumTable< Config::RestartMode >& restartModes();
|
||||
|
||||
#endif
|
@@ -11,26 +11,19 @@
|
||||
|
||||
#include "FinishedPage.h"
|
||||
|
||||
#include "CalamaresVersion.h"
|
||||
#include "ViewManager.h"
|
||||
#include "Config.h"
|
||||
#include "ui_FinishedPage.h"
|
||||
#include "utils/CalamaresUtilsGui.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Retranslator.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QBoxLayout>
|
||||
#include <QFocusEvent>
|
||||
#include <QLabel>
|
||||
#include <QProcess>
|
||||
|
||||
#include "Branding.h"
|
||||
#include "Settings.h"
|
||||
#include "utils/Retranslator.h"
|
||||
|
||||
FinishedPage::FinishedPage( QWidget* parent )
|
||||
#include <QFocusEvent>
|
||||
|
||||
|
||||
FinishedPage::FinishedPage( Config* config, QWidget* parent )
|
||||
: QWidget( parent )
|
||||
, ui( new Ui::FinishedPage )
|
||||
, m_mode( FinishedViewStep::RestartMode::UserUnchecked )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
@@ -38,68 +31,19 @@ FinishedPage::FinishedPage( QWidget* parent )
|
||||
ui->mainText->setWordWrap( true );
|
||||
ui->mainText->setOpenExternalLinks( true );
|
||||
|
||||
CALAMARES_RETRANSLATE(
|
||||
const auto* branding = Calamares::Branding::instance(); ui->retranslateUi( this );
|
||||
if ( Calamares::Settings::instance()->isSetupMode() ) {
|
||||
ui->mainText->setText( tr( "<h1>All done.</h1><br/>"
|
||||
"%1 has been set up on your computer.<br/>"
|
||||
"You may now start using your new system." )
|
||||
.arg( branding->versionedName() ) );
|
||||
ui->restartCheckBox->setToolTip( tr( "<html><head/><body>"
|
||||
"<p>When this box is checked, your system will "
|
||||
"restart immediately when you click on "
|
||||
"<span style=\"font-style:italic;\">Done</span> "
|
||||
"or close the setup program.</p></body></html>" ) );
|
||||
} else {
|
||||
ui->mainText->setText( tr( "<h1>All done.</h1><br/>"
|
||||
"%1 has been installed on your computer.<br/>"
|
||||
"You may now restart into your new system, or continue "
|
||||
"using the %2 Live environment." )
|
||||
.arg( branding->versionedName(), branding->productName() ) );
|
||||
ui->restartCheckBox->setToolTip( tr( "<html><head/><body>"
|
||||
"<p>When this box is checked, your system will "
|
||||
"restart immediately when you click on "
|
||||
"<span style=\"font-style:italic;\">Done</span> "
|
||||
"or close the installer.</p></body></html>" ) );
|
||||
} )
|
||||
}
|
||||
connect( config, &Config::restartModeChanged, [this]( Config::RestartMode mode ) {
|
||||
using Mode = Config::RestartMode;
|
||||
|
||||
|
||||
void
|
||||
FinishedPage::setRestart( FinishedViewStep::RestartMode mode )
|
||||
{
|
||||
using Mode = FinishedViewStep::RestartMode;
|
||||
|
||||
m_mode = mode;
|
||||
|
||||
ui->restartCheckBox->setVisible( mode != Mode::Never );
|
||||
ui->restartCheckBox->setEnabled( mode != Mode::Always );
|
||||
ui->restartCheckBox->setChecked( ( mode == Mode::Always ) || ( mode == Mode::UserChecked ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FinishedPage::setRestartNowCommand( const QString& command )
|
||||
{
|
||||
m_restartNowCommand = command;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FinishedPage::setUpRestart()
|
||||
{
|
||||
cDebug() << "FinishedPage::setUpRestart(), Quit button"
|
||||
<< "setup=" << FinishedViewStep::modeName( m_mode ) << "command=" << m_restartNowCommand;
|
||||
|
||||
connect( qApp, &QApplication::aboutToQuit, [this]() {
|
||||
if ( ui->restartCheckBox->isVisible() && ui->restartCheckBox->isChecked() )
|
||||
{
|
||||
cDebug() << "Running restart command" << m_restartNowCommand;
|
||||
QProcess::execute( "/bin/sh", { "-c", m_restartNowCommand } );
|
||||
}
|
||||
ui->restartCheckBox->setVisible( mode != Mode::Never );
|
||||
ui->restartCheckBox->setEnabled( mode != Mode::Always );
|
||||
} );
|
||||
connect( config, &Config::restartNowWantedChanged, ui->restartCheckBox, &QCheckBox::setChecked );
|
||||
connect( ui->restartCheckBox, &QCheckBox::stateChanged, [config]( int state ) {
|
||||
config->setRestartNowWanted( state != 0 );
|
||||
} );
|
||||
}
|
||||
|
||||
CALAMARES_RETRANSLATE_SLOT( &FinishedPage::retranslate );
|
||||
}
|
||||
|
||||
void
|
||||
FinishedPage::focusInEvent( QFocusEvent* e )
|
||||
@@ -110,19 +54,64 @@ FinishedPage::focusInEvent( QFocusEvent* e )
|
||||
void
|
||||
FinishedPage::onInstallationFailed( const QString& message, const QString& details )
|
||||
{
|
||||
const auto* branding = Calamares::Branding::instance();
|
||||
Q_UNUSED( details )
|
||||
if ( Calamares::Settings::instance()->isSetupMode() )
|
||||
ui->mainText->setText( tr( "<h1>Setup Failed</h1><br/>"
|
||||
"%1 has not been set up on your computer.<br/>"
|
||||
"The error message was: %2." )
|
||||
.arg( branding->versionedName() )
|
||||
.arg( message ) );
|
||||
else
|
||||
ui->mainText->setText( tr( "<h1>Installation Failed</h1><br/>"
|
||||
"%1 has not been installed on your computer.<br/>"
|
||||
"The error message was: %2." )
|
||||
.arg( branding->versionedName() )
|
||||
.arg( message ) );
|
||||
setRestart( FinishedViewStep::RestartMode::Never );
|
||||
m_failure = !message.isEmpty() ? message : details;
|
||||
retranslate();
|
||||
}
|
||||
|
||||
void
|
||||
FinishedPage::retranslate()
|
||||
{
|
||||
|
||||
const auto* branding = Calamares::Branding::instance();
|
||||
|
||||
ui->retranslateUi( this );
|
||||
if ( !m_failure.has_value() )
|
||||
{
|
||||
if ( Calamares::Settings::instance()->isSetupMode() )
|
||||
{
|
||||
ui->mainText->setText( tr( "<h1>All done.</h1><br/>"
|
||||
"%1 has been set up on your computer.<br/>"
|
||||
"You may now start using your new system." )
|
||||
.arg( branding->versionedName() ) );
|
||||
ui->restartCheckBox->setToolTip( tr( "<html><head/><body>"
|
||||
"<p>When this box is checked, your system will "
|
||||
"restart immediately when you click on "
|
||||
"<span style=\"font-style:italic;\">Done</span> "
|
||||
"or close the setup program.</p></body></html>" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->mainText->setText( tr( "<h1>All done.</h1><br/>"
|
||||
"%1 has been installed on your computer.<br/>"
|
||||
"You may now restart into your new system, or continue "
|
||||
"using the %2 Live environment." )
|
||||
.arg( branding->versionedName(), branding->productName() ) );
|
||||
ui->restartCheckBox->setToolTip( tr( "<html><head/><body>"
|
||||
"<p>When this box is checked, your system will "
|
||||
"restart immediately when you click on "
|
||||
"<span style=\"font-style:italic;\">Done</span> "
|
||||
"or close the installer.</p></body></html>" ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString message = m_failure.value();
|
||||
|
||||
if ( Calamares::Settings::instance()->isSetupMode() )
|
||||
{
|
||||
ui->mainText->setText( tr( "<h1>Setup Failed</h1><br/>"
|
||||
"%1 has not been set up on your computer.<br/>"
|
||||
"The error message was: %2." )
|
||||
.arg( branding->versionedName() )
|
||||
.arg( message ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->mainText->setText( tr( "<h1>Installation Failed</h1><br/>"
|
||||
"%1 has not been installed on your computer.<br/>"
|
||||
"The error message was: %2." )
|
||||
.arg( branding->versionedName() )
|
||||
.arg( message ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -11,10 +11,12 @@
|
||||
#ifndef FINISHEDPAGE_H
|
||||
#define FINISHEDPAGE_H
|
||||
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "FinishedViewStep.h"
|
||||
#include <optional>
|
||||
|
||||
class Config;
|
||||
namespace Ui
|
||||
{
|
||||
class FinishedPage;
|
||||
@@ -24,24 +26,19 @@ class FinishedPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FinishedPage( QWidget* parent = nullptr );
|
||||
explicit FinishedPage( Config* config, QWidget* parent = nullptr );
|
||||
|
||||
void setRestart( FinishedViewStep::RestartMode mode );
|
||||
void setRestartNowCommand( const QString& command );
|
||||
|
||||
void setUpRestart();
|
||||
|
||||
public slots:
|
||||
void onInstallationFailed( const QString& message, const QString& details );
|
||||
void retranslate();
|
||||
|
||||
protected:
|
||||
void focusInEvent( QFocusEvent* e ) override; //choose the child widget to focus
|
||||
|
||||
private:
|
||||
Ui::FinishedPage* ui;
|
||||
|
||||
FinishedViewStep::RestartMode m_mode;
|
||||
QString m_restartNowCommand;
|
||||
std::optional< QString > m_failure;
|
||||
};
|
||||
|
||||
#endif // FINISHEDPAGE_H
|
||||
|
@@ -10,42 +10,21 @@
|
||||
*/
|
||||
|
||||
#include "FinishedViewStep.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "FinishedPage.h"
|
||||
|
||||
#include "Branding.h"
|
||||
#include "JobQueue.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/NamedEnum.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
#include <QVariantMap>
|
||||
#include <QtDBus/QDBusConnection>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QtDBus/QDBusReply>
|
||||
|
||||
static const NamedEnumTable< FinishedViewStep::RestartMode >&
|
||||
modeNames()
|
||||
{
|
||||
using Mode = FinishedViewStep::RestartMode;
|
||||
|
||||
static const NamedEnumTable< Mode > names { { QStringLiteral( "never" ), Mode::Never },
|
||||
{ QStringLiteral( "user-unchecked" ), Mode::UserUnchecked },
|
||||
{ QStringLiteral( "user-checked" ), Mode::UserChecked },
|
||||
{ QStringLiteral( "always" ), Mode::Always } };
|
||||
|
||||
return names;
|
||||
}
|
||||
#include <QApplication>
|
||||
|
||||
FinishedViewStep::FinishedViewStep( QObject* parent )
|
||||
: Calamares::ViewStep( parent )
|
||||
, m_widget( new FinishedPage() )
|
||||
, installFailed( false )
|
||||
, m_notifyOnFinished( false )
|
||||
, m_config( new Config( this ) )
|
||||
, m_widget( new FinishedPage( m_config ) )
|
||||
, m_installFailed( false )
|
||||
{
|
||||
auto jq = Calamares::JobQueue::instance();
|
||||
connect( jq, &Calamares::JobQueue::failed, m_widget, &FinishedPage::onInstallationFailed );
|
||||
connect( jq, &Calamares::JobQueue::failed, this, &FinishedViewStep::onInstallationFailed );
|
||||
|
||||
emit nextStatusChanged( true );
|
||||
@@ -102,54 +81,12 @@ FinishedViewStep::isAtEnd() const
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FinishedViewStep::sendNotification()
|
||||
{
|
||||
// If the installation failed, don't send notification popup;
|
||||
// there's a (modal) dialog popped up with the failure notice.
|
||||
if ( installFailed )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusInterface notify(
|
||||
"org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications" );
|
||||
if ( notify.isValid() )
|
||||
{
|
||||
const auto* branding = Calamares::Branding::instance();
|
||||
QDBusReply< uint > r = notify.call(
|
||||
"Notify",
|
||||
QString( "Calamares" ),
|
||||
QVariant( 0U ),
|
||||
QString( "calamares" ),
|
||||
Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Complete" ) : tr( "Installation Complete" ),
|
||||
Calamares::Settings::instance()->isSetupMode()
|
||||
? tr( "The setup of %1 is complete." ).arg( branding->versionedName() )
|
||||
: tr( "The installation of %1 is complete." ).arg( branding->versionedName() ),
|
||||
QStringList(),
|
||||
QVariantMap(),
|
||||
QVariant( 0 ) );
|
||||
if ( !r.isValid() )
|
||||
{
|
||||
cWarning() << "Could not call org.freedesktop.Notifications.Notify at end of installation." << r.error();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Could not get dbus interface for notifications at end of installation." << notify.lastError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
FinishedViewStep::onActivate()
|
||||
{
|
||||
m_widget->setUpRestart();
|
||||
|
||||
if ( m_notifyOnFinished )
|
||||
{
|
||||
sendNotification();
|
||||
}
|
||||
m_config->doNotify( m_installFailed );
|
||||
connect( qApp, &QApplication::aboutToQuit, m_config, &Config::doRestart );
|
||||
}
|
||||
|
||||
|
||||
@@ -162,67 +99,15 @@ FinishedViewStep::jobs() const
|
||||
void
|
||||
FinishedViewStep::onInstallationFailed( const QString& message, const QString& details )
|
||||
{
|
||||
Q_UNUSED( message )
|
||||
Q_UNUSED( details )
|
||||
installFailed = true;
|
||||
m_installFailed = true;
|
||||
m_config->setRestartNowMode( Config::RestartMode::Never );
|
||||
m_widget->onInstallationFailed( message, details );
|
||||
}
|
||||
|
||||
void
|
||||
FinishedViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
RestartMode mode = RestartMode::Never;
|
||||
|
||||
QString restartMode = CalamaresUtils::getString( configurationMap, "restartNowMode" );
|
||||
if ( restartMode.isEmpty() )
|
||||
{
|
||||
if ( configurationMap.contains( "restartNowEnabled" ) )
|
||||
{
|
||||
cWarning() << "Configuring the finished module with deprecated restartNowEnabled settings";
|
||||
}
|
||||
|
||||
bool restartNowEnabled = CalamaresUtils::getBool( configurationMap, "restartNowEnabled", false );
|
||||
bool restartNowChecked = CalamaresUtils::getBool( configurationMap, "restartNowChecked", false );
|
||||
|
||||
if ( !restartNowEnabled )
|
||||
{
|
||||
mode = RestartMode::Never;
|
||||
}
|
||||
else
|
||||
{
|
||||
mode = restartNowChecked ? RestartMode::UserChecked : RestartMode::UserUnchecked;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool ok = false;
|
||||
mode = modeNames().find( restartMode, ok );
|
||||
if ( !ok )
|
||||
{
|
||||
cWarning() << "Configuring the finished module with bad restartNowMode" << restartMode;
|
||||
}
|
||||
}
|
||||
|
||||
m_widget->setRestart( mode );
|
||||
|
||||
if ( mode != RestartMode::Never )
|
||||
{
|
||||
QString restartNowCommand = CalamaresUtils::getString( configurationMap, "restartNowCommand" );
|
||||
if ( restartNowCommand.isEmpty() )
|
||||
{
|
||||
restartNowCommand = QStringLiteral( "shutdown -r now" );
|
||||
}
|
||||
m_widget->setRestartNowCommand( restartNowCommand );
|
||||
}
|
||||
|
||||
m_notifyOnFinished = CalamaresUtils::getBool( configurationMap, "notifyOnFinished", false );
|
||||
m_config->setConfigurationMap( configurationMap );
|
||||
}
|
||||
|
||||
QString
|
||||
FinishedViewStep::modeName( FinishedViewStep::RestartMode m )
|
||||
{
|
||||
bool ok = false;
|
||||
return modeNames().find( m, ok ); // May be QString()
|
||||
}
|
||||
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( FinishedViewStepFactory, registerPlugin< FinishedViewStep >(); )
|
||||
|
@@ -11,13 +11,11 @@
|
||||
#ifndef FINISHEDVIEWSTEP_H
|
||||
#define FINISHEDVIEWSTEP_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "DllMacro.h"
|
||||
#include "utils/PluginFactory.h"
|
||||
#include "viewpages/ViewStep.h"
|
||||
|
||||
#include "DllMacro.h"
|
||||
|
||||
class Config;
|
||||
class FinishedPage;
|
||||
|
||||
class PLUGINDLLEXPORT FinishedViewStep : public Calamares::ViewStep
|
||||
@@ -25,16 +23,6 @@ class PLUGINDLLEXPORT FinishedViewStep : public Calamares::ViewStep
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class RestartMode
|
||||
{
|
||||
Never = 0, ///< @brief Don't show button, just exit
|
||||
UserUnchecked, ///< @brief Show button, starts unchecked
|
||||
UserChecked, ///< @brief Show button, starts checked
|
||||
Always ///< @brief Show button, can't change, checked
|
||||
};
|
||||
/// @brief Returns the config-name of the given restart-mode @p m
|
||||
static QString modeName( RestartMode m );
|
||||
|
||||
explicit FinishedViewStep( QObject* parent = nullptr );
|
||||
~FinishedViewStep() override;
|
||||
|
||||
@@ -58,16 +46,9 @@ public slots:
|
||||
void onInstallationFailed( const QString& message, const QString& details );
|
||||
|
||||
private:
|
||||
Config* m_config;
|
||||
FinishedPage* m_widget;
|
||||
|
||||
/**
|
||||
* @brief At the end of installation (when this step is activated),
|
||||
* send a desktop notification via DBus that the install is done.
|
||||
*/
|
||||
void sendNotification();
|
||||
|
||||
bool installFailed;
|
||||
bool m_notifyOnFinished;
|
||||
bool m_installFailed; // Track if onInstallationFailed() was called
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( FinishedViewStepFactory )
|
||||
|
@@ -6,3 +6,4 @@
|
||||
#layout additional-layout additional-variant vconsole-keymap
|
||||
ru us - ruwin_alt_sh-UTF-8
|
||||
ua us - ua-utf
|
||||
gr us - gr
|
||||
|
@@ -1,18 +1,89 @@
|
||||
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||
# SPDX-FileContributor: benne-dee ( worked on groups schema )
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
---
|
||||
$schema: https://json-schema.org/schema#
|
||||
$schema: https://json-schema.org/draft-07/schema#
|
||||
$id: https://calamares.io/schemas/netinstall
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
groupsUrl: { type: string }
|
||||
required: { type: boolean, default: false }
|
||||
label: # Translatable labels
|
||||
definitions:
|
||||
package:
|
||||
$id: '#definitions/package'
|
||||
oneOf:
|
||||
-
|
||||
type: string
|
||||
description: bare package - actual package name as passed to the package manager
|
||||
(e.g. `qt5-creator-dev`).
|
||||
-
|
||||
type: object
|
||||
description: rich package - one with a package-name (for the package-manager) and
|
||||
a description (for the human).
|
||||
properties:
|
||||
name: { type: string }
|
||||
description: { type: string }
|
||||
group:
|
||||
$id: '#definitions/group'
|
||||
type: object
|
||||
additionalProperties: true
|
||||
description: Longer discussion in `netinstall.conf` file under 'Groups Format'
|
||||
properties:
|
||||
sidebar: { type: string }
|
||||
title: { type: string }
|
||||
groups: { type: array } # TODO: the schema for the whole groups file
|
||||
required: [ groupsUrl ]
|
||||
name: { type: string }
|
||||
description: { type: string }
|
||||
packages:
|
||||
type: array
|
||||
items: { $ref: '#definitions/package' }
|
||||
hidden: { type: boolean, default: false }
|
||||
selected: { type: boolean }
|
||||
critical: { type: boolean, default: false }
|
||||
immutable: { type: boolean }
|
||||
expanded: { type: boolean }
|
||||
subgroups:
|
||||
type: array
|
||||
items: { $ref: '#definitions/group' }
|
||||
pre-install:
|
||||
type: string
|
||||
description: an optional command to run within the new system before the group's
|
||||
packages are installed. It will run before **each** package in the group
|
||||
is installed.
|
||||
post-install:
|
||||
type: string
|
||||
description: an optional command to run within the new system after the group's
|
||||
packages are installed. It will run after **each** package in the group
|
||||
is installed.
|
||||
required: [name, description] # Always required, at any level in the subgroups hirearchy
|
||||
if:
|
||||
properties:
|
||||
subgroups:
|
||||
maxItems: 0
|
||||
then:
|
||||
required: [name, description, packages] # bottom-most (sub)group requires some package (otherwise, why bother?)
|
||||
# This should validate `netinstall.yaml` also.
|
||||
groups:
|
||||
$id: '#definitions/groups'
|
||||
type: array
|
||||
items: { $ref: '#definitions/group' }
|
||||
|
||||
oneOf:
|
||||
- # netinstall.conf
|
||||
type: object
|
||||
description: netinstall.conf schema
|
||||
additionalProperties: false
|
||||
properties:
|
||||
groupsUrl: { type: string }
|
||||
required: { type: boolean, default: false }
|
||||
label: # Translatable labels
|
||||
type: object
|
||||
additionalProperties: true
|
||||
properties:
|
||||
sidebar: { type: string }
|
||||
title: { type: string }
|
||||
groups: { $ref: '#definitions/groups' }
|
||||
required: [ groupsUrl ]
|
||||
|
||||
- # Groups file with top level *groups* key
|
||||
type: object
|
||||
description: Groups file with top level *groups* key
|
||||
additionalProperties: false
|
||||
properties:
|
||||
groups: { $ref: '#definitions/groups' }
|
||||
required: [ groups ]
|
||||
|
||||
- # Groups file bare
|
||||
{ $ref: '#definitions/groups' }
|
||||
|
@@ -10,14 +10,19 @@
|
||||
# can check requirements for installation.
|
||||
---
|
||||
# Display settings for various buttons on the welcome page.
|
||||
# The URLs themselves come from branding.desc is the setting
|
||||
# here is "true". If the setting is false, the button is hidden.
|
||||
# The URLs themselves come from `branding.desc`. Each button
|
||||
# is show if the corresponding *show<buttonname>* setting
|
||||
# here is "true". If the setting is "false", the button is hidden.
|
||||
# Empty or not-set is interpreted as "false".
|
||||
#
|
||||
# TODO:3.3 Remove the URL fallback here; URLs only in `branding.desc`
|
||||
#
|
||||
# The setting can also be a full URL which will then be used
|
||||
# instead of the one from the branding file, or empty or not-set
|
||||
# which will hide the button.
|
||||
# instead of the one from the branding file.
|
||||
showSupportUrl: true
|
||||
showKnownIssuesUrl: true
|
||||
showReleaseNotesUrl: false
|
||||
# TODO:3.3 Move to branding, keep only a bool here
|
||||
showDonateUrl: https://kde.org/community/donations/
|
||||
|
||||
# Requirements checking. These are general, generic, things
|
||||
@@ -26,7 +31,7 @@ showDonateUrl: https://kde.org/community/donations/
|
||||
requirements:
|
||||
# Amount of available disk, in GiB. Floating-point is allowed here.
|
||||
# Note that this does not account for *usable* disk, so it is possible
|
||||
# to pass this requirement, yet have no space to install to.
|
||||
# to satisfy this requirement, yet have no space to install to.
|
||||
requiredStorage: 5.5
|
||||
|
||||
# Amount of available RAM, in GiB. Floating-point is allowed here.
|
||||
@@ -34,7 +39,10 @@ requirements:
|
||||
|
||||
# To check for internet connectivity, Calamares does a HTTP GET
|
||||
# on this URL; on success (e.g. HTTP code 200) internet is OK.
|
||||
internetCheckUrl: http://google.com
|
||||
# Use a privacy-respecting URL here, preferably in your distro's domain.
|
||||
#
|
||||
# The URL is only used if "internet" is in the *check* list below.
|
||||
internetCheckUrl: http://example.com
|
||||
|
||||
# List conditions to check. Each listed condition will be
|
||||
# probed in some way, and yields true or false according to
|
||||
|
Reference in New Issue
Block a user