Merge branch 'development' into 3.2.x-stable

This commit is contained in:
Philip Müller 2020-02-16 10:33:38 +01:00
commit b4652936b7
88 changed files with 2705 additions and 971 deletions

View File

@ -11,3 +11,8 @@ trim_trailing_whitespace = true
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
insert_final_newline = true insert_final_newline = true
[*.sh]
indent_style = tab
insert_final_newline = true

12
CHANGES
View File

@ -6,7 +6,9 @@ website will have to do for older versions.
# 3.2.19 (unreleased) # # 3.2.19 (unreleased) #
This release contains contributions from (alphabetically by first name): This release contains contributions from (alphabetically by first name):
- No other contributors this time around. - Anke Boersma
- Camilo Higuita
- Gabriel Craciunescu
## Core ## ## Core ##
- *Assamese* translation has been completed. - *Assamese* translation has been completed.
@ -17,10 +19,18 @@ This release contains contributions from (alphabetically by first name):
translations without requiring a recompile: helpful for translators translations without requiring a recompile: helpful for translators
and possibly for distributions with their own translation style. and possibly for distributions with their own translation style.
See the translators and deployers wiki for details. See the translators and deployers wiki for details.
- A new `ViewStep` base class, `QmlViewStep`, has been added that loads
a configurable QML file and plays it. This is used by the new *notesqml*
module -- which is in itself a minimal wrapper around the same that
adds only a translatable module name.
## Modules ## ## Modules ##
- The *machineid* and *users* modules now prefer high-quality random - The *machineid* and *users* modules now prefer high-quality random
data from `/dev/urandom` rather than pseudo-random data. #1254 data from `/dev/urandom` rather than pseudo-random data. #1254
- A new *notesqml* module supports loading QML. This can be used for
"fancy" release notes as a QML application, rather than a webview
or text widget. Note that this does not replace the slideshow-during-
installation module.
# 3.2.18 (2020-01-28) # # 3.2.18 (2020-01-28) #

View File

@ -2,12 +2,11 @@
--------- ---------
[![GitHub release](https://img.shields.io/github/release/calamares/calamares.svg)](https://github.com/calamares/calamares/releases) [![GitHub release](https://img.shields.io/github/release/calamares/calamares.svg)](https://github.com/calamares/calamares/releases)
[![Build Status](https://calamares.io/ci/buildStatus/icon?job=calamares-post_commit)](https://calamares.io/ci/job/calamares-post_commit/)
[![Travis Build Status](https://travis-ci.org/calamares/calamares.svg?branch=master)](https://travis-ci.org/calamares/calamares) [![Travis Build Status](https://travis-ci.org/calamares/calamares.svg?branch=master)](https://travis-ci.org/calamares/calamares)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/5389/badge.svg)](https://scan.coverity.com/projects/5389) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5389/badge.svg)](https://scan.coverity.com/projects/5389)
[![GitHub license](https://img.shields.io/github/license/calamares/calamares.svg)](https://github.com/calamares/calamares/blob/master/LICENSE) [![GitHub license](https://img.shields.io/github/license/calamares/calamares.svg)](https://github.com/calamares/calamares/blob/master/LICENSE)
| [Report a Bug](https://github.com/calamares/calamares/issues/new) | [Contribute](https://github.com/calamares/calamares/blob/master/ci/HACKING.md) | [Translate](https://www.transifex.com/projects/p/calamares/) | Freenode (IRC): #calamares | [Wiki](https://github.com/calamares/calamares/wiki) | | [Report a Bug](https://github.com/calamares/calamares/issues/new) | [Translate](https://www.transifex.com/projects/p/calamares/) | [Contribute](https://github.com/calamares/calamares/wiki/Develop-Guide) | Freenode (IRC): #calamares | [Wiki](https://github.com/calamares/calamares/wiki) |
|:-----------------------------------------:|:----------------------:|:-----------------------:|:--------------------------:|:--------------------------:| |:-----------------------------------------:|:----------------------:|:-----------------------:|:--------------------------:|:--------------------------:|
### Dependencies ### Dependencies

View File

@ -1,211 +1 @@
Hacking on Calamares This has moved [to the wiki](https://github.com/calamares/calamares/wiki/Develop-Code).
====================
These are the guidelines for hacking on Calamares. Except for the licensing,
which **must** be GPLv3+, these are guidelines and -- like PEP8 -- the most
important thing is to know when you can ignore them.
Licensing
---------
Calamares is released under the terms of the GNU GPL, version 3 or later.
Every source file must have a license header, with a list of copyright holders and years.
Example:
```
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2013-2014, Random Person <name@example.com>
* Copyright 2010, Someone Else <someone@example.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
```
Copyright holders must be physical or legal personalities. A statement such as
`Copyright 2014, The FooBarQuux project` has no legal value if "The FooBarQuux
project" is not the legal name of a person, company, incorporated
organization, etc.
Please add your name to files you touch when making any contribution (even if
it's just a typo-fix which might not be copyrightable in all jurisdictions).
Formatting C++
--------------
This formatting guide applies to C++ code only; for Python modules, we use
[pycodestyle](https://github.com/PyCQA/pycodestyle) to apply a check of
some PEP8 guidelines.
* Spaces, not tabs.
* Indentation is 4 spaces.
* Lines should be limited to 90 characters.
* Spaces between brackets and argument functions, including for template arguments
* No space before brackets, except for keywords, for example `function( argument )` but
`if ( condition )`.
* For pointer and reference variable declarations, put a space before the variable name
and no space between the type and the `*` or `&`, e.g. `int* p`.
* `for`, `if`, `else`, `while` and similar statements put the braces on the next line,
if the following block is more than one statement. Always use braces.
* Function and class definitions have their braces on separate lines.
* A function implementation's return type is on its own line.
* `CamelCase.{cpp,h}` style file names.
* Lambdas are preferrably indented to a 4-space tab, even when passed as an
argument to functions.
Example:
```
bool
MyClass::myMethod( QStringList list, const QString& name )
{
if ( list.isEmpty() )
return false;
cDebug() << "Items in list ..";
foreach ( const QString& string, list )
cDebug() << " .." << string;
switch ( m_enumValue )
{
case Something:
return true;
case SomethingElse:
doSomething();
break;
}
}
```
You can use `clang-format` (version 7) to have Calamares sources formatted
the right way. There is a `.clang-format` file that specifies the details.
In general:
```
$ clang-format-7 -i -style=file <files>
```
`
**NOTE:** An .editorconfig file is included to assist with formatting. In
order to take advantage of this functionality you will need to acquire the
[EditorConfig](http://editorconfig.org/#download) plug-in for your editor.
Naming
------
* Use CamelCase for everything.
* Local variables should start out with a lowercase letter.
* Class names are capitalized
* Prefix class member variables with `m_`, e.g. `m_queue`.
* Prefix static member variables with `s_`, e.g. `s_instance`.
* Functions are named in the Qt style, like Java's, without the 'get' prefix.
* A getter is `variable()`.
* If it's a getter for a boolean, prefix with 'is', so `isCondition()`.
* A setter is `setVariable( arg )`.
Includes
--------
Header includes should be listed in the following order:
* own header,
* Calamares includes,
* includes for Qt-based libraries,
* Qt includes,
* other includes.
They should also be sorted alphabetically for ease of locating them.
Includes in a header file should be kept to the absolute minimum, as to keep
compile times short. This can be achieved by using forward declarations
instead of includes, like `class QListView;`.
Example:
```
#include "Settings.h"
#include "CalamaresApplication.h"
#include "utils/CalamaresUtils.h"
#include "utils/Logger.h"
#include "YamlUtils.h"
#include <QDir>
#include <QFile>
#include <yaml-cpp/yaml.h>
```
Use include guards, not `#pragma once`.
C++ tips
--------
All C++11 features are acceptable, and the use of new C++11 features is encouraged when
it makes the code easier to understand and more maintainable.
The use of `nullptr` is preferred over the use of `0` or `NULL`.
For Qt containers it is better to use Qt's own `foreach`. For all other containers, the
range-based `for` syntax introduced with C++11 is preferred ([see this blog post][1]).
When re-implementing a virtual method, always add the `override` keyword.
Try to keep your code const correct. Declare methods const if they don't mutate the
object, and use const variables. It improves safety, and also makes it easier to
understand the code.
For the Qt signal-slot system, the new (Qt5) syntax is to be preferred because it allows
the compiler to check for the existence of signals and slots. As an added benefit, the
new syntax can also be used with `tr1::bind` and C++11 lambdas. For more information, see
the [Qt wiki][2].
Example:
```
connect( m_next, &QPushButton::clicked, this, &ViewManager::next );
connect( m_moduleManager, &Calamares::ModuleManager::modulesLoaded, [this]
{
m_mainwindow->show();
});
```
[1]: http://blog.qt.digia.com/blog/2011/05/26/cpp0x-in-qt/
[2]: http://qt-project.org/wiki/New_Signal_Slot_Syntax
Debugging
---------
Use `cDebug()` from `utils/Logger.h`. You can pass a debug-level to the
macro (6 is debugging, higher is less important). Use `cWarning()` for warning
messages (equivalent to level 2) and `cError()` for errors (level 1). Warnings
and errors will add relevant text automatically. See `libcalamares/utils/Logger.h`
for details.
For log messages that are continued across multiple calls to `cDebug()`,
in particular listing things, conventional formatting is as follows:
* End the first debug message with ` ..`
* Start the next debug message by outputting `Logger::SubEntry`
For single-outputs that need to be split across multiplt lines,
output `Logger::Continuation`.
Commit Messages
---------------
Keep commit messages short(-ish) and try to describe what is being changed
*as well as why*. Use the commit keywords for GitHub, especially *FIXES:*
to auto-close issues when they are resolved.
For functional changes to Calamares modules or libraries, try to put
*[modulename]* in front of the first line of the commit message.
For non-functional changes to infrastructure, try to label the change
with the kind of change, e.g. *CMake* or *i18n* or *Documentation*.

View File

@ -1,17 +1,16 @@
The Calamares release process # Calamares Release Process
=============================
> As releases from *master* are now rolling when-they-are-ready releases, > Calamares releases are now rolling when-they-are-ready releases.
> some of these steps no longer are followed. In particular, -RC releases > Releases are made from *master* and tagged there. When, in future,
> are not done anymore (although the RC variable is set in `CMakeLists.txt` > LTS releases resume, these steps may be edited again.
> to avoid accidents) and most things are automated through the release >
> script [RELEASE.sh](RELEASE.sh) > Most things are automated through the release script [RELEASE.sh](RELEASE.sh)
#### (0) A week in advance ## (0) A week in advance
* (Only releases from master) * Run [Coverity scan][coverity], fix what's relevant. The Coverity scan runs
Run [Coverity scan][coverity], fix what's relevant. The Coverity scan runs automatically once a week on master. The badge is displayed on the
automatically once a week on master. project front page and in the wiki.
* Build with clang -Weverything, fix what's relevant. * Build with clang -Weverything, fix what's relevant.
``` ```
rm -rf build ; mkdir build ; cd build rm -rf build ; mkdir build ; cd build
@ -26,34 +25,69 @@ The Calamares release process
an additional environment variable to be set for some tests, which will an additional environment variable to be set for some tests, which will
destroy an attached disk. This is not always desirable. There are some destroy an attached disk. This is not always desirable. There are some
sample config-files that are empty and which fail the config-tests. sample config-files that are empty and which fail the config-tests.
* (Only releases from master) * Notify [translators][transifex]. In the dashboard there is an *Announcements*
Notify [translators][transifex]. In the dashboard there is an *Announcements* link that you can use to send a translation announcement. Note that regular
link that you can use to send a translation announcement. use of `txpush.sh` will notify translators as well of any changes.
[coverity]: https://scan.coverity.com/projects/calamares-calamares?tab=overview [coverity]: https://scan.coverity.com/projects/calamares-calamares?tab=overview
[transifex]: https://www.transifex.com/calamares/calamares/dashboard/ [transifex]: https://www.transifex.com/calamares/calamares/dashboard/
#### (1) Preparation
* Bump version in `CMakeLists.txt`, *CALAMARES_VERSION* variables, and set ## (1) Preparation
RC to a non-zero value (e.g. doing -rc1, -rc2, ...). Push that.
* Check `README.md` and everything `ci/HACKING.md`, make sure it's all still * Pull latest translations from Transifex. We only push / pull translations
relevant. Run `ci/calamaresstyle` to check the C++ code style.
Run pycodestyle on recently-modified Python modules, fix what makes sense.
* Check defaults in `settings.conf` and other configuration files.
* (Only releases from master)
Pull latest translations from Transifex. We only push / pull translations
from master, so longer-lived branches (e.g. 3.1.x) don't get translation from master, so longer-lived branches (e.g. 3.1.x) don't get translation
updates. This is to keep the translation workflow simple. updates. This is to keep the translation workflow simple. The script
automatically commits changes to the translations.
``` ```
sh ci/txpull.sh sh ci/txpull.sh
``` ```
* (Only releases from master) * Update the list of enabled translation languages in `CMakeLists.txt`.
Update the list of enabled translation languages in `CMakeLists.txt`.
Check the [translation site][transifex] for the list of languages with Check the [translation site][transifex] for the list of languages with
fairly complete translations. fairly complete translations, or use `ci/txstats.py` for an automated
suggestion. If there are changes, commit them.
* Push the changes.
* Drop the RC variable to 0 in `CMakeLists.txt`, *CALAMARES_VERSION_RC*.
* Check `README.md` and the
[Coding Guide](https://github.com/calamares/calamares/wiki/Develop-Code),
make sure it's all still
relevant. Run `ci/calamaresstyle` to check the C++ code style.
Run pycodestyle on recently-modified Python modules, fix what makes sense.
* Check defaults in `settings.conf` and other configuration files.
* Edit `CHANGES` and set the date of the release.
* Commit both. This is usually done with commit-message
*Changes: pre-release housekeeping*.
#### (2) Tarball
## (2) Release Day
* Run the helper script `ci/RELEASE.sh` or follow steps below.
The script checks:
- for uncommitted local changes,
- if translations are up-to-date and translators
have had enough time to chase new strings,
- that the build is successful (with gcc and clang, if available),
- tests pass,
- tarball can be created,
- tarball can be signed.
On success, it prints out a suitable signature- and SHA256 blurb
for use in the release announcement.
### (2.1) Buld and Test
* Build with gcc. If available, build again with Clang and double-check
any warnings Clang produces.
* Run the tests; `make test` in the build directory should have no
failures (or if there are, know why they are there).
### (2.2) Tag
* `git tag -s v1.1.0` Make sure the signing key is known in GitHub, so that the
tag is shown as a verified tag. Do not sign -rc tags.
You can use `make show-version` in the build directory to get the right
version number -- this will fail if you didn't follow step (1).
### (2.3) Tarball
* Create tarball: `git-archive-all -v calamares-1.1-rc1.tar.gz` or without * Create tarball: `git-archive-all -v calamares-1.1-rc1.tar.gz` or without
the helper script, the helper script,
@ -64,21 +98,25 @@ The Calamares release process
Double check that the tarball matches the version number. Double check that the tarball matches the version number.
* Test tarball (e.g. unpack somewhere else and run the tests from step 0). * Test tarball (e.g. unpack somewhere else and run the tests from step 0).
#### (3) Tag
* Set RC to zero in `CMakeLists.txt` if this is the actual release. ## (3) Housekeeping
* `git tag -s v1.1.0` Make sure the signing key is known in GitHub, so that the
tag is shown as a verified tag. Do not sign -rc tags.
* Generate MD5 and SHA256 checksums. * Generate MD5 and SHA256 checksums.
* Upload tarball. * Upload tarball.
* Announce on mailing list, notify packagers. * Announce on mailing list, notify packagers.
* Write release article. * Write release article.
#### (4) Release day
* Publish tarball. * Publish tarball.
* Update download page. * Update download page.
* Publish release article on `calamares.io`. * Publish release article on `calamares.io`.
* Publicize on social networks. * Publicize on social networks.
* Close associated milestone on GitHub if this is the actual release. * Close associated milestone on GitHub if this is the actual release.
* Publish blog post. * Publish blog post.
## (4) Post-Release
* Bump the version number in `CMakeLists.txt` in the `project()` command.
* Set *CALAMARES_VERSION_RC* back to 1.
* Add a placeholder entry for the next release in `CHANGES` with date
text *not released yet*.
* Commit and push that, usually with the message
*Changes: post-release housekeeping*.

View File

@ -1,5 +1,18 @@
#! /bin/sh #! /bin/sh
### LICENSE
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# SPDX-License-Identifier: BSD-2-Clause
# SPDX-FileCopyrightText: 2019-2020 Adriaan de Groot <groot@kde.org>
#
# This file is Free Software: you can redistribute it and/or modify
# it under the terms of the 2-clause BSD License.
#
### END LICENSE
### USAGE
#
# Does the translation tag (from a previous txpush) exist? # Does the translation tag (from a previous txpush) exist?
# This assumes that the release host has also locally done # This assumes that the release host has also locally done
# a translations push, which works for the current development # a translations push, which works for the current development
@ -7,6 +20,13 @@
# the typical txpush log messages instead of the tag. # the typical txpush log messages instead of the tag.
# #
# Use --cleanup as an argument to clean things up. # Use --cleanup as an argument to clean things up.
#
# Normal use:
# $ sh ci/txcheck.sh
# If there are differences, fix them and then clean up:
# $ sh ci/txcheck.sh --cleanup
#
### END USAGE
# The files that are translated; should match the contents of .tx/config # The files that are translated; should match the contents of .tx/config
TX_FILE_LIST="lang/calamares_en.ts lang/python.pot src/modules/dummypythonqt/lang/dummypythonqt.pot calamares.desktop" TX_FILE_LIST="lang/calamares_en.ts lang/python.pot src/modules/dummypythonqt/lang/dummypythonqt.pot calamares.desktop"
@ -17,15 +37,18 @@ TX_FILE_LIST="lang/calamares_en.ts lang/python.pot src/modules/dummypythonqt/lan
# normally used much later in the script. # normally used much later in the script.
tx_cleanup() tx_cleanup()
{ {
# Cleanup artifacs of checking # Cleanup artifacs of checking
git worktree remove --force build-txcheck-head git worktree remove --force build-txcheck-head
git worktree remove --force build-txcheck-prev git worktree remove --force build-txcheck-prev
git branch -D build-txcheck-head > /dev/null 2>&1 git branch -D build-txcheck-head > /dev/null 2>&1
} }
if test "x$1" = "x--cleanup" ; then if test "x$1" = "x--cleanup" ; then
tx_cleanup tx_cleanup
exit 0 exit 0
fi
if test "x$1" = "x--help" ; then
sed -e '1,/USAGE/d' -e '/END.USAGE/,$d' < "$0"
fi fi
test -z "$1" || { echo "! Usage: txcheck.sh [--cleanup]" ; exit 1 ; } test -z "$1" || { echo "! Usage: txcheck.sh [--cleanup]" ; exit 1 ; }
@ -36,22 +59,22 @@ test -z "$1" || { echo "! Usage: txcheck.sh [--cleanup]" ; exit 1 ; }
XMLLINT="" XMLLINT=""
for _xmllint in xmllint for _xmllint in xmllint
do do
$_xmllint --version > /dev/null 2>&1 && XMLLINT=$_xmllint $_xmllint --version > /dev/null 2>&1 && XMLLINT=$_xmllint
test -n "$XMLLINT" && break test -n "$XMLLINT" && break
done done
# Distinguish GNU date from BSD date # Distinguish GNU date from BSD date
if date +%s -d "1 week ago" > /dev/null 2>&1 ; then if date +%s -d "1 week ago" > /dev/null 2>&1 ; then
last_week() { date +%s -d "1 week ago" ; } last_week() { date +%s -d "1 week ago" ; }
else else
last_week() { date -v1w +%s; } last_week() { date -v1w +%s; }
fi fi
# Distinguish GNU SHA executables from BSD ones # Distinguish GNU SHA executables from BSD ones
if which sha256sum > /dev/null 2>&1 ; then if which sha256sum > /dev/null 2>&1 ; then
SHA256=sha256sum SHA256=sha256sum
else else
SHA256=sha256 SHA256=sha256
fi fi
### CHECK WORKING DIRECTORY ### CHECK WORKING DIRECTORY
@ -67,6 +90,8 @@ fi
if test `git describe` = `git describe --dirty` ; then if test `git describe` = `git describe --dirty` ; then
: :
else else
# Don't want any local changes, since those won't be
# reflected in the worktrees and we might miss a string change.
echo "! There are local changes." echo "! There are local changes."
exit 1 exit 1
fi fi
@ -75,13 +100,20 @@ DATE_PREV=$( git log -1 translation --date=unix | sed -e '/^Date:/s+.*:++p' -e d
DATE_HEAD=$( last_week ) DATE_HEAD=$( last_week )
test "$DATE_PREV" -le "$DATE_HEAD" || { echo "! Translation tag has not aged enough." ; git log -1 translation ; exit 1 ; } test "$DATE_PREV" -le "$DATE_HEAD" || { echo "! Translation tag has not aged enough." ; git log -1 translation ; exit 1 ; }
# Tag is good, do real work of checking strings: collect names of relevant files # Tag is good, check that necessary files exist. The list of
# files is hard-coded, but should match what is in the Transifex config.
test -f ".tx/config" || { echo "! No Transifex configuration is present." ; exit 1 ; } test -f ".tx/config" || { echo "! No Transifex configuration is present." ; exit 1 ; }
for f in $TX_FILE_LIST ; do for f in $TX_FILE_LIST ; do
test -f $f || { echo "! Translation file '$f' does not exist." ; exit 1 ; } test -f $f || { echo "! Translation file '$f' does not exist." ; exit 1 ; }
done done
# The state of translations ### COMPARE TRANSLATIONS
#
#
# The state of translations; assume that sha256 is enough
# to distinguish changed translations when we cat all the
# string sources together.
tx_sum() tx_sum()
{ {
CURDIR=`pwd` CURDIR=`pwd`

View File

@ -1,4 +1,18 @@
#!/bin/sh #!/bin/sh
### LICENSE
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# SPDX-License-Identifier: BSD-2-Clause
# SPDX-FileCopyrightText: 2017-2020 Adriaan de Groot <groot@kde.org>
# SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac <teo@kde.org>
#
# This file is Free Software: you can redistribute it and/or modify
# it under the terms of the 2-clause BSD License.
#
### END LICENSE
### USAGE
# #
# Fetch the Transifex translations for Calamares and incorporate them # Fetch the Transifex translations for Calamares and incorporate them
# into the source tree, adding commits of the different files. # into the source tree, adding commits of the different files.
@ -6,6 +20,8 @@
# Run this (occasionally) at the top-level directory to get # Run this (occasionally) at the top-level directory to get
# new translations. See also CMakeLists.txt and ci/txstats.py # new translations. See also CMakeLists.txt and ci/txstats.py
# for update instructions. # for update instructions.
#
### END USAGE
### INITIAL SETUP ### INITIAL SETUP
# #
@ -32,8 +48,8 @@ test -f "calamares.desktop" || { echo "! Not at Calamares top-level" ; exit 1 ;
XMLLINT="" XMLLINT=""
for _xmllint in xmllint for _xmllint in xmllint
do do
$_xmllint --version > /dev/null 2>&1 && XMLLINT=$_xmllint $_xmllint --version > /dev/null 2>&1 && XMLLINT=$_xmllint
test -n "$XMLLINT" && break test -n "$XMLLINT" && break
done done
# XMLLINT is optional # XMLLINT is optional
@ -53,9 +69,9 @@ tx pull --force --source --all
# so clean them up after pulling. # so clean them up after pulling.
# #
drop_language() { drop_language() {
rm -rf lang/python/"$1" src/modules/dummypythonqt/lang/"$1" lang/calamares_"$1".ts rm -rf lang/python/"$1" src/modules/dummypythonqt/lang/"$1" lang/calamares_"$1".ts
grep -v "\\[$1]" calamares.desktop > calamares.desktop.new grep -v "\\[$1]" calamares.desktop > calamares.desktop.new
mv calamares.desktop.new calamares.desktop mv calamares.desktop.new calamares.desktop
} }
drop_language es_ES drop_language es_ES
@ -68,10 +84,10 @@ mv calamares.desktop.new calamares.desktop
# And fixup the XML files like in txpush.sh # And fixup the XML files like in txpush.sh
if test -n "$XMLLINT" ; then if test -n "$XMLLINT" ; then
for TS_FILE in lang/calamares_*.ts for TS_FILE in lang/calamares_*.ts
do do
$XMLLINT --c14n11 "$TS_FILE" | { echo "<!DOCTYPE TS>" ; cat - ; } | $XMLLINT --format --encode utf-8 -o "$TS_FILE".new - && mv "$TS_FILE".new "$TS_FILE" $XMLLINT --c14n11 "$TS_FILE" | { echo "<!DOCTYPE TS>" ; cat - ; } | $XMLLINT --format --encode utf-8 -o "$TS_FILE".new - && mv "$TS_FILE".new "$TS_FILE"
done done
fi fi
@ -108,24 +124,24 @@ git diff --numstat src/modules | awk '($1==1 && $2==1){print $3}' | xargs git ch
# Go through the Python modules; those with a lang/ subdir have their # Go through the Python modules; those with a lang/ subdir have their
# own complete gettext-based setup. # own complete gettext-based setup.
for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do
FILES=$(find "$MODULE_DIR" -name "*.py" -a -type f) FILES=$(find "$MODULE_DIR" -name "*.py" -a -type f)
if test -n "$FILES" ; then if test -n "$FILES" ; then
MODULE_NAME=$(basename ${MODULE_DIR}) MODULE_NAME=$(basename ${MODULE_DIR})
if [ -d ${MODULE_DIR}/lang ]; then if [ -d ${MODULE_DIR}/lang ]; then
# Convert PO files to MO files # Convert PO files to MO files
for POFILE in $(find ${MODULE_DIR} -name "*.po") ; do for POFILE in $(find ${MODULE_DIR} -name "*.po") ; do
sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE
msgfmt -o ${POFILE%.po}.mo $POFILE msgfmt -o ${POFILE%.po}.mo $POFILE
done done
git add --verbose ${MODULE_DIR}/lang/* git add --verbose ${MODULE_DIR}/lang/*
git commit "$AUTHOR" --message="i18n: [${MODULE_NAME}] $BOILERPLATE" | true git commit "$AUTHOR" --message="i18n: [${MODULE_NAME}] $BOILERPLATE" | true
fi fi
fi fi
done done
for POFILE in $(find lang -name "python.po") ; do for POFILE in $(find lang -name "python.po") ; do
sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE
msgfmt -o ${POFILE%.po}.mo $POFILE msgfmt -o ${POFILE%.po}.mo $POFILE
done done
git add --verbose lang/python* git add --verbose lang/python*
git commit "$AUTHOR" --message="i18n: [python] $BOILERPLATE" | true git commit "$AUTHOR" --message="i18n: [python] $BOILERPLATE" | true

View File

@ -1,13 +1,33 @@
#!/bin/sh #!/bin/sh
### LICENSE
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# SPDX-License-Identifier: BSD-2-Clause
# SPDX-FileCopyrightText: 2017-2020 Adriaan de Groot <groot@kde.org>
# SPDX-FileCopyrightText: 2015-2016 Teo Mrnjavac <teo@kde.org>
#
# This file is Free Software: you can redistribute it and/or modify
# it under the terms of the 2-clause BSD License.
#
### END LICENSE
### USAGE
# #
# Extract translations from Calamares source and send them # Extract translations from Calamares source and send them
# to Transifex. # to Transifex. Also (forcibly) updates the git "translation"
# tag to document that source texts were updated and sent;
# this is used by txcheck.sh to ensure that there's enough
# time between updates and releases, and that strings don't
# change between updates and releases.
# #
# Run this at the top-level. # Run this at the top-level.
# #
# Use the --no-tx option to do the extraction, but not the # Use the --no-tx option to do the extraction, but not the
# pushing-to-Transifex part. This can be useful to check for # pushing-to-Transifex part. This can be useful to check for
# new strings or when testing the tools themselves. # new strings or when testing the tools themselves.
#
### END USAGE
### INITIAL SETUP ### INITIAL SETUP
# #
@ -28,21 +48,21 @@ test -f ".tx/config" || { echo "! Not at Calamares top-level" ; exit 1 ; }
test -f "calamares.desktop" || { echo "! Not at Calamares top-level" ; exit 1 ; } test -f "calamares.desktop" || { echo "! Not at Calamares top-level" ; exit 1 ; }
if test "x$1" = "x--no-tx" ; then if test "x$1" = "x--no-tx" ; then
# tx is the transifex command -- eat its arguments and do nothing # tx is the transifex command -- eat its arguments and do nothing
tx() { tx() {
echo "Skipped tx $*" echo "Skipped tx $*"
} }
# txtag is used to tag in git to measure changes -- skip it too # txtag is used to tag in git to measure changes -- skip it too
txtag() { txtag() {
echo "Skipped tx tagging." echo "Skipped tx tagging."
} }
else else
# tx is the regular transifex command # tx is the regular transifex command
# txtag is used to tag in git to measure changes # txtag is used to tag in git to measure changes
txtag() { txtag() {
git tag -f translation git tag -f translation
git push --force origin translation git push --force origin translation
} }
fi fi
@ -52,18 +72,18 @@ fi
LUPDATE="" LUPDATE=""
for _lupdate in lupdate-qt5 lupdate for _lupdate in lupdate-qt5 lupdate
do do
export QT_SELECT=5 export QT_SELECT=5
$_lupdate -version > /dev/null 2>&1 || export QT_SELECT=qt5 $_lupdate -version > /dev/null 2>&1 || export QT_SELECT=qt5
$_lupdate -version > /dev/null 2>&1 && LUPDATE=$_lupdate $_lupdate -version > /dev/null 2>&1 && LUPDATE=$_lupdate
test -n "$LUPDATE" && break test -n "$LUPDATE" && break
done done
test -n "$LUPDATE" || { echo "! No working lupdate" ; lupdate -version ; exit 1 ; } test -n "$LUPDATE" || { echo "! No working lupdate" ; lupdate -version ; exit 1 ; }
XMLLINT="" XMLLINT=""
for _xmllint in xmllint for _xmllint in xmllint
do do
$_xmllint --version > /dev/null 2>&1 && XMLLINT=$_xmllint $_xmllint --version > /dev/null 2>&1 && XMLLINT=$_xmllint
test -n "$XMLLINT" && break test -n "$XMLLINT" && break
done done
# XMLLINT is optional # XMLLINT is optional
@ -82,8 +102,8 @@ $LUPDATE -no-obsolete $_srcdirs -ts lang/calamares_en.ts
# $LUPDATE -no-obsolete -extensions cxxtr src/libcalamares/locale -ts lang/tz_en.ts # $LUPDATE -no-obsolete -extensions cxxtr src/libcalamares/locale -ts lang/tz_en.ts
if test -n "$XMLLINT" ; then if test -n "$XMLLINT" ; then
TS_FILE="lang/calamares_en.ts" TS_FILE="lang/calamares_en.ts"
$XMLLINT --c14n11 "$TS_FILE" | { echo "<!DOCTYPE TS>" ; cat - ; } | $XMLLINT --format --encode utf-8 -o "$TS_FILE".new - && mv "$TS_FILE".new "$TS_FILE" $XMLLINT --c14n11 "$TS_FILE" | { echo "<!DOCTYPE TS>" ; cat - ; } | $XMLLINT --format --encode utf-8 -o "$TS_FILE".new - && mv "$TS_FILE".new "$TS_FILE"
fi fi
tx push --source --no-interactive -r calamares.calamares-master tx push --source --no-interactive -r calamares.calamares-master
@ -103,29 +123,29 @@ PYGETTEXT="xgettext --keyword=_n:1,2 -L python"
SHARED_PYTHON="" SHARED_PYTHON=""
for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do
FILES=$(find "$MODULE_DIR" -name "*.py" -a -type f) FILES=$(find "$MODULE_DIR" -name "*.py" -a -type f)
if test -n "$FILES" ; then if test -n "$FILES" ; then
MODULE_NAME=$(basename ${MODULE_DIR}) MODULE_NAME=$(basename ${MODULE_DIR})
if [ -d ${MODULE_DIR}/lang ]; then if [ -d ${MODULE_DIR}/lang ]; then
${PYGETTEXT} -p ${MODULE_DIR}/lang -d ${MODULE_NAME} -o ${MODULE_NAME}.pot ${MODULE_DIR}/*.py ${PYGETTEXT} -p ${MODULE_DIR}/lang -d ${MODULE_NAME} -o ${MODULE_NAME}.pot ${MODULE_DIR}/*.py
POTFILE="${MODULE_DIR}/lang/${MODULE_NAME}.pot" POTFILE="${MODULE_DIR}/lang/${MODULE_NAME}.pot"
if [ -f "$POTFILE" ]; then if [ -f "$POTFILE" ]; then
sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' "$POTFILE" sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' "$POTFILE"
tx set -r calamares.${MODULE_NAME} --source -l en "$POTFILE" tx set -r calamares.${MODULE_NAME} --source -l en "$POTFILE"
tx push --source --no-interactive -r calamares.${MODULE_NAME} tx push --source --no-interactive -r calamares.${MODULE_NAME}
fi fi
else else
SHARED_PYTHON="$SHARED_PYTHON $FILES" SHARED_PYTHON="$SHARED_PYTHON $FILES"
fi fi
fi fi
done done
if test -n "$SHARED_PYTHON" ; then if test -n "$SHARED_PYTHON" ; then
${PYGETTEXT} -p lang -d python -o python.pot $SHARED_PYTHON ${PYGETTEXT} -p lang -d python -o python.pot $SHARED_PYTHON
POTFILE="lang/python.pot" POTFILE="lang/python.pot"
sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' "$POTFILE" sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' "$POTFILE"
tx set -r calamares.python --source -l en "$POTFILE" tx set -r calamares.python --source -l en "$POTFILE"
tx push --source --no-interactive -r calamares.python tx push --source --no-interactive -r calamares.python
fi fi
txtag txtag

View File

@ -69,11 +69,11 @@ windowPlacement: center
strings: strings:
productName: "@{NAME}" productName: "@{NAME}"
shortProductName: Generic shortProductName: Generic
version: 2017.8 LTS version: 2020.2 LTS
shortVersion: 2017.8 shortVersion: 2020.2
versionedName: Generic GNU/Linux 2017.8 LTS "Soapy Sousaphone" versionedName: Fancy GNU/Linux 2020.2 LTS "Turgid Tuba"
shortVersionedName: Generic 2017.8 shortVersionedName: FancyGL 2020.2
bootloaderEntryName: Generic bootloaderEntryName: FancyGL
productUrl: https://calamares.io/ productUrl: https://calamares.io/
supportUrl: https://github.com/calamares/calamares/issues supportUrl: https://github.com/calamares/calamares/issues
knownIssuesUrl: https://calamares.io/about/ knownIssuesUrl: https://calamares.io/about/

View File

@ -42,12 +42,17 @@
#include <QScreen> #include <QScreen>
#include <QTimer> #include <QTimer>
/// @brief Convenience for "are the settings in debug mode"
static bool
isDebug()
{
return Calamares::Settings::instance() && Calamares::Settings::instance()->debugMode();
}
CalamaresApplication::CalamaresApplication( int& argc, char* argv[] ) CalamaresApplication::CalamaresApplication( int& argc, char* argv[] )
: QApplication( argc, argv ) : QApplication( argc, argv )
, m_mainwindow( nullptr ) , m_mainwindow( nullptr )
, m_moduleManager( nullptr ) , m_moduleManager( nullptr )
, m_debugMode( false )
{ {
// Setting the organization name makes the default cache // Setting the organization name makes the default cache
// directory -- where Calamares stores logs, for instance -- // directory -- where Calamares stores logs, for instance --
@ -59,8 +64,6 @@ CalamaresApplication::CalamaresApplication( int& argc, char* argv[] )
setApplicationName( QStringLiteral( CALAMARES_APPLICATION_NAME ) ); setApplicationName( QStringLiteral( CALAMARES_APPLICATION_NAME ) );
setApplicationVersion( QStringLiteral( CALAMARES_VERSION ) ); setApplicationVersion( QStringLiteral( CALAMARES_VERSION ) );
CalamaresUtils::installTranslator( QLocale::system(), QString(), this );
QFont f = font(); QFont f = font();
CalamaresUtils::setDefaultFontSize( f.pointSize() ); CalamaresUtils::setDefaultFontSize( f.pointSize() );
} }
@ -73,15 +76,20 @@ CalamaresApplication::init()
cDebug() << "Calamares version:" << CALAMARES_VERSION; cDebug() << "Calamares version:" << CALAMARES_VERSION;
cDebug() << " languages:" << QString( CALAMARES_TRANSLATION_LANGUAGES ).replace( ";", ", " ); cDebug() << " languages:" << QString( CALAMARES_TRANSLATION_LANGUAGES ).replace( ";", ", " );
setQuitOnLastWindowClosed( false ); if ( !Calamares::Settings::instance() )
{
cError() << "Must create Calamares::Settings before the application.";
::exit( 1 );
}
initQmlPath(); initQmlPath();
initSettings();
initBranding(); initBranding();
CalamaresUtils::installTranslator( QLocale::system(), QString(), this );
setQuitOnLastWindowClosed( false );
setWindowIcon( QIcon( Calamares::Branding::instance()->imagePath( Calamares::Branding::ProductIcon ) ) ); setWindowIcon( QIcon( Calamares::Branding::instance()->imagePath( Calamares::Branding::ProductIcon ) ) );
cDebug() << "STARTUP: initQmlPath, initSettings, initBranding done"; cDebug() << "STARTUP: initSettings, initQmlPath, initBranding done";
initModuleManager(); //also shows main window initModuleManager(); //also shows main window
@ -103,20 +111,6 @@ CalamaresApplication::instance()
} }
void
CalamaresApplication::setDebug( bool enabled )
{
m_debugMode = enabled;
}
bool
CalamaresApplication::isDebug()
{
return m_debugMode;
}
CalamaresWindow* CalamaresWindow*
CalamaresApplication::mainWindow() CalamaresApplication::mainWindow()
{ {
@ -152,35 +146,6 @@ qmlDirCandidates( bool assumeBuilddir )
} }
static QStringList
settingsFileCandidates( bool assumeBuilddir )
{
static const char settings[] = "settings.conf";
QStringList settingsPaths;
if ( CalamaresUtils::isAppDataDirOverridden() )
{
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
}
else
{
if ( assumeBuilddir )
{
settingsPaths << QDir::current().absoluteFilePath( settings );
}
if ( CalamaresUtils::haveExtraDirs() )
for ( auto s : CalamaresUtils::extraConfigDirs() )
{
settingsPaths << ( s + settings );
}
settingsPaths << CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/settings.conf"; // String concat
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
}
return settingsPaths;
}
static QStringList static QStringList
brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename ) brandingFileCandidates( bool assumeBuilddir, const QString& brandingFilename )
{ {
@ -246,49 +211,6 @@ CalamaresApplication::initQmlPath()
} }
void
CalamaresApplication::initSettings()
{
QStringList settingsFileCandidatesByPriority = settingsFileCandidates( isDebug() );
QFileInfo settingsFile;
bool found = false;
foreach ( const QString& path, settingsFileCandidatesByPriority )
{
QFileInfo pathFi( path );
if ( pathFi.exists() && pathFi.isReadable() )
{
settingsFile = pathFi;
found = true;
break;
}
}
if ( !found || !settingsFile.exists() || !settingsFile.isReadable() )
{
cError() << "Cowardly refusing to continue startup without settings."
<< Logger::DebugList( settingsFileCandidatesByPriority );
if ( CalamaresUtils::isAppDataDirOverridden() )
{
cError() << "FATAL: explicitly configured application data directory is missing settings.conf";
}
else
{
cError() << "FATAL: none of the expected configuration file paths exist.";
}
::exit( EXIT_FAILURE );
}
auto* settings = new Calamares::Settings( settingsFile.absoluteFilePath(), isDebug(), this ); // Creates singleton
if ( settings->modulesSequence().count() < 1 )
{
cError() << "FATAL: no sequence set.";
::exit( EXIT_FAILURE );
}
}
void void
CalamaresApplication::initBranding() CalamaresApplication::initBranding()
{ {

View File

@ -49,16 +49,6 @@ public:
void init(); void init();
static CalamaresApplication* instance(); static CalamaresApplication* instance();
/**
* @brief setDebug controls whether debug mode is enabled
*/
void setDebug( bool enabled );
/**
* @brief isDebug returns true if running in debug mode, otherwise false.
*/
bool isDebug();
/** /**
* @brief mainWindow returns the Calamares application main window. * @brief mainWindow returns the Calamares application main window.
*/ */
@ -70,16 +60,14 @@ private slots:
void initFailed( const QStringList& l ); void initFailed( const QStringList& l );
private: private:
// Initialization steps happen in this order
void initQmlPath(); void initQmlPath();
void initSettings();
void initBranding(); void initBranding();
void initModuleManager(); void initModuleManager();
void initJobQueue(); void initJobQueue();
CalamaresWindow* m_mainwindow; CalamaresWindow* m_mainwindow;
Calamares::ModuleManager* m_moduleManager; Calamares::ModuleManager* m_moduleManager;
bool m_debugMode;
}; };
#endif // CALAMARESAPPLICATION_H #endif // CALAMARESAPPLICATION_H

View File

@ -20,9 +20,10 @@
#include "CalamaresApplication.h" #include "CalamaresApplication.h"
#include "CalamaresConfig.h" #include "Settings.h"
#include "utils/Dirs.h" #include "utils/Dirs.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Retranslator.h"
#include "3rdparty/kdsingleapplicationguard/kdsingleapplicationguard.h" #include "3rdparty/kdsingleapplicationguard/kdsingleapplicationguard.h"
@ -35,6 +36,21 @@
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
static unsigned int
debug_level( QCommandLineParser& parser, QCommandLineOption& levelOption )
{
bool ok = true;
int l = parser.value( levelOption ).toInt( &ok );
if ( !ok || ( l < 0 ) )
{
return Logger::LOGVERBOSE;
}
else
{
return static_cast< unsigned int >( l ); // l >= 0
}
}
static void static void
handle_args( CalamaresApplication& a ) handle_args( CalamaresApplication& a )
{ {
@ -42,6 +58,9 @@ handle_args( CalamaresApplication& a )
"Also look in current directory for configuration. Implies -D8." ); "Also look in current directory for configuration. Implies -D8." );
QCommandLineOption debugLevelOption( QCommandLineOption debugLevelOption(
QStringLiteral( "D" ), "Verbose output for debugging purposes (0-8).", "level" ); QStringLiteral( "D" ), "Verbose output for debugging purposes (0-8).", "level" );
QCommandLineOption debugTxOption( QStringList { "T", "debug-translation" },
"Also look in the current directory for translation." );
QCommandLineOption configOption( QCommandLineOption configOption(
QStringList { "c", "config" }, "Configuration directory to use, for testing purposes.", "config" ); QStringList { "c", "config" }, "Configuration directory to use, for testing purposes.", "config" );
QCommandLineOption xdgOption( QStringList { "X", "xdg-config" }, "Use XDG_{CONFIG,DATA}_DIRS as well." ); QCommandLineOption xdgOption( QStringList { "X", "xdg-config" }, "Use XDG_{CONFIG,DATA}_DIRS as well." );
@ -55,29 +74,11 @@ handle_args( CalamaresApplication& a )
parser.addOption( debugLevelOption ); parser.addOption( debugLevelOption );
parser.addOption( configOption ); parser.addOption( configOption );
parser.addOption( xdgOption ); parser.addOption( xdgOption );
parser.addOption( debugTxOption );
parser.process( a ); parser.process( a );
a.setDebug( parser.isSet( debugOption ) ); Logger::setupLogLevel( parser.isSet( debugOption ) ? Logger::LOGVERBOSE : debug_level( parser, debugLevelOption ) );
if ( parser.isSet( debugOption ) )
{
Logger::setupLogLevel( Logger::LOGVERBOSE );
}
else if ( parser.isSet( debugLevelOption ) )
{
bool ok = true;
int l = parser.value( debugLevelOption ).toInt( &ok );
unsigned int dlevel = 0;
if ( !ok || ( l < 0 ) )
{
dlevel = Logger::LOGVERBOSE;
}
else
{
dlevel = static_cast< unsigned int >( l ); // l >= 0
}
Logger::setupLogLevel( dlevel );
}
if ( parser.isSet( configOption ) ) if ( parser.isSet( configOption ) )
{ {
CalamaresUtils::setAppDataDir( QDir( parser.value( configOption ) ) ); CalamaresUtils::setAppDataDir( QDir( parser.value( configOption ) ) );
@ -86,6 +87,9 @@ handle_args( CalamaresApplication& a )
{ {
CalamaresUtils::setXdgDirs(); CalamaresUtils::setXdgDirs();
} }
CalamaresUtils::setAllowLocalTranslation( parser.isSet( debugOption ) || parser.isSet( debugTxOption ) );
Calamares::Settings::init( parser.isSet( debugOption ) );
a.init();
} }
int int
@ -113,14 +117,11 @@ main( int argc, char* argv[] )
// TODO: umount anything in /tmp/calamares-... as an emergency save function // TODO: umount anything in /tmp/calamares-... as an emergency save function
#endif #endif
handle_args( a );
KDSingleApplicationGuard guard( KDSingleApplicationGuard::AutoKillOtherInstances ); KDSingleApplicationGuard guard( KDSingleApplicationGuard::AutoKillOtherInstances );
int returnCode = 0;
if ( guard.isPrimaryInstance() ) if ( guard.isPrimaryInstance() )
{ {
a.init(); handle_args( a );
returnCode = a.exec(); return a.exec();
} }
else else
{ {
@ -135,7 +136,6 @@ main( int argc, char* argv[] )
{ {
qDebug() << " " << i.isValid() << i.pid() << i.arguments(); qDebug() << " " << i.isValid() << i.pid() << i.arguments();
} }
return 69; // EX_UNAVAILABLE on FreeBSD
} }
return returnCode;
} }

View File

@ -225,7 +225,7 @@ main( int argc, char* argv[] )
return 1; return 1;
} }
std::unique_ptr< Calamares::Settings > settings_p( new Calamares::Settings( QString(), true ) ); std::unique_ptr< Calamares::Settings > settings_p( Calamares::Settings::init( QString() ) );
std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) ); std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) );
QMainWindow* mw = nullptr; QMainWindow* mw = nullptr;

View File

@ -171,6 +171,18 @@ if ( ECM_FOUND AND BUILD_TESTING )
) )
calamares_automoc( libcalamarestest ) calamares_automoc( libcalamarestest )
ecm_add_test(
utils/TestPaths.cpp
TEST_NAME
libcalamarestestpaths
LINK_LIBRARIES
calamares
Qt5::Core
Qt5::Test
)
calamares_automoc( libcalamarestestpaths )
ecm_add_test( ecm_add_test(
geoip/GeoIPTests.cpp geoip/GeoIPTests.cpp
${geoip_src} ${geoip_src}

View File

@ -27,17 +27,6 @@
#include <QFile> #include <QFile>
#include <QJsonDocument> #include <QJsonDocument>
#ifdef WITH_PYTHON
#include "PythonHelper.h"
#undef slots
#include <boost/python/list.hpp>
#include <boost/python/str.hpp>
namespace bp = boost::python;
#endif
using CalamaresUtils::operator""_MiB; using CalamaresUtils::operator""_MiB;
namespace Calamares namespace Calamares
@ -167,75 +156,3 @@ GlobalStorage::loadYaml( const QString& filename )
} // namespace Calamares } // namespace Calamares
#ifdef WITH_PYTHON
namespace CalamaresPython
{
Calamares::GlobalStorage* GlobalStoragePythonWrapper::s_gs_instance = nullptr;
// The special handling for nullptr is only for the testing
// script for the python bindings, which passes in None;
// normal use will have a GlobalStorage from JobQueue::instance()
// passed in. Testing use will leak the allocated GlobalStorage
// object, but that's OK for testing.
GlobalStoragePythonWrapper::GlobalStoragePythonWrapper( Calamares::GlobalStorage* gs )
: m_gs( gs ? gs : s_gs_instance )
{
if ( !m_gs )
{
s_gs_instance = new Calamares::GlobalStorage;
m_gs = s_gs_instance;
}
}
bool
GlobalStoragePythonWrapper::contains( const std::string& key ) const
{
return m_gs->contains( QString::fromStdString( key ) );
}
int
GlobalStoragePythonWrapper::count() const
{
return m_gs->count();
}
void
GlobalStoragePythonWrapper::insert( const std::string& key, const bp::object& value )
{
m_gs->insert( QString::fromStdString( key ), CalamaresPython::variantFromPyObject( value ) );
}
bp::list
GlobalStoragePythonWrapper::keys() const
{
bp::list pyList;
const auto keys = m_gs->keys();
for ( const QString& key : keys )
{
pyList.append( key.toStdString() );
}
return pyList;
}
int
GlobalStoragePythonWrapper::remove( const std::string& key )
{
return m_gs->remove( QString::fromStdString( key ) );
}
bp::object
GlobalStoragePythonWrapper::value( const std::string& key ) const
{
return CalamaresPython::variantToPyObject( m_gs->value( QString::fromStdString( key ) ) );
}
} // namespace CalamaresPython
#endif // WITH_PYTHON

View File

@ -26,20 +26,6 @@
#include <QString> #include <QString>
#include <QVariantMap> #include <QVariantMap>
#ifdef WITH_PYTHON
namespace boost
{
namespace python
{
namespace api
{
class object;
}
class list;
} // namespace python
} // namespace boost
#endif
namespace Calamares namespace Calamares
{ {
@ -106,33 +92,4 @@ private:
} // namespace Calamares } // namespace Calamares
#ifdef WITH_PYTHON
namespace CalamaresPython
{
class GlobalStoragePythonWrapper
{
public:
explicit GlobalStoragePythonWrapper( Calamares::GlobalStorage* gs );
bool contains( const std::string& key ) const;
int count() const;
void insert( const std::string& key, const boost::python::api::object& value );
boost::python::list keys() const;
int remove( const std::string& key );
boost::python::api::object value( const std::string& key ) const;
// This is a helper for scripts that do not go through
// the JobQueue (i.e. the module testpython script),
// which allocate their own (singleton) GlobalStorage.
static Calamares::GlobalStorage* globalStorageInstance() { return s_gs_instance; }
private:
Calamares::GlobalStorage* m_gs;
static Calamares::GlobalStorage* s_gs_instance; // See globalStorageInstance()
};
} // namespace CalamaresPython
#endif
#endif // CALAMARES_GLOBALSTORAGE_H #endif // CALAMARES_GLOBALSTORAGE_H

View File

@ -19,15 +19,11 @@
#include "JobQueue.h" #include "JobQueue.h"
#include "CalamaresConfig.h"
#include "GlobalStorage.h" #include "GlobalStorage.h"
#include "Job.h" #include "Job.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "CalamaresConfig.h"
#ifdef WITH_PYTHON
#include "PythonHelper.h"
#endif
#include <QThread> #include <QThread>
namespace Calamares namespace Calamares

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014, Teo Mrnjavac <teo@kde.org> * Copyright 2014, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org> * Copyright 2017-2018, 2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,20 +19,13 @@
#include "PythonHelper.h" #include "PythonHelper.h"
#include "GlobalStorage.h"
#include "utils/Dirs.h" #include "utils/Dirs.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#undef slots
#include "utils/boost-warnings.h"
#include <boost/python.hpp>
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace bp = boost::python; namespace bp = boost::python;
namespace CalamaresPython namespace CalamaresPython
@ -398,5 +391,67 @@ Helper::handleLastError()
return QString( "<div>%1</div>" ).arg( msgList.join( "</div><div>" ) ); return QString( "<div>%1</div>" ).arg( msgList.join( "</div><div>" ) );
} }
Calamares::GlobalStorage* GlobalStoragePythonWrapper::s_gs_instance = nullptr;
// The special handling for nullptr is only for the testing
// script for the python bindings, which passes in None;
// normal use will have a GlobalStorage from JobQueue::instance()
// passed in. Testing use will leak the allocated GlobalStorage
// object, but that's OK for testing.
GlobalStoragePythonWrapper::GlobalStoragePythonWrapper( Calamares::GlobalStorage* gs )
: m_gs( gs ? gs : s_gs_instance )
{
if ( !m_gs )
{
s_gs_instance = new Calamares::GlobalStorage;
m_gs = s_gs_instance;
}
}
bool
GlobalStoragePythonWrapper::contains( const std::string& key ) const
{
return m_gs->contains( QString::fromStdString( key ) );
}
int
GlobalStoragePythonWrapper::count() const
{
return m_gs->count();
}
void
GlobalStoragePythonWrapper::insert( const std::string& key, const bp::object& value )
{
m_gs->insert( QString::fromStdString( key ), CalamaresPython::variantFromPyObject( value ) );
}
bp::list
GlobalStoragePythonWrapper::keys() const
{
bp::list pyList;
const auto keys = m_gs->keys();
for ( const QString& key : keys )
{
pyList.append( key.toStdString() );
}
return pyList;
}
int
GlobalStoragePythonWrapper::remove( const std::string& key )
{
return m_gs->remove( QString::fromStdString( key ) );
}
bp::object
GlobalStoragePythonWrapper::value( const std::string& key ) const
{
return CalamaresPython::variantToPyObject( m_gs->value( QString::fromStdString( key ) ) );
}
} // namespace CalamaresPython } // namespace CalamaresPython

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014, Teo Mrnjavac <teo@kde.org> * Copyright 2014, Teo Mrnjavac <teo@kde.org>
* Copyright 2018, Adriaan de Groot <groot@kde.org> * Copyright 2018, 2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -21,19 +21,14 @@
#define CALAMARES_PYTHONJOBHELPER_H #define CALAMARES_PYTHONJOBHELPER_H
#include "PythonJob.h" #include "PythonJob.h"
#include "utils/BoostPython.h"
#include <QStringList> #include <QStringList>
#undef slots namespace Calamares
#include "utils/boost-warnings.h" {
class GlobalStorage;
#include <boost/python/dict.hpp> }
#include <boost/python/list.hpp>
#include <boost/python/object.hpp>
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace CalamaresPython namespace CalamaresPython
{ {
@ -72,6 +67,28 @@ private:
QStringList m_pythonPaths; QStringList m_pythonPaths;
}; };
class GlobalStoragePythonWrapper
{
public:
explicit GlobalStoragePythonWrapper( Calamares::GlobalStorage* gs );
bool contains( const std::string& key ) const;
int count() const;
void insert( const std::string& key, const boost::python::api::object& value );
boost::python::list keys() const;
int remove( const std::string& key );
boost::python::api::object value( const std::string& key ) const;
// This is a helper for scripts that do not go through
// the JobQueue (i.e. the module testpython script),
// which allocate their own (singleton) GlobalStorage.
static Calamares::GlobalStorage* globalStorageInstance() { return s_gs_instance; }
private:
Calamares::GlobalStorage* m_gs;
static Calamares::GlobalStorage* s_gs_instance; // See globalStorageInstance()
};
} // namespace CalamaresPython } // namespace CalamaresPython
#endif // CALAMARES_PYTHONJOBHELPER_H #endif // CALAMARES_PYTHONJOBHELPER_H

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014-2016, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2016, Teo Mrnjavac <teo@kde.org>
* Copyright 2018, Adriaan de Groot <groot@kde.org> * Copyright 2018, 2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,20 +19,16 @@
#include "PythonJob.h" #include "PythonJob.h"
#include "CalamaresVersion.h"
#include "GlobalStorage.h" #include "GlobalStorage.h"
#include "JobQueue.h" #include "JobQueue.h"
#include "PythonHelper.h" #include "PythonHelper.h"
#include "PythonJobApi.h"
#include "utils/BoostPython.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include <QDir> #include <QDir>
#undef slots
#include <boost/python.hpp>
#include <boost/python/args.hpp>
#include "PythonJobApi.h"
namespace bp = boost::python; namespace bp = boost::python;
BOOST_PYTHON_FUNCTION_OVERLOADS( mount_overloads, CalamaresPython::mount, 2, 4 ); BOOST_PYTHON_FUNCTION_OVERLOADS( mount_overloads, CalamaresPython::mount, 2, 4 );
@ -180,7 +176,7 @@ PythonJob::PythonJob( const ModuleSystem::InstanceKey& instance,
, m_workingPath( workingPath ) , m_workingPath( workingPath )
, m_description() , m_description()
, m_configurationMap( moduleConfiguration ) , m_configurationMap( moduleConfiguration )
, m_weight( (instance.module() == QStringLiteral( "unpackfs" )) ? 12.0 : 1.0 ) , m_weight( ( instance.module() == QStringLiteral( "unpackfs" ) ) ? 12.0 : 1.0 )
{ {
} }

View File

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014, Teo Mrnjavac <teo@kde.org> * Copyright 2014, Teo Mrnjavac <teo@kde.org>
* Copyright 2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -23,7 +24,7 @@
#include "modulesystem/InstanceKey.h" #include "modulesystem/InstanceKey.h"
#include <QVariant> #include <QVariantMap>
namespace CalamaresPython namespace CalamaresPython
{ {

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014-2016, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2016, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2019, Adriaan de Groot <groot@kde.org> * Copyright 2017-2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,26 +19,17 @@
#include "PythonJobApi.h" #include "PythonJobApi.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "PythonHelper.h" #include "PythonHelper.h"
#include "utils/CalamaresUtilsSystem.h" #include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/String.h" #include "utils/String.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include <QCoreApplication> #include <QCoreApplication>
#include <QDir> #include <QDir>
#include <QStandardPaths> #include <QStandardPaths>
#undef slots
#include "utils/boost-warnings.h"
#include <boost/python.hpp>
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace bp = boost::python; namespace bp = boost::python;
static int static int

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014-2016, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2016, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org> * Copyright 2017-2018, 2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,12 +20,14 @@
#ifndef PYTHONJOBAPI_H #ifndef PYTHONJOBAPI_H
#define PYTHONJOBAPI_H #define PYTHONJOBAPI_H
#include "CalamaresVersion.h" #include "qglobal.h" // For qreal
#include "PythonJob.h" #include "utils/BoostPython.h"
#undef slots namespace Calamares
#include <boost/python/dict.hpp> {
class PythonJob;
}
namespace CalamaresPython namespace CalamaresPython
{ {

View File

@ -21,6 +21,7 @@
#include "Settings.h" #include "Settings.h"
#include "CalamaresConfig.h"
#include "utils/Dirs.h" #include "utils/Dirs.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Yaml.h" #include "utils/Yaml.h"
@ -193,8 +194,8 @@ interpretSequence( const YAML::Node& node, Settings::ModuleSequence& moduleSeque
} }
} }
Settings::Settings( const QString& settingsFilePath, bool debugMode, QObject* parent ) Settings::Settings( const QString& settingsFilePath, bool debugMode )
: QObject( parent ) : QObject()
, m_debug( debugMode ) , m_debug( debugMode )
, m_doChroot( true ) , m_doChroot( true )
, m_promptInstall( false ) , m_promptInstall( false )
@ -265,37 +266,93 @@ Settings::brandingComponentName() const
return m_brandingComponentName; return m_brandingComponentName;
} }
static QStringList
bool settingsFileCandidates( bool assumeBuilddir )
Settings::showPromptBeforeExecution() const
{ {
return m_promptInstall; static const char settings[] = "settings.conf";
QStringList settingsPaths;
if ( CalamaresUtils::isAppDataDirOverridden() )
{
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
}
else
{
if ( assumeBuilddir )
{
settingsPaths << QDir::current().absoluteFilePath( settings );
}
if ( CalamaresUtils::haveExtraDirs() )
for ( auto s : CalamaresUtils::extraConfigDirs() )
{
settingsPaths << ( s + settings );
}
settingsPaths << CMAKE_INSTALL_FULL_SYSCONFDIR "/calamares/settings.conf"; // String concat
settingsPaths << CalamaresUtils::appDataDir().absoluteFilePath( settings );
}
return settingsPaths;
} }
Settings*
bool Settings::init( bool debugMode )
Settings::debugMode() const
{ {
return m_debug; if ( s_instance )
{
cWarning() << "Calamares::Settings already created";
return s_instance;
}
QStringList settingsFileCandidatesByPriority = settingsFileCandidates( debugMode );
QFileInfo settingsFile;
bool found = false;
foreach ( const QString& path, settingsFileCandidatesByPriority )
{
QFileInfo pathFi( path );
if ( pathFi.exists() && pathFi.isReadable() )
{
settingsFile = pathFi;
found = true;
break;
}
}
if ( !found || !settingsFile.exists() || !settingsFile.isReadable() )
{
cError() << "Cowardly refusing to continue startup without settings."
<< Logger::DebugList( settingsFileCandidatesByPriority );
if ( CalamaresUtils::isAppDataDirOverridden() )
{
cError() << "FATAL: explicitly configured application data directory is missing settings.conf";
}
else
{
cError() << "FATAL: none of the expected configuration file paths exist.";
}
::exit( EXIT_FAILURE );
}
auto* settings = new Calamares::Settings( settingsFile.absoluteFilePath(), debugMode ); // Creates singleton
if ( settings->modulesSequence().count() < 1 )
{
cError() << "FATAL: no sequence set.";
::exit( EXIT_FAILURE );
}
return settings;
} }
bool Settings*
Settings::doChroot() const Settings::init( const QString& path )
{ {
return m_doChroot; if ( s_instance )
{
cWarning() << "Calamares::Settings already created";
return s_instance;
}
return new Calamares::Settings( path, true );
} }
bool
Settings::disableCancel() const
{
return m_disableCancel;
}
bool
Settings::disableCancelDuringExec() const
{
return m_disableCancelDuringExec;
}
} // namespace Calamares } // namespace Calamares

View File

@ -35,11 +35,14 @@ namespace Calamares
class DLLEXPORT Settings : public QObject class DLLEXPORT Settings : public QObject
{ {
Q_OBJECT Q_OBJECT
explicit Settings( const QString& settingsFilePath, bool debugMode );
public: public:
explicit Settings( const QString& settingsFilePath, bool debugMode, QObject* parent = nullptr );
static Settings* instance(); static Settings* instance();
/// @brief Find a settings.conf, following @p debugMode
static Settings* init( bool debugMode );
/// @brief Explicif filename, debug is always true (for testing)
static Settings* init( const QString& filename );
QStringList modulesSearchPaths() const; QStringList modulesSearchPaths() const;
using InstanceDescription = QMap< QString, QString >; using InstanceDescription = QMap< QString, QString >;
@ -51,11 +54,31 @@ public:
QString brandingComponentName() const; QString brandingComponentName() const;
bool showPromptBeforeExecution() const; /** @brief Is this a debugging run?
*
* Returns true if Calamares is in debug mode. In debug mode,
* modules and settings are loaded from more locations, to help
* development and debugging.
*/
bool debugMode() const { return m_debug; }
bool debugMode() const; /** @brief Distinguish "install" from "OEM" modes.
*
* Returns true in "install" mode, which is where actions happen
* in a chroot -- the target system, which exists separately from
* the source system. In "OEM" mode, returns false and most actions
* apply to the *current* (host) system.
*/
bool doChroot() const { return m_doChroot; }
bool doChroot() const; /** @brief Global setting of prompt-before-install.
*
* Returns true when the configuration is such that the user
* should be prompted one-last-time before any action is taken
* that really affects the machine.
*/
bool showPromptBeforeExecution() const { return m_promptInstall; }
/** @brief Distinguish between "install" and "setup" modes. /** @brief Distinguish between "install" and "setup" modes.
* *
* This influences user-visible strings, for instance using the * This influences user-visible strings, for instance using the
@ -64,9 +87,9 @@ public:
bool isSetupMode() const { return m_isSetupMode; } bool isSetupMode() const { return m_isSetupMode; }
/** @brief Global setting of disable-cancel: can't cancel ever. */ /** @brief Global setting of disable-cancel: can't cancel ever. */
bool disableCancel() const; bool disableCancel() const { return m_disableCancel; }
/** @brief Temporary setting of disable-cancel: can't cancel during exec. */ /** @brief Temporary setting of disable-cancel: can't cancel during exec. */
bool disableCancelDuringExec() const; bool disableCancelDuringExec() const { return m_disableCancelDuringExec; }
private: private:
static Settings* s_instance; static Settings* s_instance;

View File

@ -24,23 +24,16 @@ namespace CalamaresUtils
namespace Locale namespace Locale
{ {
Label::Label() Label::Label( QObject* parent )
: m_locale( QLocale() ) : Label( QString(), LabelFormat::IfNeededWithCountry, parent )
{ {
m_localeId = m_locale.name();
setLabels( QString(), LabelFormat::IfNeededWithCountry );
} }
Label::Label( const QString& locale, LabelFormat format ) Label::Label( const QString& locale, LabelFormat format, QObject* parent )
: m_locale( Label::getLocale( locale ) ) : QObject( parent )
, m_localeId( locale ) , m_locale( Label::getLocale( locale ) )
{ , m_localeId( locale.isEmpty() ? m_locale.name() : locale )
setLabels( locale, format );
}
void
Label::setLabels( const QString& locale, LabelFormat format )
{ {
//: language[name] (country[name]) //: language[name] (country[name])
QString longFormat = QObject::tr( "%1 (%2)" ); QString longFormat = QObject::tr( "%1 (%2)" );
@ -69,6 +62,10 @@ Label::setLabels( const QString& locale, LabelFormat format )
QLocale QLocale
Label::getLocale( const QString& localeName ) Label::getLocale( const QString& localeName )
{ {
if ( localeName.isEmpty() )
{
return QLocale();
}
if ( localeName.contains( "@latin" ) ) if ( localeName.contains( "@latin" ) )
{ {
QLocale loc( localeName ); // Ignores @latin QLocale loc( localeName ); // Ignores @latin

View File

@ -21,6 +21,7 @@
#define LOCALE_LABEL_H #define LOCALE_LABEL_H
#include <QLocale> #include <QLocale>
#include <QObject>
#include <QString> #include <QString>
namespace CalamaresUtils namespace CalamaresUtils
@ -35,8 +36,14 @@ namespace Locale
* translation system) into QLocales, and also into consistent * translation system) into QLocales, and also into consistent
* human-readable text labels. * human-readable text labels.
*/ */
class Label class Label : public QObject
{ {
Q_OBJECT
Q_PROPERTY( QString label READ label CONSTANT FINAL )
Q_PROPERTY( QString englishLabel READ englishLabel CONSTANT FINAL )
Q_PROPERTY( QString localeId MEMBER m_localeId CONSTANT FINAL )
public: public:
/** @brief Formatting option for label -- add (country) to label. */ /** @brief Formatting option for label -- add (country) to label. */
enum class LabelFormat enum class LabelFormat
@ -46,7 +53,7 @@ public:
}; };
/** @brief Empty locale. This uses the system-default locale. */ /** @brief Empty locale. This uses the system-default locale. */
Label(); Label( QObject* parent = nullptr );
/** @brief Construct from a locale name. /** @brief Construct from a locale name.
* *
@ -54,7 +61,9 @@ public:
* The @p format determines whether the country name is always present * The @p format determines whether the country name is always present
* in the label (human-readable form) or only if needed for disambiguation. * in the label (human-readable form) or only if needed for disambiguation.
*/ */
Label( const QString& localeName, LabelFormat format = LabelFormat::IfNeededWithCountry ); Label( const QString& localeName,
LabelFormat format = LabelFormat::IfNeededWithCountry,
QObject* parent = nullptr );
/** @brief Define a sorting order. /** @brief Define a sorting order.
* *
@ -94,8 +103,6 @@ public:
static QLocale getLocale( const QString& localeName ); static QLocale getLocale( const QString& localeName );
protected: protected:
void setLabels( const QString& name, LabelFormat format );
QLocale m_locale; QLocale m_locale;
QString m_localeId; // the locale identifier, e.g. "en_GB" QString m_localeId; // the locale identifier, e.g. "en_GB"
QString m_label; // the native name of the locale QString m_label; // the native name of the locale

View File

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2019, Adriaan de Groot <groot@kde.org> * Copyright 2019-2020 Adriaan de Groot <groot@kde.org>
* Copyright 2019, Camilo Higuita <milo.h@aol.com>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -36,7 +37,7 @@ LabelModel::LabelModel( const QStringList& locales, QObject* parent )
for ( const auto& l : locales ) for ( const auto& l : locales )
{ {
m_locales.push_back( Label( l ) ); m_locales.push_back( new Label( l, Label::LabelFormat::IfNeededWithCountry, this ) );
} }
} }
@ -65,27 +66,33 @@ LabelModel::data( const QModelIndex& index, int role ) const
switch ( role ) switch ( role )
{ {
case LabelRole: case LabelRole:
return locale.label(); return locale->label();
case EnglishLabelRole: case EnglishLabelRole:
return locale.englishLabel(); return locale->englishLabel();
default: default:
return QVariant(); return QVariant();
} }
} }
QHash< int, QByteArray >
LabelModel::roleNames() const
{
return { { LabelRole, "label" }, { EnglishLabelRole, "englishLabel" } };
}
const Label& const Label&
LabelModel::locale( int row ) const LabelModel::locale( int row ) const
{ {
if ( ( row < 0 ) || ( row >= m_locales.count() ) ) if ( ( row < 0 ) || ( row >= m_locales.count() ) )
{ {
for ( const auto& l : m_locales ) for ( const auto& l : m_locales )
if ( l.isEnglish() ) if ( l->isEnglish() )
{ {
return l; return *l;
} }
return m_locales[ 0 ]; return *m_locales[ 0 ];
} }
return m_locales[ row ]; return *m_locales[ row ];
} }
int int
@ -93,7 +100,7 @@ LabelModel::find( std::function< bool( const Label& ) > predicate ) const
{ {
for ( int row = 0; row < m_locales.count(); ++row ) for ( int row = 0; row < m_locales.count(); ++row )
{ {
if ( predicate( m_locales[ row ] ) ) if ( predicate( *m_locales[ row ] ) )
{ {
return row; return row;
} }

View File

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2019, Adriaan de Groot <groot@kde.org> * Copyright 2019-2020, Adriaan de Groot <groot@kde.org>
* Copyright 2019, Camilo Higuita <milo.h@aol.com>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -33,6 +34,8 @@ namespace Locale
class DLLEXPORT LabelModel : public QAbstractListModel class DLLEXPORT LabelModel : public QAbstractListModel
{ {
Q_OBJECT
public: public:
enum enum
{ {
@ -46,6 +49,7 @@ public:
int rowCount( const QModelIndex& parent ) const override; int rowCount( const QModelIndex& parent ) const override;
QVariant data( const QModelIndex& index, int role ) const override; QVariant data( const QModelIndex& index, int role ) const override;
QHash< int, QByteArray > roleNames() const override;
/** @brief Gets locale information for entry #n /** @brief Gets locale information for entry #n
* *
@ -69,7 +73,7 @@ public:
int find( const QString& countryCode ) const; int find( const QString& countryCode ) const;
private: private:
QVector< Label > m_locales; QVector< Label* > m_locales;
QStringList m_localeIds; QStringList m_localeIds;
}; };

View File

@ -19,6 +19,7 @@
#include "Tests.h" #include "Tests.h"
#include "Manager.h" #include "Manager.h"
#include "utils/Logger.h"
#include <QtTest/QtTest> #include <QtTest/QtTest>
@ -43,6 +44,9 @@ NetworkTests::testInstance()
void void
NetworkTests::testPing() NetworkTests::testPing()
{ {
auto& nam = CalamaresUtils::Network::Manager::instance(); using namespace CalamaresUtils::Network;
QVERIFY( nam.synchronousPing( QUrl( "https://www.kde.org" ) ) ); Logger::setupLogLevel( Logger::LOGVERBOSE );
auto& nam = Manager::instance();
auto r = nam.synchronousPing( QUrl( "https://www.kde.org" ), RequestOptions( RequestOptions::FollowRedirect ) );
QVERIFY( r );
} }

View File

@ -0,0 +1,73 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019-2020, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/*
* The Python and Boost::Python headers are not C++14 warning-proof, especially
* with picky compilers like Clang 8 and 9. Since we use Clang for the
* find-all-the-warnings case, switch those warnings off for
* the we-can't-change-them system headers.
*
* This convenience header handles including all the bits we need for
* Python support, while silencing warnings.
*/
#ifndef UTILS_BOOSTPYTHON_H
#define UTILS_BOOSTPYTHON_H
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreserved-id-macro"
#pragma clang diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#pragma clang diagnostic ignored "-Wextra-semi-stmt"
#pragma clang diagnostic ignored "-Wall"
#pragma clang diagnostic ignored "-Wimplicit-float-conversion"
#pragma clang diagnostic ignored "-Wundef"
#pragma clang diagnostic ignored "-Wdeprecated-dynamic-exception-spec"
#pragma clang diagnostic ignored "-Wshadow-field-in-constructor"
#pragma clang diagnostic ignored "-Wshadow"
#pragma clang diagnostic ignored "-Wmissing-noreturn"
#pragma clang diagnostic ignored "-Wcast-qual"
#pragma clang diagnostic ignored "-Wcast-align"
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wdouble-promotion"
#pragma clang diagnostic ignored "-Wredundant-parens"
#pragma clang diagnostic ignored "-Wweak-vtables"
#pragma clang diagnostic ignored "-Wdeprecated"
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
#pragma clang diagnostic ignored "-Wdocumentation"
#pragma clang diagnostic ignored "-Wcomma"
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Wunused-template"
// Actually for Python headers
#pragma clang diagnostic ignored "-Wreserved-id-macro"
#endif
#undef slots
#include <boost/python.hpp>
#include <boost/python/args.hpp>
#include <boost/python/dict.hpp>
#include <boost/python/list.hpp>
#include <boost/python/object.hpp>
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014, Teo Mrnjavac <teo@kde.org> * Copyright 2014, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org> * Copyright 2017-2018, 2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -263,11 +263,16 @@ System::runCommand( System::RunLocation location,
return ProcessResult( r, output ); return ProcessResult( r, output );
} }
/// @brief Cheap check if a path is absolute.
static inline bool
isAbsolutePath( const QString& path )
{
return path.startsWith( '/' );
}
QString QString
System::targetPath( const QString& path ) const System::targetPath( const QString& path ) const
{ {
QString completePath;
if ( doChroot() ) if ( doChroot() )
{ {
Calamares::GlobalStorage* gs Calamares::GlobalStorage* gs
@ -275,18 +280,17 @@ System::targetPath( const QString& path ) const
if ( !gs || !gs->contains( "rootMountPoint" ) ) if ( !gs || !gs->contains( "rootMountPoint" ) )
{ {
cWarning() << "No rootMountPoint in global storage, cannot create target file" << path; cWarning() << "No rootMountPoint in global storage, cannot name target file" << path;
return QString(); return QString();
} }
completePath = gs->value( "rootMountPoint" ).toString() + '/' + path; QString root = gs->value( "rootMountPoint" ).toString();
return isAbsolutePath( path ) ? ( root + path ) : ( root + '/' + path );
} }
else else
{ {
completePath = QStringLiteral( "/" ) + path; return isAbsolutePath( path ) ? path : ( QStringLiteral( "/" ) + path );
} }
return completePath;
} }
QString QString
@ -327,6 +331,59 @@ System::createTargetFile( const QString& path, const QByteArray& contents ) cons
return QFileInfo( f ).canonicalFilePath(); return QFileInfo( f ).canonicalFilePath();
} }
void
System::removeTargetFile( const QString& path ) const
{
if ( !isAbsolutePath( path ) )
{
cWarning() << "Will not remove non-absolute path" << path;
return;
}
QString target = targetPath( path );
if ( !target.isEmpty() )
{
QFile::remove( target );
}
// If it was empty, a warning was already printed
}
bool
System::createTargetDirs( const QString& path ) const
{
if ( !isAbsolutePath( path ) )
{
cWarning() << "Will not create basedirs for non-absolute path" << path;
return false;
}
QString target = targetPath( path );
if ( target.isEmpty() )
{
// If it was empty, a warning was already printed
return false;
}
QString root = Calamares::JobQueue::instance()->globalStorage()->value( "rootMountPoint" ).toString();
if ( root.isEmpty() )
{
return false;
}
QDir d( root );
if ( !d.exists() )
{
cWarning() << "Root mountpoint" << root << "does not exist.";
return false;
}
return d.mkpath( target ); // This re-does everything starting from the **host** /
}
bool
System::createTargetParentDirs( const QString& filePath ) const
{
return createTargetDirs( QFileInfo( filePath ).dir().path() );
}
QPair< quint64, float > QPair< quint64, float >
System::getTotalMemoryB() const System::getTotalMemoryB() const

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014, Teo Mrnjavac <teo@kde.org> * Copyright 2014, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org> * Copyright 2017-2018, 2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -246,6 +246,33 @@ public:
*/ */
DLLEXPORT QString createTargetFile( const QString& path, const QByteArray& contents ) const; DLLEXPORT QString createTargetFile( const QString& path, const QByteArray& contents ) const;
/** @brief Remove a file from the target system.
*
* @param path Path to the file; this is interpreted from the root
* of the target system (@see targetPath()).
*
* Does no error checking to see if the target file was really removed.
*/
DLLEXPORT void removeTargetFile( const QString& path ) const;
/** @brief Ensure that the directory @p path exists
*
* @param path a full pathname to a desired directory.
*
* All the directory components including the last path component are
* created, as needed. Returns true on success.
*
* @see QDir::mkpath
*/
DLLEXPORT bool createTargetDirs( const QString& path ) const;
/** @brief Convenience to create parent directories of a file path.
*
* Creates all the parent directories until the last
* component of @p filePath . @see createTargetDirs()
*/
DLLEXPORT bool createTargetParentDirs( const QString& filePath ) const;
/** /**
* @brief getTotalMemoryB returns the total main memory, in bytes. * @brief getTotalMemoryB returns the total main memory, in bytes.
* *

View File

@ -35,7 +35,7 @@ CalamaresUtils::getEntropy( int size, QByteArray& b )
char* buffer = b.data(); char* buffer = b.data();
std::fill( buffer, buffer + size, 0xcb ); std::fill( buffer, buffer + size, 0xcb );
int readSize = 0; qint64 readSize = 0;
QFile urandom( "/dev/urandom" ); QFile urandom( "/dev/urandom" );
if ( urandom.exists() && urandom.open( QIODevice::ReadOnly ) ) if ( urandom.exists() && urandom.open( QIODevice::ReadOnly ) )
{ {
@ -62,7 +62,7 @@ CalamaresUtils::getEntropy( int size, QByteArray& b )
#define GET_ONE_BYTE \ #define GET_ONE_BYTE \
if ( readSize < size ) \ if ( readSize < size ) \
{ \ { \
buffer[ readSize++ ] = next & 0xff; \ buffer[ readSize++ ] = char( next & 0xffU ); \
next = next >> 8; \ next = next >> 8; \
} }
GET_ONE_BYTE GET_ONE_BYTE

View File

@ -27,6 +27,8 @@
#include <QEvent> #include <QEvent>
#include <QTranslator> #include <QTranslator>
static bool s_allowLocalTranslations = false;
/** @brief Helper class for loading translations /** @brief Helper class for loading translations
* *
* This is used by the loadSingletonTranslator() function to hand off * This is used by the loadSingletonTranslator() function to hand off
@ -131,7 +133,7 @@ static bool
tryLoad( QTranslator* translator, const QString& prefix, const QString& localeName ) tryLoad( QTranslator* translator, const QString& prefix, const QString& localeName )
{ {
// In debug-mode, try loading from the current directory // In debug-mode, try loading from the current directory
if ( Calamares::Settings::instance() && Calamares::Settings::instance()->debugMode() && translator->load( prefix + localeName ) ) if ( s_allowLocalTranslations && translator->load( prefix + localeName ) )
{ {
cDebug() << Logger::SubEntry << "Loaded local translation" << prefix << localeName; cDebug() << Logger::SubEntry << "Loaded local translation" << prefix << localeName;
return true; return true;
@ -139,14 +141,15 @@ tryLoad( QTranslator* translator, const QString& prefix, const QString& localeNa
// Or load from appDataDir -- often /usr/share/calamares -- subdirectory land/ // Or load from appDataDir -- often /usr/share/calamares -- subdirectory land/
QDir localeData( CalamaresUtils::appDataDir() ); QDir localeData( CalamaresUtils::appDataDir() );
if ( localeData.exists() && translator->load( localeData.absolutePath() + QStringLiteral("/lang/") + prefix + localeName) ) if ( localeData.exists()
&& translator->load( localeData.absolutePath() + QStringLiteral( "/lang/" ) + prefix + localeName ) )
{ {
cDebug() << Logger::SubEntry << "Loaded appdata translation" << prefix << localeName; cDebug() << Logger::SubEntry << "Loaded appdata translation" << prefix << localeName;
return true; return true;
} }
// Or from QRC (most common) // Or from QRC (most common)
if ( translator->load( QStringLiteral( ":/lang/") + prefix + localeName ) ) if ( translator->load( QStringLiteral( ":/lang/" ) + prefix + localeName ) )
{ {
cDebug() << Logger::SubEntry << "Loaded QRC translation" << prefix << localeName; cDebug() << Logger::SubEntry << "Loaded QRC translation" << prefix << localeName;
return true; return true;
@ -260,5 +263,11 @@ Retranslator::eventFilter( QObject* obj, QEvent* e )
return QObject::eventFilter( obj, e ); return QObject::eventFilter( obj, e );
} }
void
setAllowLocalTranslation( bool allow )
{
s_allowLocalTranslations = allow;
}
} // namespace CalamaresUtils } // namespace CalamaresUtils

View File

@ -42,6 +42,15 @@ DLLEXPORT void installTranslator( const QLocale& locale, const QString& branding
DLLEXPORT QString translatorLocaleName(); DLLEXPORT QString translatorLocaleName();
/** @brief Set @p allow to true to load translations from current dir.
*
* If false, (or never called) the translations are loaded only from
* system locations (the AppData dir) and from QRC (compiled in).
* Enable local translations to test translations stored in the
* current directory.
*/
DLLEXPORT void setAllowLocalTranslation( bool allow );
class Retranslator : public QObject class Retranslator : public QObject
{ {
Q_OBJECT Q_OBJECT

View File

@ -0,0 +1,165 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2018, 2020, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "CalamaresUtilsSystem.h"
#include "Entropy.h"
#include "Logger.h"
#include "UMask.h"
#include "Yaml.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include <QDir>
// #include <QTemporaryFile>
#include <QtTest/QtTest>
// #include <fcntl.h>
// #include <sys/stat.h>
// #include <unistd.h>
class TestPaths : public QObject
{
Q_OBJECT
public:
TestPaths() {}
virtual ~TestPaths() {}
private Q_SLOTS:
void initTestCase();
void init();
void cleanupTestCase();
void testTargetPath();
void testCreateTarget();
void testCreateTargetBasedirs();
private:
CalamaresUtils::System* m_system = nullptr; // Points to singleton instance, not owned
Calamares::GlobalStorage* m_gs = nullptr;
};
static const char testFile[] = "/calamares-testcreate";
static const char absFile[] = "/tmp/calamares-testcreate"; // With rootMountPoint prepended
void
TestPaths::initTestCase()
{
Logger::setupLogLevel( Logger::LOGDEBUG );
// Ensure we have a system object, expect it to be a "bogus" one
CalamaresUtils::System* system = CalamaresUtils::System::instance();
QVERIFY( system );
QVERIFY( system->doChroot() );
// Ensure we have a system-wide GlobalStorage with /tmp as root
if ( !Calamares::JobQueue::instance() )
{
cDebug() << "Creating new JobQueue";
(void)new Calamares::JobQueue();
}
Calamares::GlobalStorage* gs
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
QVERIFY( gs );
m_system = system;
m_gs = gs;
}
void
TestPaths::cleanupTestCase()
{
QFile::remove( absFile );
}
void
TestPaths::init()
{
cDebug() << "Setting rootMountPoint";
m_gs->insert( "rootMountPoint", "/tmp" );
}
void
TestPaths::testTargetPath()
{
// Paths mapped normally
QCOMPARE( m_system->targetPath( "/etc/calamares" ), QStringLiteral( "/tmp/etc/calamares" ) );
QCOMPARE( m_system->targetPath( "//etc//calamares" ),
QStringLiteral( "/tmp//etc//calamares" ) ); // extra / are not cleaned up
QCOMPARE( m_system->targetPath( "etc/calamares" ), QStringLiteral( "/tmp/etc/calamares" ) ); // relative to root
// Weird Paths
QCOMPARE( m_system->targetPath( QString() ), QStringLiteral( "/tmp/" ) );
// Now break GS
m_gs->remove( "rootMountPoint" );
QCOMPARE( m_system->targetPath( QString() ), QString() ); // Without root, no path
}
void
TestPaths::testCreateTarget()
{
QCOMPARE( m_system->createTargetFile( testFile, "Hello" ), QString( absFile ) ); // Success
QFileInfo fi( absFile );
QVERIFY( fi.exists() );
QCOMPARE( fi.size(), 5 );
m_system->removeTargetFile( testFile );
QFileInfo fi2( absFile ); // fi caches information
QVERIFY( !fi2.exists() );
}
struct DirRemover
{
DirRemover( const QString& base, const QString& dir )
: m_base( base )
, m_dir( dir )
{
}
~DirRemover() { QDir( m_base ).rmpath( m_dir ); }
bool exists() const { return QDir( m_base ).exists( m_dir ); }
QString m_base, m_dir;
};
void
TestPaths::testCreateTargetBasedirs()
{
{
DirRemover dirrm( "/tmp", "var/lib/dbus" );
QVERIFY( m_system->createTargetDirs( "/" ) );
QVERIFY( m_system->createTargetDirs( "/var/lib/dbus" ) );
QVERIFY( QFile( "/tmp/var/lib/dbus" ).exists() );
QVERIFY( dirrm.exists() );
}
QVERIFY( !QFile( "/tmp/var/lib/dbus" ).exists() );
// QFileInfo.dir() behaves even when things don't exist
QCOMPARE( QFileInfo( "/tmp/var/lib/dbus/bogus" ).dir().path(), QStringLiteral( "/tmp/var/lib/dbus" ) );
}
QTEST_GUILESS_MAIN( TestPaths )
#include "utils/moc-warnings.h"
#include "TestPaths.moc"

View File

@ -24,6 +24,9 @@
#include "UMask.h" #include "UMask.h"
#include "Yaml.h" #include "Yaml.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QtTest/QtTest> #include <QtTest/QtTest>
@ -221,3 +224,30 @@ LibCalamaresTests::testPrintableEntropy()
QVERIFY( c.cell() < 127 ); QVERIFY( c.cell() < 127 );
} }
} }
void
LibCalamaresTests::testOddSizedPrintable()
{
QString s;
for ( int l = 0; l <= 37; ++l )
{
auto r = CalamaresUtils::getPrintableEntropy( l, s );
if ( l == 0 )
{
QCOMPARE( r, CalamaresUtils::EntropySource::None );
}
else
{
QVERIFY( r != CalamaresUtils::EntropySource::None );
}
QCOMPARE( s.length(), l );
for ( QChar c : s )
{
QVERIFY( c.isPrint() );
QCOMPARE( c.row(), 0 );
QVERIFY( c.cell() > 32 ); // ASCII SPACE
QVERIFY( c.cell() < 127 );
}
}
}

View File

@ -43,6 +43,7 @@ private Q_SLOTS:
/** @brief Tests the entropy functions. */ /** @brief Tests the entropy functions. */
void testEntropy(); void testEntropy();
void testPrintableEntropy(); void testPrintableEntropy();
void testOddSizedPrintable();
}; };
#endif #endif

View File

@ -1,8 +0,0 @@
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreserved-id-macro"
#pragma clang diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#pragma clang diagnostic ignored "-Wextra-semi-stmt"
#pragma clang diagnostic ignored "-Wall"
#endif

View File

@ -3,6 +3,7 @@
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2019, Adriaan de Groot <groot@kde.org> * Copyright 2017-2019, Adriaan de Groot <groot@kde.org>
* Copyright 2018, Raul Rodrigo Segura (raurodse) * Copyright 2018, Raul Rodrigo Segura (raurodse)
* Copyright 2019, Camilo Higuita <milo.h@aol.com>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -74,7 +75,8 @@ const QStringList Branding::s_imageEntryStrings =
{ {
"productLogo", "productLogo",
"productIcon", "productIcon",
"productWelcome" "productWelcome",
"productWallpaper"
}; };
const QStringList Branding::s_styleEntryStrings = const QStringList Branding::s_styleEntryStrings =

View File

@ -3,6 +3,7 @@
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org> * Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
* Copyright 2018, Raul Rodrigo Segura (raurodse) * Copyright 2018, Raul Rodrigo Segura (raurodse)
* Copyright 2019, Camilo Higuita <milo.h@aol.com>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -48,7 +49,7 @@ public:
* e.g. *Branding::ProductName to get the string value for * e.g. *Branding::ProductName to get the string value for
* the product name. * the product name.
*/ */
enum StringEntry : short enum StringEntry
{ {
ProductName, ProductName,
Version, Version,
@ -62,13 +63,16 @@ public:
KnownIssuesUrl, KnownIssuesUrl,
ReleaseNotesUrl ReleaseNotesUrl
}; };
Q_ENUM( StringEntry )
enum ImageEntry : short enum ImageEntry : short
{ {
ProductLogo, ProductLogo,
ProductIcon, ProductIcon,
ProductWelcome ProductWelcome,
ProductWallpaper
}; };
Q_ENUM( ImageEntry )
enum StyleEntry : short enum StyleEntry : short
{ {
@ -77,6 +81,7 @@ public:
SidebarTextSelect, SidebarTextSelect,
SidebarTextHighlight SidebarTextHighlight
}; };
Q_ENUM( StyleEntry )
/** @brief Setting for how much the main window may expand. */ /** @brief Setting for how much the main window may expand. */
enum class WindowExpansion enum class WindowExpansion
@ -85,6 +90,7 @@ public:
Fullscreen, Fullscreen,
Fixed Fixed
}; };
Q_ENUM( WindowExpansion )
/** @brief Setting for the main window size. /** @brief Setting for the main window size.
* *
* The units are pixels (Pixies) or something-based-on-fontsize (Fonties), which * The units are pixels (Pixies) or something-based-on-fontsize (Fonties), which
@ -96,6 +102,7 @@ public:
Pixies, Pixies,
Fonties Fonties
}; };
Q_ENUM( WindowDimensionUnit )
class WindowDimension : public NamedSuffix< WindowDimensionUnit, WindowDimensionUnit::None > class WindowDimension : public NamedSuffix< WindowDimensionUnit, WindowDimensionUnit::None >
{ {
public: public:

View File

@ -16,8 +16,11 @@ set( calamaresui_SOURCES
utils/CalamaresUtilsGui.cpp utils/CalamaresUtilsGui.cpp
utils/ImageRegistry.cpp utils/ImageRegistry.cpp
utils/Paste.cpp utils/Paste.cpp
utils/Qml.cpp
viewpages/BlankViewStep.cpp viewpages/BlankViewStep.cpp
viewpages/ExecutionViewStep.cpp
viewpages/QmlViewStep.cpp
viewpages/ViewStep.cpp viewpages/ViewStep.cpp
widgets/ClickableLabel.cpp widgets/ClickableLabel.cpp
@ -25,7 +28,6 @@ set( calamaresui_SOURCES
widgets/WaitingWidget.cpp widgets/WaitingWidget.cpp
${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp ${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp
ExecutionViewStep.cpp
Branding.cpp Branding.cpp
ViewManager.cpp ViewManager.cpp
) )

View File

@ -21,17 +21,16 @@
#include "ViewManager.h" #include "ViewManager.h"
#include "viewpages/BlankViewStep.h"
#include "viewpages/ViewStep.h"
#include "Branding.h" #include "Branding.h"
#include "ExecutionViewStep.h"
#include "JobQueue.h" #include "JobQueue.h"
#include "Settings.h" #include "Settings.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Paste.h" #include "utils/Paste.h"
#include "utils/Retranslator.h" #include "utils/Retranslator.h"
#include "viewpages/BlankViewStep.h"
#include "viewpages/ViewStep.h"
#include "viewpages/ExecutionViewStep.h"
#include <QApplication> #include <QApplication>
#include <QBoxLayout> #include <QBoxLayout>
@ -159,13 +158,6 @@ void
ViewManager::insertViewStep( int before, ViewStep* step ) ViewManager::insertViewStep( int before, ViewStep* step )
{ {
m_steps.insert( before, step ); m_steps.insert( before, step );
QLayout* layout = step->widget()->layout();
if ( layout )
{
layout->setContentsMargins( 0, 0, 0, 0 );
}
m_stack->insertWidget( before, step->widget() );
connect( step, &ViewStep::enlarge, this, &ViewManager::enlarge ); connect( step, &ViewStep::enlarge, this, &ViewManager::enlarge );
connect( step, &ViewStep::nextStatusChanged, this, [this]( bool status ) { connect( step, &ViewStep::nextStatusChanged, this, [this]( bool status ) {
ViewStep* vs = qobject_cast< ViewStep* >( sender() ); ViewStep* vs = qobject_cast< ViewStep* >( sender() );
@ -178,6 +170,17 @@ ViewManager::insertViewStep( int before, ViewStep* step )
} }
} ); } );
if ( !step->widget() )
{
cError() << "ViewStep" << step->moduleInstanceKey() << "has no widget.";
}
QLayout* layout = step->widget()->layout();
if ( layout )
{
layout->setContentsMargins( 0, 0, 0, 0 );
}
m_stack->insertWidget( before, step->widget() );
m_stack->setCurrentIndex( 0 ); m_stack->setCurrentIndex( 0 );
step->widget()->setFocus(); step->widget()->setFocus();
} }

View File

@ -19,7 +19,6 @@
#include "ModuleManager.h" #include "ModuleManager.h"
#include "ExecutionViewStep.h"
#include "Module.h" #include "Module.h"
#include "RequirementsChecker.h" #include "RequirementsChecker.h"
#include "Settings.h" #include "Settings.h"
@ -27,6 +26,7 @@
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Yaml.h" #include "utils/Yaml.h"
#include "viewpages/ExecutionViewStep.h"
#include <QApplication> #include <QApplication>
#include <QDir> #include <QDir>
@ -129,8 +129,9 @@ ModuleManager::doInit()
} }
// At this point m_availableDescriptorsByModuleName is filled with // At this point m_availableDescriptorsByModuleName is filled with
// the modules that were found in the search paths. // the modules that were found in the search paths.
cDebug() << "Found" << m_availableDescriptorsByModuleName.count() << "modules" cDebug() << "Found"
<< m_moduleDirectoriesByModuleName.count() << "names"; << m_availableDescriptorsByModuleName.count() << "modules"
<< m_moduleDirectoriesByModuleName.count() << "names";
emit initDone(); emit initDone();
} }

View File

@ -0,0 +1,52 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Qml.h"
#include "utils/Logger.h"
#include <QByteArray>
#include <QObject>
#include <QQuickItem>
#include <QVariant>
namespace CalamaresUtils
{
void
callQMLFunction( QQuickItem* qmlObject, const char* method )
{
QByteArray methodSignature( method );
methodSignature.append( "()" );
if ( qmlObject && qmlObject->metaObject()->indexOfMethod( methodSignature ) >= 0 )
{
QVariant returnValue;
QMetaObject::invokeMethod( qmlObject, method, Q_RETURN_ARG( QVariant, returnValue ) );
if ( !returnValue.isNull() )
{
cDebug() << "QML" << methodSignature << "returned" << returnValue;
}
}
else if ( qmlObject )
{
cDebug() << "QML" << methodSignature << "is missing.";
}
}
} // namespace CalamaresUtils

View File

@ -0,0 +1,42 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef UTILS_QML_H
#define UTILS_QML_H
#include "DllMacro.h"
class QQuickItem;
namespace CalamaresUtils
{
/** @brief Calls the QML method @p method on @p qmlObject
*
* Pass in only the name of the method (e.g. onActivate). This function
* checks if the method exists (with no arguments) before trying to
* call it, so that no warnings are printed due to missing methods.
*
* If there is a return value from the QML method, it is logged (but not otherwise used).
*/
DLLEXPORT void
callQMLFunction( QQuickItem* qmlObject, const char* method );
} // namespace CalamaresUtils
#endif

View File

@ -19,12 +19,7 @@
#ifndef BLANKVIEWSTEP_H #ifndef BLANKVIEWSTEP_H
#define BLANKVIEWSTEP_H #define BLANKVIEWSTEP_H
#include <QObject> #include "viewpages/ViewStep.h"
#include <utils/PluginFactory.h>
#include <viewpages/ViewStep.h>
class QWidget;
namespace Calamares namespace Calamares
{ {

View File

@ -18,19 +18,20 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <ExecutionViewStep.h> #include "ExecutionViewStep.h"
#include "Branding.h" #include "Branding.h"
#include "Job.h" #include "Job.h"
#include "JobQueue.h" #include "JobQueue.h"
#include "Settings.h" #include "Settings.h"
#include "ViewManager.h" #include "ViewManager.h"
#include "modulesystem/Module.h" #include "modulesystem/Module.h"
#include "modulesystem/ModuleManager.h" #include "modulesystem/ModuleManager.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
#include "utils/Dirs.h" #include "utils/Dirs.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Qml.h"
#include "utils/Retranslator.h" #include "utils/Retranslator.h"
#include <QDir> #include <QDir>
@ -42,35 +43,6 @@
#include <QQuickWidget> #include <QQuickWidget>
#include <QVBoxLayout> #include <QVBoxLayout>
/** @brief Calls the QML method @p method()
*
* Pass in only the name of the method (e.g. onActivate). This function
* checks if the method exists (with no arguments) before trying to
* call it, so that no warnings are printed due to missing methods.
*
* If there is a return value from the QML method, it is logged (but not otherwise used).
*/
static void
callQMLFunction( QQuickItem* qmlObject, const char* method )
{
QByteArray methodSignature( method );
methodSignature.append( "()" );
if ( qmlObject && qmlObject->metaObject()->indexOfMethod( methodSignature ) >= 0 )
{
QVariant returnValue;
QMetaObject::invokeMethod( qmlObject, method, Q_RETURN_ARG( QVariant, returnValue ) );
if ( !returnValue.isNull() )
{
cDebug() << "QML" << methodSignature << "returned" << returnValue;
}
}
else if ( qmlObject )
{
cDebug() << "QML" << methodSignature << "is missing.";
}
}
namespace Calamares namespace Calamares
{ {
@ -205,7 +177,7 @@ changeSlideShowState( Slideshow state, QQuickItem* slideshow, QQuickWidget* widg
if ( Branding::instance()->slideshowAPI() == 2 ) if ( Branding::instance()->slideshowAPI() == 2 )
{ {
// The QML was already loaded in the constructor, need to start it // The QML was already loaded in the constructor, need to start it
callQMLFunction( slideshow, activate ? "onActivate" : "onLeave" ); CalamaresUtils::callQMLFunction( slideshow, activate ? "onActivate" : "onLeave" );
} }
else if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() ) else if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() )
{ {

View File

@ -0,0 +1,322 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "QmlViewStep.h"
#include "Branding.h"
#include "ViewManager.h"
#include "utils/Dirs.h"
#include "utils/Logger.h"
#include "utils/NamedEnum.h"
#include "utils/Qml.h"
#include "utils/Variant.h"
#include "widgets/WaitingWidget.h"
#include <QQmlComponent>
#include <QQmlEngine>
#include <QQuickItem>
#include <QQuickWidget>
#include <QVBoxLayout>
#include <QWidget>
static const NamedEnumTable< Calamares::QmlViewStep::QmlSearch >&
searchNames()
{
using Search = Calamares::QmlViewStep::QmlSearch;
// *INDENT-OFF*
// clang-format off
static NamedEnumTable< Search > names {
{ QStringLiteral( "both" ), Search::Both },
{ QStringLiteral( "qrc" ), Search::QrcOnly },
{ QStringLiteral( "branding" ), Search::BrandingOnly }
};
// *INDENT-ON*
// clang-format on
return names;
}
/// @brief State-change of the QML, for changeQMLState()
enum class QMLAction
{
Start,
Stop
};
/** @brief Tells the QML we activated or left it.
*
* If @p action is @c QMLAction::Start, calls onActivate in the QML.
* If @p action is @c QMLAction::Stop, calls onLeave in the QML.
*
* Sets *activatedInCalamares* property on the QML as well (to true
* if @p action is @c QMLAction::Start, false otherwise).
*/
static void
changeQMLState( QMLAction action, QQuickItem* item )
{
static const char propertyName[] = "activatedInCalamares";
bool activate = action == QMLAction::Start;
CalamaresUtils::callQMLFunction( item, activate ? "onActivate" : "onLeave" );
auto property = item->property( propertyName );
if ( property.isValid() && ( property.type() == QVariant::Bool ) && ( property.toBool() != activate ) )
{
item->setProperty( propertyName, activate );
}
}
namespace Calamares
{
QmlViewStep::QmlViewStep( const QString& name, QObject* parent )
: ViewStep( parent )
, m_name( name )
, m_widget( new QWidget )
, m_spinner( new WaitingWidget( tr( "Loading ..." ) ) )
, m_qmlWidget( new QQuickWidget )
{
QVBoxLayout* layout = new QVBoxLayout( m_widget );
layout->addWidget( m_spinner );
m_qmlWidget->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
m_qmlWidget->setResizeMode( QQuickWidget::SizeRootObjectToView );
m_qmlWidget->engine()->addImportPath( CalamaresUtils::qmlModulesDir().absolutePath() );
// QML Loading starts when the configuration for the module is set.
}
QmlViewStep::~QmlViewStep() {}
QString
QmlViewStep::prettyName() const
{
// TODO: query the QML itself
return tr( "QML Step <i>%1</i>." ).arg( m_name );
}
bool
QmlViewStep::isAtBeginning() const
{
return true;
}
bool
QmlViewStep::isAtEnd() const
{
return true;
}
bool
QmlViewStep::isBackEnabled() const
{
return true;
}
bool
QmlViewStep::isNextEnabled() const
{
return true;
}
Calamares::JobList
QmlViewStep::jobs() const
{
return JobList();
}
void
QmlViewStep::onActivate()
{
if ( m_qmlObject )
{
changeQMLState( QMLAction::Start, m_qmlObject );
}
}
void
QmlViewStep::onLeave()
{
if ( m_qmlObject )
{
changeQMLState( QMLAction::Stop, m_qmlObject );
}
}
QWidget*
QmlViewStep::widget()
{
return m_widget;
}
void
QmlViewStep::loadComplete()
{
cDebug() << "QML component" << m_qmlFileName << m_qmlComponent->status();
if ( m_qmlComponent->status() == QQmlComponent::Error )
{
showFailedQml();
}
if ( m_qmlComponent->isReady() && !m_qmlObject )
{
cDebug() << "QML component complete" << m_qmlFileName;
// Don't do this again
disconnect( m_qmlComponent, &QQmlComponent::statusChanged, this, &QmlViewStep::loadComplete );
QObject* o = m_qmlComponent->create();
m_qmlObject = qobject_cast< QQuickItem* >( o );
if ( !m_qmlObject )
{
cError() << Logger::SubEntry << "Could not create QML from" << m_qmlFileName;
delete o;
}
else
{
// setContent() is public API, but not documented publicly.
// It is marked \internal in the Qt sources, but does exactly
// what is needed: sets up visual parent by replacing the root
// item, and handling resizes.
m_qmlWidget->setContent( QUrl( m_qmlFileName ), m_qmlComponent, m_qmlObject );
showQml();
}
}
}
void
QmlViewStep::showQml()
{
if ( !m_qmlWidget || !m_qmlObject )
{
cDebug() << "showQml() called but no QML object";
return;
}
if ( m_spinner )
{
m_widget->layout()->removeWidget( m_spinner );
m_widget->layout()->addWidget( m_qmlWidget );
delete m_spinner;
m_spinner = nullptr;
}
else
{
cDebug() << "showQml() called twice";
}
if ( ViewManager::instance()->currentStep() == this )
{
// We're alreay visible! Must have been slow QML loading, and we
// passed onActivate already.
changeQMLState( QMLAction::Start, m_qmlObject );
}
}
/** @brief Find a suitable QML file, given the search method and name hints
*
* Returns QString() if nothing is found (which would mean the module
* is badly configured).
*/
QString
searchQmlFile( QmlViewStep::QmlSearch method, const QString& configuredName, const QString& moduleName )
{
using QmlSearch = Calamares::QmlViewStep::QmlSearch;
cDebug() << "Looking for QML for" << moduleName;
QStringList candidates;
if ( configuredName.startsWith( '/' ) )
{
candidates << configuredName;
}
if ( ( method == QmlSearch::Both ) || ( method == QmlSearch::BrandingOnly ) )
{
QString brandDir = Calamares::Branding::instance()->componentDirectory();
candidates << ( configuredName.isEmpty() ? QString()
: QStringLiteral( "%1/%2.qml" ).arg( brandDir, configuredName ) )
<< ( moduleName.isEmpty() ? QString() : QStringLiteral( "%1/%2.qml" ).arg( brandDir, moduleName ) );
}
if ( ( method == QmlSearch::Both ) || ( method == QmlSearch::QrcOnly ) )
{
candidates << ( configuredName.isEmpty() ? QString() : QStringLiteral( ":/%1.qml" ).arg( configuredName ) )
<< ( moduleName.isEmpty() ? QString() : QStringLiteral( ":/%1.qml" ).arg( moduleName ) );
}
for ( const QString& candidate : candidates )
{
if ( candidate.isEmpty() )
{
continue;
}
cDebug() << Logger::SubEntry << "Looking at QML file" << candidate;
if ( QFile::exists( candidate ) )
{
if ( candidate.startsWith( ':' ) )
{
// Inconsistency: QFile only sees the file with :,
// but QML needs an explicit scheme (of qrc:)
return QStringLiteral( "qrc" ) + candidate;
}
return candidate;
}
}
cDebug() << Logger::SubEntry << "None found.";
return QString();
}
void
QmlViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{
bool ok = false;
m_searchMethod = searchNames().find( CalamaresUtils::getString( configurationMap, "search" ), ok );
if ( !ok )
{
cDebug() << "Bad QML search mode.";
}
QString qmlFile = CalamaresUtils::getString( configurationMap, "filename" );
if ( qmlFile.isEmpty() )
{
// TODO use the module instance
}
if ( !m_qmlComponent )
{
m_qmlFileName = searchQmlFile( m_searchMethod, qmlFile, m_name );
cDebug() << "QmlViewStep" << moduleInstanceKey() << "loading" << m_qmlFileName;
m_qmlComponent = new QQmlComponent(
m_qmlWidget->engine(), QUrl( m_qmlFileName ), QQmlComponent::CompilationMode::Asynchronous );
connect( m_qmlComponent, &QQmlComponent::statusChanged, this, &QmlViewStep::loadComplete );
if ( m_qmlComponent->status() == QQmlComponent::Error )
{
showFailedQml();
}
}
else
{
cWarning() << "QML configuration set after component has loaded.";
}
}
void
QmlViewStep::showFailedQml()
{
cWarning() << "QmlViewStep" << moduleInstanceKey() << "loading failed.";
m_spinner->setText( prettyName() + ' ' + tr( "Loading failed." ) );
}
} // namespace Calamares

View File

@ -0,0 +1,102 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef QMLVIEWSTEP_H
#define QMLVIEWSTEP_H
#include "viewpages/ViewStep.h"
class QQmlComponent;
class QQuickItem;
class QQuickWidget;
class WaitingWidget;
namespace Calamares
{
/** @brief A viewstep that uses QML for the UI
*
* This is generally a **base** class for other view steps, but
* it can be used stand-alone for viewsteps that don't really have
* any functionality.
*/
class QmlViewStep : public Calamares::ViewStep
{
Q_OBJECT
public:
enum class QmlSearch
{
QrcOnly,
BrandingOnly,
Both
};
/** @brief Creates a QML view step
*
* The name should not have an extension or schema or anything;
* just the plain name, which will be searched as "/<name>.qml" in
* QRC files, or "<name>.qml" in suitable branding paths.
* The search behavior depends on a QmlSearch value.
*/
QmlViewStep( const QString& name, QObject* parent = nullptr );
virtual ~QmlViewStep() override;
virtual QString prettyName() const override;
virtual QWidget* widget() override;
virtual bool isNextEnabled() const override;
virtual bool isBackEnabled() const override;
virtual bool isAtBeginning() const override;
virtual bool isAtEnd() const override;
virtual void onActivate() override;
virtual void onLeave() override;
/// @brief QML widgets don't produce jobs by default
virtual JobList jobs() const override;
/// @brief Configure search paths; subclasses should call this as well
virtual void setConfigurationMap( const QVariantMap& configurationMap ) override;
private Q_SLOTS:
void loadComplete();
private:
/// @brief Swap out the spinner for the QQuickWidget
void showQml();
/// @brief Show error message in spinner.
void showFailedQml();
/// @brief Controls where m_name is searched
QmlSearch m_searchMethod;
QString m_name;
QString m_qmlFileName;
QWidget* m_widget = nullptr;
WaitingWidget* m_spinner = nullptr;
QQuickWidget* m_qmlWidget = nullptr;
QQmlComponent* m_qmlComponent = nullptr;
QQuickItem* m_qmlObject = nullptr;
};
} // namespace Calamares
#endif

View File

@ -156,7 +156,8 @@ HostInfoJob::exec()
gs->insert( "hostOSName", hostOSName() ); gs->insert( "hostOSName", hostOSName() );
gs->insert( "hostCPU", hostCPU() ); gs->insert( "hostCPU", hostCPU() );
auto ram = CalamaresUtils::BytesToMiB( CalamaresUtils::System::instance()->getTotalMemoryB().first ); // Memory can't be negative, so it's reported as unsigned long.
auto ram = CalamaresUtils::BytesToMiB( qint64( CalamaresUtils::System::instance()->getTotalMemoryB().first ) );
if ( ram ) if ( ram )
{ {
gs->insert( "hostRAMMiB", ram ); gs->insert( "hostRAMMiB", ram );

View File

@ -4,7 +4,7 @@
# === This file is part of Calamares - <https://github.com/calamares> === # === This file is part of Calamares - <https://github.com/calamares> ===
# #
# Copyright 2014, Rohan Garg <rohan@kde.org> # Copyright 2014, Rohan Garg <rohan@kde.org>
# Copyright 2015,2019, Philip Müller <philm@manjaro.org> # Copyright 2015,2019,2020, Philip Müller <philm@manjaro.org>
# Copyright 2017, Alf Gaida <agaida@sidution.org> # Copyright 2017, Alf Gaida <agaida@sidution.org>
# Copyright 2019, Adriaan de Groot <groot@kde.org> # Copyright 2019, Adriaan de Groot <groot@kde.org>
# #
@ -136,6 +136,13 @@ def modify_mkinitcpio_conf(partitions, root_mount_point):
if detect_plymouth(): if detect_plymouth():
hooks.append("plymouth") hooks.append("plymouth")
# Detect bootsplash theme and enable hook
bootsplash_folder = os.path.join(root_mount_point, "usr/lib/firmware/bootsplash-themes")
if os.path.exists(bootsplash_folder):
bootsplash_themes = os.listdir(bootsplash_folder)
for bootsplash_theme in bootsplash_themes:
hooks.append("bootsplash-{!s}".format(bootsplash_theme))
for partition in partitions: for partition in partitions:
if partition["fs"] == "linuxswap": if partition["fs"] == "linuxswap":
swap_uuid = partition["uuid"] swap_uuid = partition["uuid"]

View File

@ -12,6 +12,7 @@ calamares_add_plugin( machineid
if ( ECM_FOUND AND BUILD_TESTING ) if ( ECM_FOUND AND BUILD_TESTING )
ecm_add_test( ecm_add_test(
Tests.cpp Tests.cpp
MachineIdJob.cpp
Workers.cpp Workers.cpp
TEST_NAME TEST_NAME
machineidtest machineidtest

View File

@ -3,7 +3,7 @@
* Copyright 2014, Kevin Kofler <kevin.kofler@chello.at> * Copyright 2014, Kevin Kofler <kevin.kofler@chello.at>
* Copyright 2016, Philip Müller <philm@manjaro.org> * Copyright 2016, Philip Müller <philm@manjaro.org>
* Copyright 2017, Alf Gaida <agaida@siduction.org> * Copyright 2017, Alf Gaida <agaida@siduction.org>
* Copyright 2019, Adriaan de Groot <groot@kde.org> * Copyright 2019-2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -68,18 +68,20 @@ MachineIdJob::exec()
QString target_dbus_machineid_file = QStringLiteral( "/var/lib/dbus/machine-id" ); QString target_dbus_machineid_file = QStringLiteral( "/var/lib/dbus/machine-id" );
QString target_entropy_file = QStringLiteral( "/var/lib/urandom/random-seed" ); QString target_entropy_file = QStringLiteral( "/var/lib/urandom/random-seed" );
const CalamaresUtils::System* system = CalamaresUtils::System::instance();
// Clear existing files // Clear existing files
if ( m_entropy ) if ( m_entropy )
{ {
MachineId::removeFile( root, target_entropy_file ); system->removeTargetFile( target_entropy_file );
} }
if ( m_dbus ) if ( m_dbus )
{ {
MachineId::removeFile( root, target_dbus_machineid_file ); system->removeTargetFile( target_dbus_machineid_file );
} }
if ( m_systemd ) if ( m_systemd )
{ {
MachineId::removeFile( root, target_systemd_machineid_file ); system->removeTargetFile( target_systemd_machineid_file );
} }
//Create new files //Create new files
@ -104,6 +106,10 @@ MachineIdJob::exec()
} }
if ( m_dbus ) if ( m_dbus )
{ {
if ( !system->createTargetParentDirs( target_dbus_machineid_file ) )
{
cWarning() << "Could not create DBus data-directory.";
}
if ( m_dbus_symlink && QFile::exists( root + target_systemd_machineid_file ) ) if ( m_dbus_symlink && QFile::exists( root + target_systemd_machineid_file ) )
{ {
auto r = MachineId::createDBusLink( root, target_dbus_machineid_file, target_systemd_machineid_file ); auto r = MachineId::createDBusLink( root, target_dbus_machineid_file, target_systemd_machineid_file );

View File

@ -16,11 +16,14 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "MachineIdJob.h"
#include "Workers.h" #include "Workers.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QtTest/QtTest> #include <QtTest/QtTest>
@ -35,10 +38,11 @@ public:
private Q_SLOTS: private Q_SLOTS:
void initTestCase(); void initTestCase();
void testRemoveFile();
void testCopyFile(); void testCopyFile();
void testPoolSize(); void testPoolSize();
void testJob();
}; };
void void
@ -84,11 +88,6 @@ MachineIdTests::testCopyFile()
} }
} }
void
MachineIdTests::testRemoveFile()
{
}
void void
MachineIdTests::testPoolSize() MachineIdTests::testPoolSize()
{ {
@ -101,6 +100,62 @@ MachineIdTests::testPoolSize()
#endif #endif
} }
void
MachineIdTests::testJob()
{
Logger::setupLogLevel( Logger::LOGDEBUG );
// Ensure we have a system object, expect it to be a "bogus" one
CalamaresUtils::System* system = CalamaresUtils::System::instance();
QVERIFY( system );
QVERIFY( system->doChroot() );
// Ensure we have a system-wide GlobalStorage with /tmp as root
if ( !Calamares::JobQueue::instance() )
{
cDebug() << "Creating new JobQueue";
(void)new Calamares::JobQueue();
}
Calamares::GlobalStorage* gs
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
QVERIFY( gs );
gs->insert( "rootMountPoint", "/tmp" );
// Prepare part of the target filesystem
QVERIFY( system->createTargetDirs("/etc") );
QVERIFY( !(system->createTargetFile( "/etc/machine-id", "Hello" ).isEmpty() ) );
MachineIdJob job( nullptr );
QVERIFY( !job.prettyName().isEmpty() );
QVariantMap config;
config.insert( "dbus", true );
job.setConfigurationMap( config );
{
auto r = job.exec();
QVERIFY( !r ); // It's supposed to fail, because no dbus-uuidgen executable exists
QVERIFY( QFile::exists( "/tmp/var/lib/dbus" ) ); // but the target dir exists
}
config.insert( "dbus-symlink", true );
job.setConfigurationMap( config );
{
auto r = job.exec();
QVERIFY( !r ); // It's supposed to fail, because no dbus-uuidgen executable exists
QVERIFY( QFile::exists( "/tmp/var/lib/dbus" ) ); // but the target dir exists
// These all (would) fail, because the chroot isn't viable
#if 0
QVERIFY( QFile::exists( "/tmp/var/lib/dbus/machine-id" ) );
QFileInfo fi( "/tmp/var/lib/dbus/machine-id" );
QVERIFY( fi.exists() );
QVERIFY( fi.isSymLink() );
QCOMPARE( fi.size(), 5);
#endif
}
}
QTEST_GUILESS_MAIN( MachineIdTests ) QTEST_GUILESS_MAIN( MachineIdTests )

View File

@ -36,17 +36,6 @@ isAbsolutePath( const QString& fileName )
return fileName.startsWith( '/' ); return fileName.startsWith( '/' );
} }
// might need to use a helper to remove the file
void
removeFile( const QString& rootMountPoint, const QString& fileName )
{
if ( isAbsolutePath( fileName ) )
{
QFile::remove( rootMountPoint + fileName );
}
// Otherwise, do nothing
}
Calamares::JobResult Calamares::JobResult
copyFile( const QString& rootMountPoint, const QString& fileName ) copyFile( const QString& rootMountPoint, const QString& fileName )
{ {
@ -192,7 +181,7 @@ Calamares::JobResult
createDBusLink( const QString& rootMountPoint, const QString& fileName, const QString& systemdFileName ) createDBusLink( const QString& rootMountPoint, const QString& fileName, const QString& systemdFileName )
{ {
Q_UNUSED( rootMountPoint ) Q_UNUSED( rootMountPoint )
return runCmd( QStringList { QStringLiteral( "ln" ), QStringLiteral( "-s" ), systemdFileName, fileName } ); return runCmd( QStringList { QStringLiteral( "ln" ), QStringLiteral( "-sf" ), systemdFileName, fileName } );
} }
} // namespace MachineId } // namespace MachineId

View File

@ -30,9 +30,6 @@ namespace MachineId
* for moving files around in the target system. * for moving files around in the target system.
*/ */
/// @brief Remove @p fileName from the target system at @p rootMountPoint
void removeFile( const QString& rootMountPoint, const QString& fileName );
/// @brief Copy @p fileName from host into target system at @p rootMountPoint /// @brief Copy @p fileName from host into target system at @p rootMountPoint
Calamares::JobResult copyFile( const QString& rootMountPoint, const QString& fileName ); Calamares::JobResult copyFile( const QString& rootMountPoint, const QString& fileName );

View File

@ -1,73 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# === This file is part of Calamares - <https://github.com/calamares> ===
#
# Copyright 2014, Kevin Kofler <kevin.kofler@chello.at>
# Copyright 2019, Philip Müller <philm@manjaro.org>
# Copyright 2017, Alf Gaida <agaida@siduction.org>
# Copyright 2019, Adriaan de Groot <groot@kde.org>
#
# 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 <http://www.gnu.org/licenses/>.
import libcalamares
import os
from libcalamares.utils import check_target_env_call, debug
import gettext
_ = gettext.translation("calamares-python",
localedir=libcalamares.utils.gettext_path(),
languages=libcalamares.utils.gettext_languages(),
fallback=True).gettext
def pretty_name():
return _("Generate machine-id.")
def run():
"""
Generate machine-id using dbus and systemd.
:return:
"""
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
if root_mount_point is None:
libcalamares.utils.warning("rootMountPoint is empty, {!s}".format(root_mount_point))
return (_("Configuration Error"),
_("No root mount point is given for <pre>{!s}</pre> to use." ).format("machineid"))
enable_systemd = libcalamares.job.configuration["systemd"]
enable_dbus = libcalamares.job.configuration["dbus"]
enable_symlink = libcalamares.job.configuration["symlink"]
target_systemd_machineid_file = root_mount_point + "/etc/machine-id"
target_dbus_machineid_file = root_mount_point + "/var/lib/dbus/machine-id"
if os.path.exists(target_dbus_machineid_file):
os.remove(target_dbus_machineid_file)
if enable_systemd:
if os.path.exists(target_systemd_machineid_file):
os.remove(target_systemd_machineid_file)
check_target_env_call("systemd-machine-id-setup")
if enable_dbus:
if enable_symlink and os.path.exists(target_systemd_machineid_file):
check_target_env_call(["ln", "-sf", "/etc/machine-id",
"/var/lib/dbus/machine-id"])
else:
check_target_env_call(["dbus-uuidgen", "--ensure"])
return None

View File

@ -0,0 +1,11 @@
calamares_add_plugin( notesqml
TYPE viewmodule
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
NotesQmlViewStep.cpp
RESOURCES
notesqml.qrc
LINK_PRIVATE_LIBRARIES
calamaresui
SHARED_LIB
)

View File

@ -0,0 +1,52 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Adriaan de Groot <groot@kde.org>
* Copyright 2020, Anke Boersma <demm@kaosx.us>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "NotesQmlViewStep.h"
#include <QVariant>
NotesQmlViewStep::NotesQmlViewStep( QObject* parent )
: Calamares::QmlViewStep( "notesqml", parent )
{
}
NotesQmlViewStep::~NotesQmlViewStep() {}
QString
NotesQmlViewStep::prettyName() const
{
return m_notesName ? m_notesName->get() : tr( "Notes" );
}
void
NotesQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{
Calamares::QmlViewStep::setConfigurationMap( configurationMap ); // call parent implementation
bool qmlLabel_ok = false;
auto qmlLabel = CalamaresUtils::getSubMap( configurationMap, "qmlLabel", qmlLabel_ok );
if ( qmlLabel.contains( "notes" ) )
{
m_notesName = new CalamaresUtils::Locale::TranslatedString( qmlLabel, "notes" );
}
}
CALAMARES_PLUGIN_FACTORY_DEFINITION( NotesQmlViewStepFactory, registerPlugin< NotesQmlViewStep >(); )

View File

@ -0,0 +1,48 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Adriaan de Groot <groot@kde.org>
* Copyright 2020, Anke Boersma <demm@kaosx.us>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef NOTESQMLVIEWSTEP_H
#define NOTESQMLVIEWSTEP_H
#include "PluginDllMacro.h"
#include "locale/TranslatableConfiguration.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Variant.h"
#include "utils/PluginFactory.h"
#include "viewpages/QmlViewStep.h"
class PLUGINDLLEXPORT NotesQmlViewStep : public Calamares::QmlViewStep
{
Q_OBJECT
public:
NotesQmlViewStep( QObject* parent = nullptr );
virtual ~NotesQmlViewStep() override;
QString prettyName() const override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
private:
CalamaresUtils::Locale::TranslatedString* m_notesName; // As it appears in the sidebar
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( NotesQmlViewStepFactory )
#endif

View File

@ -0,0 +1,73 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Anke Boersma <demm@kaosx.us>
*
* 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 <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.1
Item {
width: 740
height: 420
Flickable {
id: flick
anchors.fill: parent
contentHeight: 800
ScrollBar.vertical: ScrollBar {
width: 10
policy: ScrollBar.AlwaysOn
}
TextArea {
id: intro
x: 1
y: 0
width: 720
font.pointSize: 14
textFormat: Text.RichText
antialiasing: true
activeFocusOnPress: false
wrapMode: Text.WordWrap
text: qsTr("<h3>Generic GNU/Linux 2017.8 LTS <quote>Soapy Sousaphone</quote></h3>
<p>This an example QML file, showing options in RichText with Flickable content.</p>
<p>QML with RichText can use HTML tags, Flickable content is useful for touchscreens.</p>
<p><b>This is bold text</b></p>
<p><i>This is italic text</i></p>
<p><u>This is underlined text</u></p>
<p><strike>This is strikethrough</strike></p>
<p>Code example:
<code>ls -l /home</code></p>
<p><b>Lists:</b></p>
<ul>
<li>Intel CPU systems</li>
<li>AMD CPU systems</li>
</ul>
<p>The vertical scrollbar is adjustable, current width set to 10.</p>")
}
}
}

View File

@ -0,0 +1,40 @@
# The *notesqml* module can be used to display a QML file
# as an installer step. This is most useful for release-notes
# and similar somewhat-static content, but if you want to you
# can put SameGame in there as well.
#
# While the module compiles a QML file into a QRC for inclusion
# into the shared library, normal use will configure it with
# an external file, either from Calamares AppData directory or
# from the branding directory.
#
# ---
#
# QML modules can search for the QML inside the Qt resources
# (QRC) which are compiled into the module, or in the branding
# setup for Calamares, (or both of them, with branding taking
# precedence). This allows the module to ship a default UI and
# branding to optionally introduce a replacement file.
#
# Generally, leave the search method set to "both" because if
# you don't want to brand the UI, just don't ship a branding
# QML file for it.
#
# To support instanced QML modules, searches in the branding
# directory look for the full notesqml@instanceid name as well.
---
# Search mode. Valid values are "both", "qrc" and "branding"
search: both
# Name of the QML file. If not set, uses the name of the instance
# of the module (e.g. if you list this module in `settings.conf`
# in the *instances* section, you get *id*, otherwise it would
# normally be "notesqml").
#filename: notesqml
# This is the name of the module in the progress-tree / sidebar
# in Calamares. To support multiple instances of the QML module,
# the name is configurable and translatable here.
qmlLabel:
notes: "Release Notes"
notes[nl]: "Opmerkingen"

View File

@ -0,0 +1,75 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, Anke Boersma <demm@kaosx.us>
*
* 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 <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.1
Item {
width: 740
height: 420
Flickable {
id: flick
anchors.fill: parent
contentHeight: 800
ScrollBar.vertical: ScrollBar {
id: fscrollbar
width: 10
policy: ScrollBar.AlwaysOn
}
TextArea {
id: intro
x: 1
y: 0
width: parent.width - fscrollbar.width
font.pointSize: 14
textFormat: Text.RichText
antialiasing: true
activeFocusOnPress: false
wrapMode: Text.WordWrap
text: qsTr("<h3>Generic GNU/Linux 2020.2 LTS <quote>Turgid Tuba</quote></h3>
<p>This an example QML file, showing options in RichText with Flickable content.</p>
<p>QML with RichText can use HTML tags, Flickable content is useful for touchscreens.</p>
<p><b>This is bold text</b></p>
<p><i>This is italic text</i></p>
<p><u>This is underlined text</u></p>
<p><center>This text will be center-aligned.</center></p>
<p><s>This is strikethrough</s></p>
<p>Code example:
<code>ls -l /home</code></p>
<p><b>Lists:</b></p>
<ul>
<li>Intel CPU systems</li>
<li>AMD CPU systems</li>
</ul>
<p>The vertical scrollbar is adjustable, current width set to 10.</p>")
}
}
}

View File

@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file alias="notesqml.qml">notesqml.qml</file>
</qresource>
</RCC>

View File

@ -114,6 +114,31 @@ Partition* createNewEncryptedPartition( PartitionNode* parent,
Partition* clonePartition( Device* device, Partition* partition ); Partition* clonePartition( Device* device, Partition* partition );
QString prettyNameForFileSystemType( FileSystem::Type t ); QString prettyNameForFileSystemType( FileSystem::Type t );
static inline QString
untranslatedFS( FileSystem& fs )
{
return fs.name( { QStringLiteral( "C" ) } );
}
static inline QString
untranslatedFS( FileSystem* fs )
{
return fs ? untranslatedFS( *fs ) : QString();
}
static inline QString
userVisibleFS( FileSystem& fs )
{
return fs.name();
}
static inline QString
userVisibleFS( FileSystem* fs )
{
return fs ? userVisibleFS( *fs ) : QString();
}
} }
#endif /* KPMHELPERS_H */ #endif /* KPMHELPERS_H */

View File

@ -2,7 +2,7 @@
* *
* Copyright 2014, Aurélien Gâteau <agateau@kde.org> * Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2016, Teo Mrnjavac <teo@kde.org> * Copyright 2016, Teo Mrnjavac <teo@kde.org>
* Copyright 2018, Adriaan de Groot <groot@kde.org> * Copyright 2018, 2020, Adriaan de Groot <groot@kde.org>
* Copyright 2018, Andrius Štikonas <andrius@stikonas.eu> * Copyright 2018, Andrius Štikonas <andrius@stikonas.eu>
* Copyright 2018, Caio Carvalho <caiojcarvalho@gmail.com> * Copyright 2018, Caio Carvalho <caiojcarvalho@gmail.com>
* *
@ -93,11 +93,17 @@ CreatePartitionDialog::CreatePartitionDialog( Device* device, PartitionNode* par
else else
initGptPartitionTypeUi(); initGptPartitionTypeUi();
// File system // File system; the config value is translated (best-effort) to a type
FileSystem::Type defaultFsType = FileSystem::typeForName( FileSystem::Type defaultFSType;
QString untranslatedFSName = PartUtils::findFS(
Calamares::JobQueue::instance()-> Calamares::JobQueue::instance()->
globalStorage()-> globalStorage()->
value( "defaultFileSystemType" ).toString() ); value( "defaultFileSystemType" ).toString(), &defaultFSType );
if ( defaultFSType == FileSystem::Type::Unknown )
{
defaultFSType = FileSystem::Type::Ext4;
}
int defaultFsIndex = -1; int defaultFsIndex = -1;
int fsCounter = 0; int fsCounter = 0;
QStringList fsNames; QStringList fsNames;
@ -106,8 +112,8 @@ CreatePartitionDialog::CreatePartitionDialog( Device* device, PartitionNode* par
if ( fs->supportCreate() != FileSystem::cmdSupportNone && if ( fs->supportCreate() != FileSystem::cmdSupportNone &&
fs->type() != FileSystem::Extended ) fs->type() != FileSystem::Extended )
{ {
fsNames << fs->name(); fsNames << KPMHelpers::userVisibleFS( fs ); // This is put into the combobox
if ( fs->type() == defaultFsType ) if ( fs->type() == defaultFSType )
defaultFsIndex = fsCounter; defaultFsIndex = fsCounter;
fsCounter++; fsCounter++;
} }
@ -232,6 +238,7 @@ CreatePartitionDialog::updateMountPointUi()
bool enabled = m_ui->primaryRadioButton->isChecked(); bool enabled = m_ui->primaryRadioButton->isChecked();
if ( enabled ) if ( enabled )
{ {
// This maps translated (user-visible) FS names to a type
FileSystem::Type type = FileSystem::typeForName( m_ui->fsComboBox->currentText() ); FileSystem::Type type = FileSystem::typeForName( m_ui->fsComboBox->currentText() );
enabled = !s_unmountableFS.contains( type ); enabled = !s_unmountableFS.contains( type );

View File

@ -2,7 +2,7 @@
* *
* Copyright 2014, Aurélien Gâteau <agateau@kde.org> * Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2016, Teo Mrnjavac <teo@kde.org> * Copyright 2016, Teo Mrnjavac <teo@kde.org>
* Copyright 2018, Adriaan de Groot <groot@kde.org> * Copyright 2018, 2020, Adriaan de Groot <groot@kde.org>
* *
* Flags handling originally from KDE Partition Manager, * Flags handling originally from KDE Partition Manager,
* Copyright 2008-2009, Volker Lanz <vl@fidra.de> * Copyright 2008-2009, Volker Lanz <vl@fidra.de>
@ -22,21 +22,21 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <gui/EditExistingPartitionDialog.h> #include "EditExistingPartitionDialog.h"
#include <core/ColorUtils.h> #include "core/ColorUtils.h"
#include <core/PartitionCoreModule.h> #include "core/PartitionCoreModule.h"
#include <core/PartitionInfo.h> #include "core/PartitionInfo.h"
#include "core/PartUtils.h" #include "core/PartUtils.h"
#include <core/KPMHelpers.h> #include "core/KPMHelpers.h"
#include "gui/PartitionDialogHelpers.h" #include "gui/PartitionDialogHelpers.h"
#include <gui/PartitionSizeController.h> #include "gui/PartitionSizeController.h"
#include <ui_EditExistingPartitionDialog.h> #include "ui_EditExistingPartitionDialog.h"
#include <utils/Logger.h>
#include "GlobalStorage.h" #include "GlobalStorage.h"
#include "JobQueue.h" #include "JobQueue.h"
#include "utils/Logger.h"
// KPMcore // KPMcore
#include <kpmcore/core/device.h> #include <kpmcore/core/device.h>
@ -77,7 +77,7 @@ EditExistingPartitionDialog::EditExistingPartitionDialog( Device* device, Partit
m_ui->fileSystemComboBox->setEnabled( doFormat ); m_ui->fileSystemComboBox->setEnabled( doFormat );
if ( !doFormat ) if ( !doFormat )
m_ui->fileSystemComboBox->setCurrentText( m_partition->fileSystem().name() ); m_ui->fileSystemComboBox->setCurrentText( KPMHelpers::userVisibleFS( m_partition->fileSystem() ) );
updateMountPointPicker(); updateMountPointPicker();
} ); } );
@ -93,16 +93,25 @@ EditExistingPartitionDialog::EditExistingPartitionDialog( Device* device, Partit
for ( auto fs : FileSystemFactory::map() ) for ( auto fs : FileSystemFactory::map() )
{ {
if ( fs->supportCreate() != FileSystem::cmdSupportNone && fs->type() != FileSystem::Extended ) if ( fs->supportCreate() != FileSystem::cmdSupportNone && fs->type() != FileSystem::Extended )
fsNames << fs->name(); fsNames << KPMHelpers::userVisibleFS( fs ); // For the combo box
} }
m_ui->fileSystemComboBox->addItems( fsNames ); m_ui->fileSystemComboBox->addItems( fsNames );
if ( fsNames.contains( m_partition->fileSystem().name() ) ) FileSystem::Type defaultFSType;
m_ui->fileSystemComboBox->setCurrentText( m_partition->fileSystem().name() ); QString untranslatedFSName = PartUtils::findFS(
Calamares::JobQueue::instance()->
globalStorage()->
value( "defaultFileSystemType" ).toString(), &defaultFSType );
if ( defaultFSType == FileSystem::Type::Unknown )
{
defaultFSType = FileSystem::Type::Ext4;
}
QString thisFSNameForUser = KPMHelpers::userVisibleFS( m_partition->fileSystem() );
if ( fsNames.contains( thisFSNameForUser ) )
m_ui->fileSystemComboBox->setCurrentText( thisFSNameForUser );
else else
m_ui->fileSystemComboBox->setCurrentText( Calamares::JobQueue::instance()-> m_ui->fileSystemComboBox->setCurrentText( FileSystem::nameForType( defaultFSType ) );
globalStorage()->
value( "defaultFileSystemType" ).toString() );
m_ui->fileSystemLabel->setEnabled( m_ui->formatRadioButton->isChecked() ); m_ui->fileSystemLabel->setEnabled( m_ui->formatRadioButton->isChecked() );
m_ui->fileSystemComboBox->setEnabled( m_ui->formatRadioButton->isChecked() ); m_ui->fileSystemComboBox->setEnabled( m_ui->formatRadioButton->isChecked() );

View File

@ -600,7 +600,7 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
else if ( fsType != FileSystem::Unknown ) else if ( fsType != FileSystem::Unknown )
cWarning() << "Partition-module setting *defaultFileSystemType* changed" << fsRealName; cWarning() << "Partition-module setting *defaultFileSystemType* changed" << fsRealName;
else else
cWarning() << "Partition-module setting *defaultFileSystemType* is bad (" << fsRealName << ") using ext4."; cWarning() << "Partition-module setting *defaultFileSystemType* is bad (" << fsName << ") using" << fsRealName << "instead.";
gs->insert( "defaultFileSystemType", fsRealName ); gs->insert( "defaultFileSystemType", fsRealName );

View File

@ -22,6 +22,7 @@
#include "ui_ReplaceWidget.h" #include "ui_ReplaceWidget.h"
#include "core/DeviceModel.h" #include "core/DeviceModel.h"
#include "core/KPMHelpers.h"
#include "core/PartitionCoreModule.h" #include "core/PartitionCoreModule.h"
#include "core/PartitionActions.h" #include "core/PartitionActions.h"
#include "core/PartitionInfo.h" #include "core/PartitionInfo.h"
@ -192,8 +193,8 @@ ReplaceWidget::onPartitionSelected()
return; return;
} }
QString prettyName = tr( "Data partition (%1)" ) QString fsNameForUser = KPMHelpers::userVisibleFS( partition->fileSystem() );
.arg( partition->fileSystem().name() ); QString prettyName = tr( "Data partition (%1)" ).arg( fsNameForUser );
for ( const QString& line : osproberLines ) for ( const QString& line : osproberLines )
{ {
QStringList lineColumns = line.split( ':' ); QStringList lineColumns = line.split( ':' );
@ -210,13 +211,13 @@ ReplaceWidget::onPartitionSelected()
if ( osName.isEmpty() ) if ( osName.isEmpty() )
{ {
prettyName = tr( "Unknown system partition (%1)" ) prettyName = tr( "Unknown system partition (%1)" )
.arg( partition->fileSystem().name() ); .arg( fsNameForUser );
} }
else else
{ {
prettyName = tr ( "%1 system partition (%2)" ) prettyName = tr ( "%1 system partition (%2)" )
.arg( osName.replace( 0, 1, osName.at( 0 ).toUpper() ) ) .arg( osName.replace( 0, 1, osName.at( 0 ).toUpper() ) )
.arg( partition->fileSystem().name() ); .arg( fsNameForUser );
} }
break; break;
} }

View File

@ -2,7 +2,7 @@
* *
* Copyright 2014, Aurélien Gâteau <agateau@kde.org> * Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2015, Teo Mrnjavac <teo@kde.org> * Copyright 2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org> * Copyright 2017, 2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,6 +20,8 @@
#include "jobs/CreatePartitionJob.h" #include "jobs/CreatePartitionJob.h"
#include "core/KPMHelpers.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Units.h" #include "utils/Units.h"
@ -32,6 +34,9 @@
#include <kpmcore/ops/newoperation.h> #include <kpmcore/ops/newoperation.h>
#include <kpmcore/util/report.h> #include <kpmcore/util/report.h>
using KPMHelpers::untranslatedFS;
using KPMHelpers::userVisibleFS;
CreatePartitionJob::CreatePartitionJob( Device* device, Partition* partition ) CreatePartitionJob::CreatePartitionJob( Device* device, Partition* partition )
: PartitionJob( partition ) : PartitionJob( partition )
, m_device( device ) , m_device( device )
@ -42,7 +47,7 @@ QString
CreatePartitionJob::prettyName() const CreatePartitionJob::prettyName() const
{ {
return tr( "Create new %2MiB partition on %4 (%3) with file system %1." ) return tr( "Create new %2MiB partition on %4 (%3) with file system %1." )
.arg( m_partition->fileSystem().name() ) .arg( userVisibleFS( m_partition->fileSystem() ) )
.arg( CalamaresUtils::BytesToMiB( m_partition->capacity() ) ) .arg( CalamaresUtils::BytesToMiB( m_partition->capacity() ) )
.arg( m_device->name() ) .arg( m_device->name() )
.arg( m_device->deviceNode() ); .arg( m_device->deviceNode() );
@ -54,7 +59,7 @@ CreatePartitionJob::prettyDescription() const
{ {
return tr( "Create new <strong>%2MiB</strong> partition on <strong>%4</strong> " return tr( "Create new <strong>%2MiB</strong> partition on <strong>%4</strong> "
"(%3) with file system <strong>%1</strong>." ) "(%3) with file system <strong>%1</strong>." )
.arg( m_partition->fileSystem().name() ) .arg( userVisibleFS( m_partition->fileSystem() ) )
.arg( CalamaresUtils::BytesToMiB( m_partition->capacity() ) ) .arg( CalamaresUtils::BytesToMiB( m_partition->capacity() ) )
.arg( m_device->name() ) .arg( m_device->name() )
.arg( m_device->deviceNode() ); .arg( m_device->deviceNode() );
@ -65,7 +70,7 @@ QString
CreatePartitionJob::prettyStatusMessage() const CreatePartitionJob::prettyStatusMessage() const
{ {
return tr( "Creating new %1 partition on %2." ) return tr( "Creating new %1 partition on %2." )
.arg( m_partition->fileSystem().name() ) .arg( userVisibleFS( m_partition->fileSystem() ) )
.arg( m_device->deviceNode() ); .arg( m_device->deviceNode() );
} }

View File

@ -2,7 +2,7 @@
* *
* Copyright 2014, Aurélien Gâteau <agateau@kde.org> * Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2015-2016, Teo Mrnjavac <teo@kde.org> * Copyright 2015-2016, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, 2019, Adriaan de Groot <groot@kde.org> * Copyright 2017, 2019-2020, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -20,12 +20,13 @@
#include "jobs/FillGlobalStorageJob.h" #include "jobs/FillGlobalStorageJob.h"
#include "GlobalStorage.h" #include "core/KPMHelpers.h"
#include "JobQueue.h"
#include "core/PartitionInfo.h" #include "core/PartitionInfo.h"
#include "core/PartitionIterator.h" #include "core/PartitionIterator.h"
#include "core/KPMHelpers.h"
#include "Branding.h" #include "Branding.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "utils/Logger.h" #include "utils/Logger.h"
// KPMcore // KPMcore
@ -40,16 +41,18 @@
#include <QFileInfo> #include <QFileInfo>
#include <QProcess> #include <QProcess>
typedef QHash<QString, QString> UuidForPartitionHash; using KPMHelpers::untranslatedFS;
using KPMHelpers::userVisibleFS;
typedef QHash< QString, QString > UuidForPartitionHash;
static UuidForPartitionHash static UuidForPartitionHash
findPartitionUuids( QList < Device* > devices ) findPartitionUuids( QList< Device* > devices )
{ {
UuidForPartitionHash hash; UuidForPartitionHash hash;
foreach ( Device* device, devices ) foreach ( Device* device, devices )
{ {
for ( auto it = PartitionIterator::begin( device ); for ( auto it = PartitionIterator::begin( device ); it != PartitionIterator::end( device ); ++it )
it != PartitionIterator::end( device ); ++it )
{ {
Partition* p = *it; Partition* p = *it;
QString path = p->partitionPath(); QString path = p->partitionPath();
@ -59,7 +62,9 @@ findPartitionUuids( QList < Device* > devices )
} }
if ( hash.isEmpty() ) if ( hash.isEmpty() )
{
cDebug() << "No UUIDs found for existing partitions."; cDebug() << "No UUIDs found for existing partitions.";
}
return hash; return hash;
} }
@ -73,7 +78,9 @@ getLuksUuid( const QString& path )
process.start(); process.start();
process.waitForFinished(); process.waitForFinished();
if ( process.exitStatus() != QProcess::NormalExit || process.exitCode() ) if ( process.exitStatus() != QProcess::NormalExit || process.exitCode() )
{
return QString(); return QString();
}
QString uuid = QString::fromLocal8Bit( process.readAllStandardOutput() ).trimmed(); QString uuid = QString::fromLocal8Bit( process.readAllStandardOutput() ).trimmed();
return uuid; return uuid;
} }
@ -85,22 +92,22 @@ mapForPartition( Partition* partition, const QString& uuid )
QVariantMap map; QVariantMap map;
map[ "device" ] = partition->partitionPath(); map[ "device" ] = partition->partitionPath();
map[ "mountPoint" ] = PartitionInfo::mountPoint( partition ); map[ "mountPoint" ] = PartitionInfo::mountPoint( partition );
map[ "fsName" ] = partition->fileSystem().name(); map[ "fsName" ] = userVisibleFS( partition->fileSystem() );
map[ "fs" ] = partition->fileSystem().name( { QStringLiteral("C") } ); // Untranslated map[ "fs" ] = untranslatedFS( partition->fileSystem() );
if ( partition->fileSystem().type() == FileSystem::Luks && if ( partition->fileSystem().type() == FileSystem::Luks
dynamic_cast< FS::luks& >( partition->fileSystem() ).innerFS() ) && dynamic_cast< FS::luks& >( partition->fileSystem() ).innerFS() )
map[ "fs" ] = dynamic_cast< FS::luks& >( partition->fileSystem() ).innerFS()->name(); {
map[ "fs" ] = untranslatedFS( dynamic_cast< FS::luks& >( partition->fileSystem() ).innerFS() );
}
map[ "uuid" ] = uuid; map[ "uuid" ] = uuid;
// Debugging for inside the loop in createPartitionList(), // Debugging for inside the loop in createPartitionList(),
// so indent a bit // so indent a bit
Logger::CDebug deb; Logger::CDebug deb;
using TR = Logger::DebugRow<const char *const, const QString&>; using TR = Logger::DebugRow< const char* const, const QString& >;
deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode() deb << Logger::SubEntry << "mapping for" << partition->partitionPath() << partition->deviceNode()
<< TR( "mtpoint:", PartitionInfo::mountPoint( partition ) ) << TR( "mtpoint:", PartitionInfo::mountPoint( partition ) ) << TR( "fs:", map[ "fs" ].toString() )
<< TR( "fs:", map[ "fs" ].toString() ) << TR( "fsName", map[ "fsName" ].toString() ) << TR( "uuid", uuid );
<< TR( "fsname", map[ "fsName" ].toString() )
<< TR( "uuid", uuid );
if ( partition->roles().has( PartitionRole::Luks ) ) if ( partition->roles().has( PartitionRole::Luks ) )
{ {
@ -137,7 +144,7 @@ FillGlobalStorageJob::prettyDescription() const
QStringList lines; QStringList lines;
const auto partitionList = createPartitionList().toList(); const auto partitionList = createPartitionList().toList();
for ( const QVariant &partitionItem : partitionList ) for ( const QVariant& partitionItem : partitionList )
{ {
if ( partitionItem.type() == QVariant::Map ) if ( partitionItem.type() == QVariant::Map )
{ {
@ -146,32 +153,42 @@ FillGlobalStorageJob::prettyDescription() const
QString mountPoint = partitionMap.value( "mountPoint" ).toString(); QString mountPoint = partitionMap.value( "mountPoint" ).toString();
QString fsType = partitionMap.value( "fs" ).toString(); QString fsType = partitionMap.value( "fs" ).toString();
if ( mountPoint.isEmpty() || fsType.isEmpty() ) if ( mountPoint.isEmpty() || fsType.isEmpty() )
{
continue; continue;
}
if ( path.isEmpty() ) if ( path.isEmpty() )
{ {
if ( mountPoint == "/" ) if ( mountPoint == "/" )
{
lines.append( tr( "Install %1 on <strong>new</strong> %2 system partition." ) lines.append( tr( "Install %1 on <strong>new</strong> %2 system partition." )
.arg( *Calamares::Branding::ShortProductName ) .arg( *Calamares::Branding::ShortProductName )
.arg( fsType ) ); .arg( fsType ) );
}
else else
{
lines.append( tr( "Set up <strong>new</strong> %2 partition with mount point " lines.append( tr( "Set up <strong>new</strong> %2 partition with mount point "
"<strong>%1</strong>." ) "<strong>%1</strong>." )
.arg( mountPoint ) .arg( mountPoint )
.arg( fsType ) ); .arg( fsType ) );
}
} }
else else
{ {
if ( mountPoint == "/" ) if ( mountPoint == "/" )
{
lines.append( tr( "Install %2 on %3 system partition <strong>%1</strong>." ) lines.append( tr( "Install %2 on %3 system partition <strong>%1</strong>." )
.arg( path ) .arg( path )
.arg( *Calamares::Branding::ShortProductName ) .arg( *Calamares::Branding::ShortProductName )
.arg( fsType ) ); .arg( fsType ) );
}
else else
{
lines.append( tr( "Set up %3 partition <strong>%1</strong> with mount point " lines.append( tr( "Set up %3 partition <strong>%1</strong> with mount point "
"<strong>%2</strong>." ) "<strong>%2</strong>." )
.arg( path ) .arg( path )
.arg( mountPoint ) .arg( mountPoint )
.arg( fsType ) ); .arg( fsType ) );
}
} }
} }
} }
@ -179,8 +196,7 @@ FillGlobalStorageJob::prettyDescription() const
QVariant bootloaderMap = createBootLoaderMap(); QVariant bootloaderMap = createBootLoaderMap();
if ( !m_bootLoaderPath.isEmpty() ) if ( !m_bootLoaderPath.isEmpty() )
{ {
lines.append( tr( "Install boot loader on <strong>%1</strong>." ) lines.append( tr( "Install boot loader on <strong>%1</strong>." ).arg( m_bootLoaderPath ) );
.arg( m_bootLoaderPath ) );
} }
return lines.join( "<br/>" ); return lines.join( "<br/>" );
} }
@ -201,7 +217,9 @@ FillGlobalStorageJob::exec()
{ {
QVariant var = createBootLoaderMap(); QVariant var = createBootLoaderMap();
if ( !var.isValid() ) if ( !var.isValid() )
{
cDebug() << "Failed to find path for boot loader"; cDebug() << "Failed to find path for boot loader";
}
cDebug() << "FillGlobalStorageJob writing bootLoader path:" << var; cDebug() << "FillGlobalStorageJob writing bootLoader path:" << var;
storage->insert( "bootLoader", var ); storage->insert( "bootLoader", var );
} }
@ -222,8 +240,7 @@ FillGlobalStorageJob::createPartitionList() const
for ( auto device : m_devices ) for ( auto device : m_devices )
{ {
cDebug() << Logger::SubEntry << "partitions on" << device->deviceNode(); cDebug() << Logger::SubEntry << "partitions on" << device->deviceNode();
for ( auto it = PartitionIterator::begin( device ); for ( auto it = PartitionIterator::begin( device ); it != PartitionIterator::end( device ); ++it )
it != PartitionIterator::end( device ); ++it )
{ {
// Debug-logging is done when creating the map // Debug-logging is done when creating the map
lst << mapForPartition( *it, hash.value( ( *it )->partitionPath() ) ); lst << mapForPartition( *it, hash.value( ( *it )->partitionPath() ) );
@ -241,7 +258,9 @@ FillGlobalStorageJob::createBootLoaderMap() const
{ {
Partition* partition = KPMHelpers::findPartitionByMountPoint( m_devices, path ); Partition* partition = KPMHelpers::findPartitionByMountPoint( m_devices, path );
if ( !partition ) if ( !partition )
{
return QVariant(); return QVariant();
}
path = partition->partitionPath(); path = partition->partitionPath();
} }
map[ "installPath" ] = path; map[ "installPath" ] = path;

View File

@ -19,6 +19,8 @@
#include "jobs/FormatPartitionJob.h" #include "jobs/FormatPartitionJob.h"
#include "core/KPMHelpers.h"
#include "utils/Logger.h" #include "utils/Logger.h"
// KPMcore // KPMcore
@ -29,6 +31,9 @@
#include <ops/createfilesystemoperation.h> #include <ops/createfilesystemoperation.h>
#include <util/report.h> #include <util/report.h>
using KPMHelpers::untranslatedFS;
using KPMHelpers::userVisibleFS;
FormatPartitionJob::FormatPartitionJob( Device* device, Partition* partition ) FormatPartitionJob::FormatPartitionJob( Device* device, Partition* partition )
: PartitionJob( partition ) : PartitionJob( partition )
, m_device( device ) , m_device( device )
@ -40,7 +45,7 @@ FormatPartitionJob::prettyName() const
{ {
return tr( "Format partition %1 (file system: %2, size: %3 MiB) on %4." ) return tr( "Format partition %1 (file system: %2, size: %3 MiB) on %4." )
.arg( m_partition->partitionPath() ) .arg( m_partition->partitionPath() )
.arg( m_partition->fileSystem().name() ) .arg( userVisibleFS( m_partition->fileSystem() ) )
.arg( m_partition->capacity() / 1024 / 1024 ) .arg( m_partition->capacity() / 1024 / 1024 )
.arg( m_device->name() ); .arg( m_device->name() );
} }
@ -52,7 +57,7 @@ FormatPartitionJob::prettyDescription() const
return tr( "Format <strong>%3MiB</strong> partition <strong>%1</strong> with " return tr( "Format <strong>%3MiB</strong> partition <strong>%1</strong> with "
"file system <strong>%2</strong>." ) "file system <strong>%2</strong>." )
.arg( m_partition->partitionPath() ) .arg( m_partition->partitionPath() )
.arg( m_partition->fileSystem().name() ) .arg( userVisibleFS( m_partition->fileSystem() ) )
.arg( m_partition->capacity() / 1024 / 1024 ); .arg( m_partition->capacity() / 1024 / 1024 );
} }
@ -63,7 +68,7 @@ FormatPartitionJob::prettyStatusMessage() const
return tr( "Formatting partition %1 with " return tr( "Formatting partition %1 with "
"file system %2." ) "file system %2." )
.arg( m_partition->partitionPath() ) .arg( m_partition->partitionPath() )
.arg( m_partition->fileSystem().name() ); .arg( userVisibleFS( m_partition->fileSystem() ) );
} }

View File

@ -21,6 +21,8 @@
#include "SetPartitionFlagsJob.h" #include "SetPartitionFlagsJob.h"
#include "core/KPMHelpers.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Units.h" #include "utils/Units.h"
@ -32,6 +34,8 @@
#include <util/report.h> #include <util/report.h>
using CalamaresUtils::BytesToMiB; using CalamaresUtils::BytesToMiB;
using KPMHelpers::untranslatedFS;
using KPMHelpers::userVisibleFS;
SetPartFlagsJob::SetPartFlagsJob( Device* device, SetPartFlagsJob::SetPartFlagsJob( Device* device,
Partition* partition, Partition* partition,
@ -48,10 +52,11 @@ SetPartFlagsJob::prettyName() const
if ( !partition()->partitionPath().isEmpty() ) if ( !partition()->partitionPath().isEmpty() )
return tr( "Set flags on partition %1." ).arg( partition()->partitionPath() ); return tr( "Set flags on partition %1." ).arg( partition()->partitionPath() );
if ( !partition()->fileSystem().name().isEmpty() ) QString fsNameForUser = userVisibleFS( partition()->fileSystem() );
if ( !fsNameForUser.isEmpty() )
return tr( "Set flags on %1MiB %2 partition." ) return tr( "Set flags on %1MiB %2 partition." )
.arg( BytesToMiB( partition()->capacity() ) ) .arg( BytesToMiB( partition()->capacity() ) )
.arg( partition()->fileSystem().name() ); .arg( fsNameForUser );
return tr( "Set flags on new partition." ); return tr( "Set flags on new partition." );
} }
@ -67,10 +72,11 @@ SetPartFlagsJob::prettyDescription() const
return tr( "Clear flags on partition <strong>%1</strong>." ) return tr( "Clear flags on partition <strong>%1</strong>." )
.arg( partition()->partitionPath() ); .arg( partition()->partitionPath() );
if ( !partition()->fileSystem().name().isEmpty() ) QString fsNameForUser = userVisibleFS( partition()->fileSystem() );
if ( !fsNameForUser.isEmpty() )
return tr( "Clear flags on %1MiB <strong>%2</strong> partition." ) return tr( "Clear flags on %1MiB <strong>%2</strong> partition." )
.arg( BytesToMiB( partition()->capacity() ) ) .arg( BytesToMiB( partition()->capacity() ) )
.arg( partition()->fileSystem().name() ); .arg( fsNameForUser );
return tr( "Clear flags on new partition." ); return tr( "Clear flags on new partition." );
} }
@ -81,11 +87,12 @@ SetPartFlagsJob::prettyDescription() const
.arg( partition()->partitionPath() ) .arg( partition()->partitionPath() )
.arg( flagsList.join( ", " ) ); .arg( flagsList.join( ", " ) );
if ( !partition()->fileSystem().name().isEmpty() ) QString fsNameForUser = userVisibleFS( partition()->fileSystem() );
if ( !fsNameForUser.isEmpty() )
return tr( "Flag %1MiB <strong>%2</strong> partition as " return tr( "Flag %1MiB <strong>%2</strong> partition as "
"<strong>%3</strong>." ) "<strong>%3</strong>." )
.arg( BytesToMiB( partition()->capacity() ) ) .arg( BytesToMiB( partition()->capacity() ) )
.arg( partition()->fileSystem().name() ) .arg( fsNameForUser )
.arg( flagsList.join( ", " ) ); .arg( flagsList.join( ", " ) );
return tr( "Flag new partition as <strong>%1</strong>." ) return tr( "Flag new partition as <strong>%1</strong>." )
@ -103,10 +110,11 @@ SetPartFlagsJob::prettyStatusMessage() const
return tr( "Clearing flags on partition <strong>%1</strong>." ) return tr( "Clearing flags on partition <strong>%1</strong>." )
.arg( partition()->partitionPath() ); .arg( partition()->partitionPath() );
if ( !partition()->fileSystem().name().isEmpty() ) QString fsNameForUser = userVisibleFS( partition()->fileSystem() );
if ( !fsNameForUser.isEmpty() )
return tr( "Clearing flags on %1MiB <strong>%2</strong> partition." ) return tr( "Clearing flags on %1MiB <strong>%2</strong> partition." )
.arg( BytesToMiB( partition()->capacity() ) ) .arg( BytesToMiB( partition()->capacity() ) )
.arg( partition()->fileSystem().name() ); .arg( fsNameForUser );
return tr( "Clearing flags on new partition." ); return tr( "Clearing flags on new partition." );
} }
@ -117,11 +125,12 @@ SetPartFlagsJob::prettyStatusMessage() const
.arg( partition()->partitionPath() ) .arg( partition()->partitionPath() )
.arg( flagsList.join( ", " ) ); .arg( flagsList.join( ", " ) );
if ( !partition()->fileSystem().name().isEmpty() ) QString fsNameForUser = userVisibleFS( partition()->fileSystem() );
if ( !fsNameForUser.isEmpty() )
return tr( "Setting flags <strong>%3</strong> on " return tr( "Setting flags <strong>%3</strong> on "
"%1MiB <strong>%2</strong> partition." ) "%1MiB <strong>%2</strong> partition." )
.arg( BytesToMiB( partition()->capacity() ) ) .arg( BytesToMiB( partition()->capacity() ) )
.arg( partition()->fileSystem().name() ) .arg( fsNameForUser )
.arg( flagsList.join( ", " ) ); .arg( flagsList.join( ", " ) );
return tr( "Setting flags <strong>%1</strong> on new partition." ) return tr( "Setting flags <strong>%1</strong> on new partition." )

View File

@ -176,7 +176,7 @@ script:
if ( !Calamares::JobQueue::instance() ) if ( !Calamares::JobQueue::instance() )
(void)new Calamares::JobQueue( nullptr ); (void)new Calamares::JobQueue( nullptr );
if ( !Calamares::Settings::instance() ) if ( !Calamares::Settings::instance() )
(void)new Calamares::Settings( QString(), true ); (void)Calamares::Settings::init( QString() );
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
QVERIFY( gs != nullptr ); QVERIFY( gs != nullptr );

View File

@ -23,13 +23,13 @@
#include "SummaryViewStep.h" #include "SummaryViewStep.h"
#include "Branding.h" #include "Branding.h"
#include "ExecutionViewStep.h"
#include "Settings.h" #include "Settings.h"
#include "ViewManager.h" #include "ViewManager.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Retranslator.h" #include "utils/Retranslator.h"
#include "viewpages/ExecutionViewStep.h"
#include <QBoxLayout> #include <QBoxLayout>
#include <QLabel> #include <QLabel>

View File

@ -40,3 +40,13 @@ calamares_add_plugin( welcome
Qt5::Network Qt5::Network
SHARED_LIB SHARED_LIB
) )
add_executable( welcomeqmltest qmlmain.cpp Config.cpp )
target_link_libraries( welcomeqmltest PRIVATE calamaresui Qt5::Core )
set_target_properties( welcomeqmltest
PROPERTIES
ENABLE_EXPORTS TRUE
RUNTIME_OUTPUT_NAME welcomeqmltest
)
calamares_automoc( welcomeqmltest )
calamares_autouic( welcomeqmltest )

View File

@ -0,0 +1,28 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Config.h"
Config::Config()
: m_helpUrl( "https://www.kde.org/" )
{
}
Config::~Config()
{
}

View File

@ -0,0 +1,40 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef WELCOME_CONFIG_H
#define WELCOME_CONFIG_H
#include <QObject>
#include <QUrl>
class Config : public QObject
{
Q_OBJECT
Q_PROPERTY( QUrl helpUrl READ helpUrl WRITE setHelpUrl CONSTANT )
public:
Config();
virtual ~Config();
QUrl helpUrl() const { return m_helpUrl; }
void setHelpUrl( const QUrl& url ) { m_helpUrl = url; }
private:
QUrl m_helpUrl;
};
#endif

View File

@ -0,0 +1,84 @@
/* Example executable showing a QML page and using the
* models from libcalamares for displaying a welcome.
*/
#include <memory>
#include <QApplication>
#include <QLabel>
#include <QMainWindow>
#include <QQmlEngine>
#include <QQuickWidget>
#include <QString>
#include <QTimer>
#include <QUrl>
#include <QVBoxLayout>
#include <QWidget>
#include <KAboutData>
#include "Branding.h"
#include "JobQueue.h"
#include "Settings.h"
#include "locale/LabelModel.h"
#include "utils/Logger.h"
#include "Config.h"
static Config* theConfig()
{
static Config* cnf = new Config();
return cnf;
}
int main(int argc, char **argv)
{
QApplication a( argc, argv );
KAboutData aboutData( "calamares",
"Calamares",
"0.1",
"Calamares QML Test Application",
KAboutLicense::GPL_V3,
QString(),
QString(),
"https://calamares.io",
"https://github.com/calamares/calamares/issues" );
KAboutData::setApplicationData( aboutData );
a.setApplicationDisplayName( QString() ); // To avoid putting an extra "Calamares/" into the log-file
Logger::setupLogLevel( Logger::LOGVERBOSE );
std::unique_ptr< Calamares::Settings > settings_p( Calamares::Settings::init( QString() ) );
std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) );
Calamares::Branding defaultBrand( "src/branding/default/branding.desc" );
cDebug() << "Branding @" << (void *)Calamares::Branding::instance();
QMainWindow mw;
QWidget background;
QVBoxLayout vl;
QLabel l( "Hello, world", &mw );
QQuickWidget qqw( &mw );
vl.addWidget( &qqw );
vl.addWidget( &l );
background.setLayout( &vl );
mw.setCentralWidget( &background );
mw.resize( QSize( 400, 400 ) );
mw.show();
Config cnf;
if ( argc > 1 )
{
cnf.setHelpUrl( QUrl( argv[1] ) );
}
// TODO: this should put the one config object in the context, rather than adding a factory function to share it everywhere
qmlRegisterSingletonType< Config >( "io.calamares.modules.welcome", 1, 0, "PotatoConfig", [](QQmlEngine*, QJSEngine*) -> QObject* { return theConfig(); });
qmlRegisterSingletonType< CalamaresUtils::Locale::LabelModel >( "io.calamares.locale", 1, 0, "LocaleModel", [](QQmlEngine*, QJSEngine*) -> QObject* { return CalamaresUtils::Locale::availableTranslations(); } );
qqw.setSource( QUrl::fromLocalFile("../src/modules/welcome/welcome.qml") );
return a.exec();
}

View File

@ -0,0 +1,29 @@
import QtQuick 2.0;
import QtQuick.Controls 2.3;
import io.calamares.modules.welcome 1.0;
import io.calamares.locale 1.0;
Rectangle {
width: 200;
height: 200;
color: "pink";
Label {
id: label;
anchors.centerIn: parent;
text: "Welcome to Calamares";
}
Button {
id: thebutton;
anchors.top: label.bottom;
text: PotatoConfig.helpUrl;
}
ListView {
anchors.fill: parent;
model: LocaleModel;
delegate: Label { text: display }
}
}

View File

@ -0,0 +1,44 @@
# This is a re-write of the welcome module using QML view steps
# instead of widgets.
set( _welcome ${CMAKE_CURRENT_SOURCE_DIR}/../welcome )
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ${_welcome} )
# DUPLICATED WITH WELCOME MODULE
find_package( Qt5 ${QT_VERSION} CONFIG REQUIRED DBus Network )
find_package( LIBPARTED )
if ( LIBPARTED_FOUND )
set( PARTMAN_SRC ${_welcome}/checker/partman_devices.c )
set( CHECKER_LINK_LIBRARIES ${LIBPARTED_LIBRARY} )
else()
set( PARTMAN_SRC )
set( CHECKER_LINK_LIBRARIES )
add_definitions( -DWITHOUT_LIBPARTED )
endif()
set( CHECKER_SOURCES
${_welcome}/checker/CheckerContainer.cpp
${_welcome}/checker/GeneralRequirements.cpp
${_welcome}/checker/ResultWidget.cpp
${_welcome}/checker/ResultsListWidget.cpp
${PARTMAN_SRC}
)
calamares_add_plugin( welcomeq
TYPE viewmodule
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
${CHECKER_SOURCES}
WelcomeQmlViewStep.cpp
Config.cpp
RESOURCES
welcomeq.qrc
LINK_PRIVATE_LIBRARIES
calamaresui
${CHECKER_LINK_LIBRARIES}
Qt5::DBus
Qt5::Network
SHARED_LIB
)

View File

@ -0,0 +1,28 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019-2020, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "Config.h"
Config::Config()
: m_helpUrl( "https://www.kde.org/" )
{
}
Config::~Config()
{
}

View File

@ -0,0 +1,40 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019-2020, Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef WELCOME_CONFIG_H
#define WELCOME_CONFIG_H
#include <QObject>
#include <QUrl>
class Config : public QObject
{
Q_OBJECT
Q_PROPERTY( QUrl helpUrl READ helpUrl WRITE setHelpUrl CONSTANT )
public:
Config();
virtual ~Config();
QUrl helpUrl() const { return m_helpUrl; }
void setHelpUrl( const QUrl& url ) { m_helpUrl = url; }
private:
QUrl m_helpUrl;
};
#endif

View File

@ -0,0 +1,243 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2018,2020 Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "WelcomeQmlViewStep.h"
#include "checker/GeneralRequirements.h"
#include "geoip/Handler.h"
#include "locale/LabelModel.h"
#include "locale/Lookup.h"
#include "utils/Logger.h"
#include "utils/Variant.h"
#include "Branding.h"
#include "modulesystem/ModuleManager.h"
#include <QFutureWatcher>
#include <QPixmap>
#include <QVariant>
CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeQmlViewStepFactory, registerPlugin< WelcomeQmlViewStep >(); )
WelcomeQmlViewStep::WelcomeQmlViewStep( QObject* parent )
: Calamares::ViewStep( parent )
, m_requirementsChecker( new GeneralRequirements( this ) )
{
connect( Calamares::ModuleManager::instance(),
&Calamares::ModuleManager::requirementsComplete,
this,
&WelcomeQmlViewStep::nextStatusChanged );
}
WelcomeQmlViewStep::~WelcomeQmlViewStep()
{
}
QString
WelcomeQmlViewStep::prettyName() const
{
return tr( "Welcome" );
}
QWidget*
WelcomeQmlViewStep::widget()
{
return nullptr;
}
bool
WelcomeQmlViewStep::isNextEnabled() const
{
// TODO: should return true
return false;
}
bool
WelcomeQmlViewStep::isBackEnabled() const
{
// 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;
}
bool
WelcomeQmlViewStep::isAtEnd() const
{
// TODO: adjust to "pages" in the QML
return true;
}
Calamares::JobList
WelcomeQmlViewStep::jobs() const
{
return Calamares::JobList();
}
/** @brief Look up a URL for a button
*
* Looks up @p key in @p map; if it is a *boolean* value, then
* assume an old-style configuration, and fetch the string from
* the branding settings @p e. If it is a string, not a boolean,
* use it as-is. If not found, or a weird type, returns empty.
*
* This allows switching the showKnownIssuesUrl and similar settings
* in welcome.conf from a boolean (deferring to branding) to an
* actual string for immediate use. Empty strings, as well as
* "false" as a setting, will hide the buttons as before.
*/
static QString
jobOrBrandingSetting( Calamares::Branding::StringEntry e, const QVariantMap& map, const QString& key )
{
if ( !map.contains( key ) )
{
return QString();
}
auto v = map.value( key );
if ( v.type() == QVariant::Bool )
{
return v.toBool() ? ( *e ) : QString();
}
if ( v.type() == QVariant::String )
{
return v.toString();
}
return QString();
}
void
WelcomeQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{
using Calamares::Branding;
m_config.setHelpUrl( jobOrBrandingSetting( Branding::SupportUrl, configurationMap, "showSupportUrl" ) );
// TODO: expand Config class and set the remaining fields
// TODO: figure out how the requirements (held by ModuleManager) should be accessible
// to QML as a odel.
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.";
bool ok = false;
QVariantMap geoip = CalamaresUtils::getSubMap( configurationMap, "geoip", ok );
if ( ok )
{
using FWString = QFutureWatcher< QString >;
auto* handler = new CalamaresUtils::GeoIP::Handler( CalamaresUtils::getString( geoip, "style" ),
CalamaresUtils::getString( geoip, "url" ),
CalamaresUtils::getString( geoip, "selector" ) );
if ( handler->type() != CalamaresUtils::GeoIP::Handler::Type::None )
{
auto* future = new FWString();
connect( future, &FWString::finished, [view = this, f = future, h = handler]() {
QString countryResult = f->future().result();
cDebug() << "GeoIP result for welcome=" << countryResult;
view->setCountry( countryResult, h );
f->deleteLater();
delete h;
} );
future->setFuture( handler->queryRaw() );
}
else
{
// Would not produce useful country code anyway.
delete handler;
}
}
QString language = CalamaresUtils::getString( configurationMap, "languageIcon" );
if ( !language.isEmpty() )
{
auto icon = Calamares::Branding::instance()->image( language, QSize( 48, 48 ) );
if ( !icon.isNull() )
{
// TODO: figure out where to set this: Config?
}
}
}
Calamares::RequirementsList
WelcomeQmlViewStep::checkRequirements()
{
return m_requirementsChecker->checkRequirements();
}
static inline void
logGeoIPHandler( CalamaresUtils::GeoIP::Handler* handler )
{
if ( handler )
{
cDebug() << Logger::SubEntry << "Obtained from" << handler->url() << " ("
<< static_cast< int >( handler->type() ) << handler->selector() << ')';
}
}
void
WelcomeQmlViewStep::setCountry( const QString& countryCode, CalamaresUtils::GeoIP::Handler* handler )
{
if ( countryCode.length() != 2 )
{
cDebug() << "Unusable country code" << countryCode;
logGeoIPHandler( handler );
return;
}
auto c_l = CalamaresUtils::Locale::countryData( countryCode );
if ( c_l.first == QLocale::Country::AnyCountry )
{
cDebug() << "Unusable country code" << countryCode;
logGeoIPHandler( handler );
return;
}
else
{
int r = CalamaresUtils::Locale::availableTranslations()->find( countryCode );
if ( r < 0 )
{
cDebug() << "Unusable country code" << countryCode << "(no suitable translation)";
}
if ( ( r >= 0 ) )
{
// TODO: update Config to point to selected language
}
}
}

View File

@ -0,0 +1,95 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2019-2020 Adriaan de Groot <groot@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef WELCOME_QMLVIEWSTEP_H
#define WELCOME_QMLVIEWSTEP_H
#include "Config.h"
#include "modulesystem/Requirement.h"
#include "utils/PluginFactory.h"
#include "viewpages/ViewStep.h"
#include <PluginDllMacro.h>
#include <QObject>
#include <QVariantMap>
namespace CalamaresUtils
{
namespace GeoIP
{
class Handler;
}
} // namespace CalamaresUtils
class GeneralRequirements;
class QQmlComponent;
class QQuickItem;
class QQuickWidget;
// TODO: Needs a generic Calamares::QmlViewStep as base class
// TODO: refactor and move what makes sense to base class
class PLUGINDLLEXPORT WelcomeQmlViewStep : public Calamares::ViewStep
{
Q_OBJECT
public:
explicit WelcomeQmlViewStep( QObject* parent = nullptr );
virtual ~WelcomeQmlViewStep() override;
QString prettyName() const override;
QWidget* widget() override;
bool isNextEnabled() const override;
bool isBackEnabled() const override;
bool isAtBeginning() const override;
bool isAtEnd() const override;
Calamares::JobList jobs() const override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
/** @brief Sets the country that Calamares is running in.
*
* This (ideally) sets up language and locale settings that are right for
* the given 2-letter country code. Uses the handler's information (if
* given) for error reporting.
*/
void setCountry( const QString&, CalamaresUtils::GeoIP::Handler* handler );
Calamares::RequirementsList checkRequirements() override;
private:
// TODO: a generic QML viewstep should return a config object from a method
Config m_config;
GeneralRequirements* m_requirementsChecker;
// TODO: these need to be in the base class (also a base class of ExecutionViewStep)
QQuickWidget* m_qmlWidget;
QQmlComponent* m_qmlComponent;
QQuickItem* m_qmlItem;
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( WelcomeQmlViewStepFactory )
#endif // WELCOME_QMLVIEWSTEP_H