Compare commits
139 Commits
v1.1.2
...
old-module
| Author | SHA1 | Date | |
|---|---|---|---|
| 379f38bfe9 | |||
| 25acdeceba | |||
| 5462411d8a | |||
| b7f606cba1 | |||
| d51ba1e8df | |||
| 10dc285ed2 | |||
| 916f1c2fae | |||
| 0d9923ed0b | |||
| 8947b568a7 | |||
| 3dc5e111bb | |||
| c6e2cacd51 | |||
| 3d3e73f015 | |||
| fe012233e3 | |||
| e55d467f12 | |||
| c99c53714f | |||
| 9e10e21381 | |||
| c6884e1044 | |||
| fc2b4c54a5 | |||
| c04875fb6a | |||
| bac0c002d8 | |||
| 999e45c64a | |||
| a1012b9a82 | |||
| 39427ffc4c | |||
|
|
6bd75570de | ||
|
|
acdcdea668 | ||
|
|
edb405a4d1 | ||
|
|
3ad9c221d4 | ||
|
|
dc3550eccd | ||
|
|
fac16ac6a7 | ||
|
|
a442ed8c12 | ||
|
|
e08d687061 | ||
|
|
15f6369537 | ||
|
|
f01b4ed2f8 | ||
|
|
ea762b0945 | ||
|
|
cae8acb4a4 | ||
|
|
ae204d0108 | ||
|
|
a2fae600c4 | ||
|
|
349acad491 | ||
|
|
9b4c4876bc | ||
|
|
cc02baed9a | ||
|
|
dfab089938 | ||
|
|
2dd9a7ba8a | ||
|
|
82f31f3cd9 | ||
|
|
c5b01a574d | ||
|
|
bc4789d57f | ||
|
|
0962b98494 | ||
|
|
108476c025 | ||
|
|
04a1bc9e2c | ||
|
|
bff5e485f4 | ||
|
|
3c838436c2 | ||
|
|
644c9cf4f3 | ||
|
|
dcaa378ddd | ||
|
|
14fd23dcef | ||
|
|
f4bc7052e0 | ||
|
|
4f0f48d99d | ||
|
|
1344880f2e | ||
|
|
5704e146a0 | ||
|
|
85eb434b57 | ||
|
|
4b2ea61aa3 | ||
|
|
39d25eef1c | ||
|
|
e82d32fe66 | ||
|
|
a50ab49c22 | ||
|
|
a66ab99ce8 | ||
|
|
c3170a9dfb | ||
|
|
88437d3612 | ||
|
|
6db52a904e | ||
|
|
8f0403a3f8 | ||
|
|
caf231b0d1 | ||
|
|
9ad86f81bb | ||
|
|
4d601f2e6a | ||
|
|
69f68d82e6 | ||
|
|
572a94e493 | ||
|
|
90454be1b9 | ||
|
|
6144404bd0 | ||
|
|
8f4d8d119c | ||
|
|
e8c870205d | ||
|
|
081d7d47d1 | ||
|
|
e92ecea3f5 | ||
|
|
e158402478 | ||
|
|
d242d077db | ||
|
|
5f9b46a820 | ||
|
|
9151d0fcee | ||
|
|
282f5bfade | ||
|
|
eeb264f32e | ||
|
|
83606aaf9d | ||
|
|
322a7a212f | ||
|
|
40c7496f85 | ||
|
|
f1fd52e790 | ||
|
|
12f6068622 | ||
|
|
16a3e2edb2 | ||
|
|
8fc9b907af | ||
|
|
ecaf2c3076 | ||
|
|
ea97927997 | ||
|
|
6795190216 | ||
|
|
51149e34d7 | ||
|
|
a2674c652d | ||
|
|
d4d6d17efe | ||
|
|
b74d77a9c5 | ||
|
|
5074bebd32 | ||
|
|
76be9988fe | ||
|
|
c85daf8f7b | ||
|
|
13e8b1e9b5 | ||
|
|
e6ddf30512 | ||
|
|
9938d11ad1 | ||
|
|
def4ee5c7e | ||
|
|
718f73c9c8 | ||
|
|
720415d8b7 | ||
|
|
0f0b9aa776 | ||
|
|
19d508ca2e | ||
|
|
7af1aeb132 | ||
|
|
3f7cabe832 | ||
|
|
341c9f4a7f | ||
|
|
03260efb3a | ||
|
|
18060db82d | ||
|
|
b978f03618 | ||
|
|
a4a6194a5d | ||
|
|
93cf06da82 | ||
|
|
901211c12d | ||
|
|
e89a58a34b | ||
|
|
fb36765982 | ||
|
|
f1d2bfacce | ||
|
|
9703bd9058 | ||
|
|
0e2a178436 | ||
|
|
fb70e29e29 | ||
|
|
fbfa9d8038 | ||
|
|
59ab728502 | ||
|
|
476224d34e | ||
|
|
2aaf440fec | ||
|
|
b416caa462 | ||
|
|
0c11b864e5 | ||
|
|
0f9ffb9e35 | ||
|
|
813d26ec4e | ||
|
|
5d44118b4b | ||
|
|
833e33f011 | ||
|
|
ea3a03a8cc | ||
|
|
05bbeae2c3 | ||
|
|
b9b923e69c | ||
|
|
809491c969 | ||
|
|
febeb3281e |
@@ -8,6 +8,7 @@ AlignEscapedNewlines: DontAlign
|
|||||||
AllowAllParametersOfDeclarationOnNextLine: "false"
|
AllowAllParametersOfDeclarationOnNextLine: "false"
|
||||||
AllowShortFunctionsOnASingleLine: Inline
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
AllowShortIfStatementsOnASingleLine: "false"
|
AllowShortIfStatementsOnASingleLine: "false"
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
AllowShortLoopsOnASingleLine: "false"
|
AllowShortLoopsOnASingleLine: "false"
|
||||||
AlwaysBreakAfterReturnType: TopLevelDefinitions
|
AlwaysBreakAfterReturnType: TopLevelDefinitions
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
@@ -28,7 +29,6 @@ ReflowComments: "false"
|
|||||||
SortIncludes: "true"
|
SortIncludes: "true"
|
||||||
SpaceAfterCStyleCast: "false"
|
SpaceAfterCStyleCast: "false"
|
||||||
SpacesBeforeTrailingComments: "2"
|
SpacesBeforeTrailingComments: "2"
|
||||||
# SpaceInEmptyBlock: "true"
|
|
||||||
SpacesInAngles: "true"
|
SpacesInAngles: "true"
|
||||||
SpacesInParentheses: "true"
|
SpacesInParentheses: "true"
|
||||||
SpacesInSquareBrackets: "true"
|
SpacesInSquareBrackets: "true"
|
||||||
|
|||||||
35
.clang-format.base
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# SPDX-FileCopyrightText: no
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
---
|
||||||
|
BasedOnStyle: WebKit
|
||||||
|
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignEscapedNewlines: DontAlign
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: "false"
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortIfStatementsOnASingleLine: "false"
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: "false"
|
||||||
|
AlwaysBreakAfterReturnType: TopLevelDefinitions
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BinPackArguments: "false"
|
||||||
|
BinPackParameters: "false"
|
||||||
|
BreakBeforeBraces: Allman
|
||||||
|
BreakBeforeTernaryOperators: "true"
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
ColumnLimit: 120
|
||||||
|
Cpp11BracedListStyle: "false"
|
||||||
|
FixNamespaceComments: "true"
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IndentWidth: "4"
|
||||||
|
MaxEmptyLinesToKeep: "2"
|
||||||
|
NamespaceIndentation: None
|
||||||
|
PointerAlignment: Left
|
||||||
|
ReflowComments: "false"
|
||||||
|
SortIncludes: "true"
|
||||||
|
SpaceAfterCStyleCast: "false"
|
||||||
|
SpacesBeforeTrailingComments: "2"
|
||||||
|
SpacesInAngles: "true"
|
||||||
|
SpacesInParentheses: "true"
|
||||||
|
SpacesInSquareBrackets: "true"
|
||||||
|
Standard: Cpp11
|
||||||
74
.github/workflows/nightly-neon.yml
vendored
@@ -31,70 +31,30 @@ jobs:
|
|||||||
path: ${{ env.BUILDDIR }}
|
path: ${{ env.BUILDDIR }}
|
||||||
repo: calamares/calamares
|
repo: calamares/calamares
|
||||||
- name: "prepare env"
|
- name: "prepare env"
|
||||||
run: |
|
uses: calamares/actions/prepare-neon@v2
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get -y install git-core
|
|
||||||
sudo apt-get -y install \
|
|
||||||
build-essential \
|
|
||||||
cmake \
|
|
||||||
extra-cmake-modules \
|
|
||||||
gettext \
|
|
||||||
kio-dev \
|
|
||||||
libatasmart-dev \
|
|
||||||
libboost-python-dev \
|
|
||||||
libkf5config-dev \
|
|
||||||
libkf5coreaddons-dev \
|
|
||||||
libkf5i18n-dev \
|
|
||||||
libkf5iconthemes-dev \
|
|
||||||
libkf5parts-dev \
|
|
||||||
libkf5service-dev \
|
|
||||||
libkf5solid-dev \
|
|
||||||
libkpmcore-dev \
|
|
||||||
libparted-dev \
|
|
||||||
libpolkit-qt5-1-dev \
|
|
||||||
libqt5svg5-dev \
|
|
||||||
libqt5webkit5-dev \
|
|
||||||
libyaml-cpp-dev \
|
|
||||||
os-prober \
|
|
||||||
pkg-config \
|
|
||||||
python3-dev \
|
|
||||||
qtbase5-dev \
|
|
||||||
qtdeclarative5-dev \
|
|
||||||
qttools5-dev \
|
|
||||||
qttools5-dev-tools
|
|
||||||
- name: "prepare source"
|
- name: "prepare source"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: "prepare artifacts"
|
- name: "prepare artifacts"
|
||||||
run: tar xvzf "$BUILDDIR/calamares.tar.gz" -C / --strip-components 1
|
run: tar xvzf "$BUILDDIR/calamares.tar.gz" -C / --strip-components 1
|
||||||
- name: "prepare build"
|
- name: "build"
|
||||||
id: pre_build
|
id: build
|
||||||
run: |
|
uses: calamares/actions/generic-build@v2
|
||||||
test -n "$BUILDDIR" || { echo "! \$BUILDDIR not set" ; exit 1 ; }
|
|
||||||
mkdir -p $BUILDDIR
|
|
||||||
test -f $SRCDIR/CMakeLists.txt || { echo "! Missing $SRCDIR/CMakeLists.txt" ; exit 1 ; }
|
|
||||||
echo "::set-output name=message::"`git log -1 --abbrev-commit --pretty=oneline --no-decorate ${{ github.event.head_commit.id }}`
|
|
||||||
- name: "Calamares-Extensions: cmake"
|
|
||||||
working-directory: ${{ env.BUILDDIR }}
|
|
||||||
run: cmake $CMAKE_ARGS $SRCDIR
|
|
||||||
- name: "Calamares-Extensions: make"
|
|
||||||
working-directory: ${{ env.BUILDDIR }}
|
|
||||||
run: make -j2 VERBOSE=1
|
|
||||||
- name: "Calamares-Extensions: install"
|
|
||||||
working-directory: ${{ env.BUILDDIR }}
|
|
||||||
run: make install VERBOSE=1
|
|
||||||
- name: "notify: ok"
|
- name: "notify: ok"
|
||||||
uses: rectalogic/notify-irc@v1
|
|
||||||
if: ${{ success() && github.repository == 'calamares/calamares-extensions' }}
|
if: ${{ success() && github.repository == 'calamares/calamares-extensions' }}
|
||||||
|
uses: calamares/actions/matrix-notify@v2
|
||||||
with:
|
with:
|
||||||
server: chat.freenode.net
|
token: ${{ secrets.MATRIX_TOKEN }}
|
||||||
nickname: cala-ci
|
room: ${{ secrets.MATRIX_ROOM }}
|
||||||
channel: "#calamares"
|
message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ steps.build.outputs.git_summary }}"
|
||||||
message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"
|
|
||||||
- name: "notify: fail"
|
- name: "notify: fail"
|
||||||
uses: rectalogic/notify-irc@v1
|
|
||||||
if: ${{ failure() && github.repository == 'calamares/calamares' }}
|
if: ${{ failure() && github.repository == 'calamares/calamares' }}
|
||||||
|
uses: calamares/actions/matrix-notify@v2
|
||||||
with:
|
with:
|
||||||
server: chat.freenode.net
|
token: ${{ secrets.MATRIX_TOKEN }}
|
||||||
nickname: cala-ci
|
room: ${{ secrets.MATRIX_ROOM }}
|
||||||
channel: "#calamares"
|
message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ steps.build.outputs.git_summary}}"
|
||||||
message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ steps.pre_build.outputs.message }}"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
76
.github/workflows/push.yml
vendored
@@ -37,70 +37,30 @@ jobs:
|
|||||||
path: ${{ env.BUILDDIR }}
|
path: ${{ env.BUILDDIR }}
|
||||||
repo: calamares/calamares
|
repo: calamares/calamares
|
||||||
- name: "prepare env"
|
- name: "prepare env"
|
||||||
run: |
|
uses: calamares/actions/prepare-neon@v2
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get -y install git-core
|
|
||||||
sudo apt-get -y install \
|
|
||||||
build-essential \
|
|
||||||
cmake \
|
|
||||||
extra-cmake-modules \
|
|
||||||
gettext \
|
|
||||||
kio-dev \
|
|
||||||
libatasmart-dev \
|
|
||||||
libboost-python-dev \
|
|
||||||
libkf5config-dev \
|
|
||||||
libkf5coreaddons-dev \
|
|
||||||
libkf5i18n-dev \
|
|
||||||
libkf5iconthemes-dev \
|
|
||||||
libkf5parts-dev \
|
|
||||||
libkf5service-dev \
|
|
||||||
libkf5solid-dev \
|
|
||||||
libkpmcore-dev \
|
|
||||||
libparted-dev \
|
|
||||||
libpolkit-qt5-1-dev \
|
|
||||||
libqt5svg5-dev \
|
|
||||||
libqt5webkit5-dev \
|
|
||||||
libyaml-cpp-dev \
|
|
||||||
os-prober \
|
|
||||||
pkg-config \
|
|
||||||
python3-dev \
|
|
||||||
qtbase5-dev \
|
|
||||||
qtdeclarative5-dev \
|
|
||||||
qttools5-dev \
|
|
||||||
qttools5-dev-tools
|
|
||||||
- name: "prepare source"
|
- name: "prepare source"
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: "prepare artifacts"
|
- name: "prepare artifacts"
|
||||||
run: tar xvzf "$BUILDDIR/calamares.tar.gz" -C / --strip-components 1
|
run: tar xvzf "$BUILDDIR/calamares.tar.gz" -C / --strip-components 1
|
||||||
- name: "prepare build"
|
- name: "build"
|
||||||
id: pre_build
|
id: build
|
||||||
run: |
|
uses: calamares/actions/generic-build@v2
|
||||||
test -n "$BUILDDIR" || { echo "! \$BUILDDIR not set" ; exit 1 ; }
|
|
||||||
mkdir -p $BUILDDIR
|
|
||||||
test -f $SRCDIR/CMakeLists.txt || { echo "! Missing $SRCDIR/CMakeLists.txt" ; exit 1 ; }
|
|
||||||
echo "::set-output name=message::"`git log -1 --abbrev-commit --pretty=oneline --no-decorate ${{ github.event.head_commit.id }}`
|
|
||||||
- name: "Calamares-Extensions: cmake"
|
|
||||||
working-directory: ${{ env.BUILDDIR }}
|
|
||||||
run: cmake $CMAKE_ARGS $SRCDIR
|
|
||||||
- name: "Calamares-Extensions: make"
|
|
||||||
working-directory: ${{ env.BUILDDIR }}
|
|
||||||
run: make -j2 VERBOSE=1
|
|
||||||
- name: "Calamares-Extensions: install"
|
|
||||||
working-directory: ${{ env.BUILDDIR }}
|
|
||||||
run: make install VERBOSE=1
|
|
||||||
- name: "notify: ok"
|
- name: "notify: ok"
|
||||||
uses: rectalogic/notify-irc@v1
|
|
||||||
if: ${{ success() && github.repository == 'calamares/calamares-extensions' }}
|
if: ${{ success() && github.repository == 'calamares/calamares-extensions' }}
|
||||||
|
uses: calamares/actions/matrix-notify@v2
|
||||||
with:
|
with:
|
||||||
server: chat.freenode.net
|
token: ${{ secrets.MATRIX_TOKEN }}
|
||||||
nickname: cala-ci
|
room: ${{ secrets.MATRIX_ROOM }}
|
||||||
channel: "#calamares"
|
message: |
|
||||||
message: "OK ${{ github.workflow }} in ${{ github.repository }} ${{ github.actor }} on ${{ github.event.ref }}\n.. ${{ steps.pre_build.outputs.message }}"
|
OK ${{ github.workflow }} in ${{ github.repository }} by ${{ github.actor }} on ${{ github.event.ref }}
|
||||||
|
.. ${{ steps.build.outputs.git-summary }}
|
||||||
- name: "notify: fail"
|
- name: "notify: fail"
|
||||||
uses: rectalogic/notify-irc@v1
|
if: ${{ failure() && github.repository == 'calamares/calamares-extensions' }}
|
||||||
if: ${{ failure() && github.repository == 'calamares/calamares' }}
|
uses: calamares/actions/matrix-notify@v2
|
||||||
with:
|
with:
|
||||||
server: chat.freenode.net
|
token: ${{ secrets.MATRIX_TOKEN }}
|
||||||
nickname: cala-ci
|
room: ${{ secrets.MATRIX_ROOM }}
|
||||||
channel: "#calamares"
|
message: |
|
||||||
message: "FAIL ${{ github.workflow }} in ${{ github.repository }} ${{ github.actor }} on ${{ github.event.ref }}\n.. ${{ steps.pre_build.outputs.message }}\n.. DIFF ${{ github.event.compare }}"
|
FAIL ${{ github.workflow }} in ${{ github.repository }} by ${{ github.actor }} on ${{ github.event.ref }}
|
||||||
|
.. ${{ steps.build.outputs.git-summary }}
|
||||||
|
.. ${{ github.event.compare }}
|
||||||
|
|||||||
3
.gitignore
vendored
@@ -1,3 +1,6 @@
|
|||||||
|
# SPDX-FileCopyrightText: no
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
#
|
||||||
.kdev4/
|
.kdev4/
|
||||||
build/
|
build/
|
||||||
*.kdev4
|
*.kdev4
|
||||||
|
|||||||
23
.reuse/dep5
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Upstream-Name: Calamares-Extensions
|
||||||
|
Source: https://github.com/calamares/calamares-extensions.git
|
||||||
|
|
||||||
|
### BUILD ARTIFACTS / NOT SOURCE
|
||||||
|
#
|
||||||
|
# QRC Files are basically build artifacts
|
||||||
|
#
|
||||||
|
FILES: modules/*/*.qrc
|
||||||
|
License: CC0-1.0
|
||||||
|
Copyright: no
|
||||||
|
|
||||||
|
# GitHub issue templates are not part of the source
|
||||||
|
#
|
||||||
|
Files: .github/ISSUE_TEMPLATE/*
|
||||||
|
License: CC0-1.0
|
||||||
|
Copyright: no
|
||||||
|
|
||||||
|
# GitHub actions are not part of the source
|
||||||
|
Files: .github/workflows/*.yml
|
||||||
|
License: CC0-1.0
|
||||||
|
Copyright: no
|
||||||
|
|
||||||
43
CHANGES
@@ -6,6 +6,49 @@ This is the changelog for Calamares-Extensions. For each release, the major
|
|||||||
changes and contributors are listed. Note that Calamares-Extensions does not
|
changes and contributors are listed. Note that Calamares-Extensions does not
|
||||||
have a historical changelog -- this log starts with version 1.0.0.
|
have a historical changelog -- this log starts with version 1.0.0.
|
||||||
|
|
||||||
|
# 1.3.2 (2023-08-28)
|
||||||
|
|
||||||
|
We skipped a couple of releases in the release-notes, then tagged
|
||||||
|
1.3.1 without a version bump or release-notes. So 1.3.2 brings us
|
||||||
|
back to "regular releases".
|
||||||
|
|
||||||
|
This release contains contributions from (alphabetically by first name):
|
||||||
|
- Anke Boersma
|
||||||
|
- Nathan Schulte
|
||||||
|
- Oliver Smith
|
||||||
|
- stravanpannala
|
||||||
|
- undef
|
||||||
|
|
||||||
|
Changes and new modules in this release:
|
||||||
|
- *mobile* Has new configuration options. (Thanks Nathan, Oliver)
|
||||||
|
- *unpackfsc* Uses a more portable invocation of tar. (Thanks sravanpannala)
|
||||||
|
|
||||||
|
|
||||||
|
# 1.2.1 (2021-11-16)
|
||||||
|
|
||||||
|
The 1.2.0 release had no release-notes for that version, and failed to
|
||||||
|
credit Anke and Otus.
|
||||||
|
|
||||||
|
Changes and new modules in this release:
|
||||||
|
- *unpackfsc* can use `fsarchiver` and unpack that, instead of squashfs;
|
||||||
|
a distro might choose one tool or the other. Currently, only *savedir* /
|
||||||
|
*restdir* mode (i.e. directories, not block-devices) are supported.
|
||||||
|
|
||||||
|
# 1.2.0 (2021-11-16)
|
||||||
|
|
||||||
|
This release contains contributions from (alphabetically by first name):
|
||||||
|
- Anke Boersma
|
||||||
|
- Otus9051
|
||||||
|
|
||||||
|
Changes and new modules in this release:
|
||||||
|
- *refind* is a new module that installs the rEFInd bootloader. It can
|
||||||
|
be used instead of the *bootloader* module from core Calamares. (Thanks Anke)
|
||||||
|
- *unpackfsc* is a new module that uses `unsquashfs` directly. This may
|
||||||
|
be faster or more convenient than the *unpackfs* module from core Calamares.
|
||||||
|
The configuration file supports only one entry, but is otherwise easy to
|
||||||
|
adapt from an existing `unpackfs.conf`.
|
||||||
|
|
||||||
|
|
||||||
# 1.1.2 (2021-05-14)
|
# 1.1.2 (2021-05-14)
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
This release contains contributions from (alphabetically by first name):
|
||||||
|
|||||||
125
CMakeLists.txt
@@ -1,20 +1,15 @@
|
|||||||
# === This file is part of Calamares - <https://github.com/calamares> ===
|
# === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
#
|
#
|
||||||
# Calamares is free software: you can redistribute it and/or modify
|
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
# it under the terms of the GNU General Public License as published by
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
# 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
|
# Calamares-Examples is Free Software: see the License-Identifier above.
|
||||||
# along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: GPL-3.0+
|
# Individual files may have different licenses (like the CMake
|
||||||
# License-Filename: LICENSE
|
# infrastructure, which is BSD-2-Clause licensed). Check the SPDX
|
||||||
|
# identifiers in each file.
|
||||||
#
|
#
|
||||||
###
|
###
|
||||||
#
|
#
|
||||||
@@ -36,22 +31,67 @@
|
|||||||
# USE_* : fills in SKIP_MODULES for modules called *-<something>
|
# USE_* : fills in SKIP_MODULES for modules called *-<something>
|
||||||
# In this repository, there is just one "group" to which USE_* applies:
|
# In this repository, there is just one "group" to which USE_* applies:
|
||||||
# USE_os : operating-system-specific modules.
|
# USE_os : operating-system-specific modules.
|
||||||
cmake_minimum_required(VERSION 3.3 FATAL_ERROR)
|
#
|
||||||
|
### NOTES
|
||||||
|
#
|
||||||
|
# Call this CMake file in script mode, e.g. `cmake -P CMakeLists.txt`
|
||||||
|
# to print out version information. Use `cmake -DVERSION_STYLE=short`
|
||||||
|
# to get just the short versioning.
|
||||||
|
#
|
||||||
|
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
|
||||||
|
|
||||||
|
set( CALAMARES_EXTENSIONS_VERSION 1.4.0 )
|
||||||
|
|
||||||
|
include( ${CMAKE_CURRENT_LIST_DIR}/CMakeModules/ExtendedVersion.cmake )
|
||||||
|
if ( CMAKE_SCRIPT_MODE_FILE )
|
||||||
|
report_version( ${CALAMARES_EXTENSIONS_VERSION} ${CMAKE_CURRENT_LIST_DIR} )
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
project(calamares-extensions
|
project(calamares-extensions
|
||||||
VERSION 1.1.2
|
VERSION ${CALAMARES_EXTENSIONS_VERSION}
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set( CMAKE_CXX_STANDARD 17 )
|
||||||
|
set( CMAKE_CXX_STANDARD_REQUIRED ON )
|
||||||
|
|
||||||
|
|
||||||
|
if(WITH_QT6)
|
||||||
|
set(kfname "KF6")
|
||||||
|
set(KF_VERSION 5.240) # KDE Neon weirdness
|
||||||
|
else()
|
||||||
|
message(STATUS "Building Calamares with Qt5")
|
||||||
|
set(kfname "KF5")
|
||||||
|
set(KF_VERSION 5.78)
|
||||||
|
# API that was deprecated before Qt 5.15 causes a compile error
|
||||||
|
add_compile_definitions(QT_DISABLE_DEPRECATED_BEFORE=0x050f00)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include( FeatureSummary )
|
||||||
|
find_package(${kfname}CoreAddons ${KF_VERSION} QUIET)
|
||||||
|
set_package_properties(
|
||||||
|
${kfname}CoreAddons
|
||||||
|
PROPERTIES
|
||||||
|
TYPE REQUIRED
|
||||||
|
DESCRIPTION "KDE Framework CoreAddons"
|
||||||
|
URL "https://api.kde.org/frameworks/"
|
||||||
|
PURPOSE "Essential Framework for AboutData and Macros"
|
||||||
|
)
|
||||||
|
|
||||||
# On developer's machine, the user package registry breaks
|
# On developer's machine, the user package registry breaks
|
||||||
# consumers by loading the developer's config from a build
|
# consumers by loading the developer's config from a build
|
||||||
# directory (which doesn't have the rest of the config
|
# directory (which doesn't have the rest of the config
|
||||||
# installed inside it).
|
# installed inside it).
|
||||||
find_package(Calamares 3.2.26 REQUIRED NO_CMAKE_PACKAGE_REGISTRY)
|
set( CALAMARES_VERSION_REQUIRED 3.3.0 )
|
||||||
|
find_package(Calamares ${CALAMARES_VERSION_REQUIRED} NO_CMAKE_PACKAGE_REGISTRY)
|
||||||
if (NOT TARGET Calamares::calamares OR NOT TARGET Calamares::calamaresui)
|
if (NOT TARGET Calamares::calamares OR NOT TARGET Calamares::calamaresui)
|
||||||
message(FATAL_ERROR "Calamares found with missing CMake targets")
|
find_package(Calamares ${CALAMARES_VERSION_REQUIRED} REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(YAMLCPP REQUIRED) # Needed to untangle some dependencies before Calamares 3.2.36
|
message(STATUS "Found Calamares version ${Calamares_VERSION}")
|
||||||
|
message(STATUS " libraries ${Calamares_LIB_DIRS}")
|
||||||
|
message(STATUS "")
|
||||||
|
|
||||||
### CMAKE SETUP
|
### CMAKE SETUP
|
||||||
#
|
#
|
||||||
@@ -71,6 +111,7 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.10.0")
|
|||||||
"K_EXPORT_PLASMA_RUNNER"
|
"K_EXPORT_PLASMA_RUNNER"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
include( CTest )
|
||||||
|
|
||||||
|
|
||||||
### BRANDING
|
### BRANDING
|
||||||
@@ -78,18 +119,19 @@ endif()
|
|||||||
# Typically you would use only one branding, since that's
|
# Typically you would use only one branding, since that's
|
||||||
# the (single) branding for your distro.
|
# the (single) branding for your distro.
|
||||||
#
|
#
|
||||||
calamares_add_branding_subdirectory( branding/default NAME default )
|
# calamares_add_branding_subdirectory( branding/default NAME default )
|
||||||
calamares_add_branding_subdirectory( branding/default-mobile NAME default-mobile )
|
# calamares_add_branding_subdirectory( branding/default-mobile NAME default-mobile )
|
||||||
calamares_add_branding_subdirectory( branding/fancy NAME fancy )
|
# calamares_add_branding_subdirectory( branding/fancy NAME fancy )
|
||||||
|
|
||||||
# This one has files in subdirectories
|
# This one has files in subdirectories
|
||||||
calamares_add_branding_subdirectory( branding/samegame NAME samegame SUBDIRECTORIES img )
|
# calamares_add_branding_subdirectory( branding/samegame NAME samegame SUBDIRECTORIES img )
|
||||||
|
|
||||||
# KaOS branding, with translations, note we can *NAME* something
|
# KaOS branding, with translations, note we can *NAME* something
|
||||||
# different from the source directory it lives in; this will be installed
|
# different from the source directory it lives in; this will be installed
|
||||||
# to a directory called *NAME* though -- and the `branding.desc` must
|
# to a directory called *NAME* though -- and the `branding.desc` must
|
||||||
# have a *componentName* that matches this *NAME*.
|
# have a *componentName* that matches this *NAME*.
|
||||||
calamares_add_branding_subdirectory( branding/kaos_branding NAME kaos )
|
# calamares_add_branding_subdirectory( branding/kaos_branding NAME kaos )
|
||||||
|
calamares_add_branding_subdirectory( branding/artix NAME artix )
|
||||||
|
|
||||||
### MODULES
|
### MODULES
|
||||||
#
|
#
|
||||||
@@ -97,28 +139,25 @@ calamares_add_branding_subdirectory( branding/kaos_branding NAME kaos )
|
|||||||
#
|
#
|
||||||
set(LIST_SKIPPED_MODULES "")
|
set(LIST_SKIPPED_MODULES "")
|
||||||
|
|
||||||
calamares_add_module_subdirectory( modules/filekeeper LIST_SKIPPED_MODULES ) # C++ job
|
# calamares_add_module_subdirectory( modules/freebsddisk LIST_SKIPPED_MODULES ) # C++ viewmodule
|
||||||
calamares_add_module_subdirectory( modules/freebsddisk LIST_SKIPPED_MODULES ) # C++ viewmodule
|
# calamares_add_module_subdirectory( modules/mobile LIST_SKIPPED_MODULES )
|
||||||
calamares_add_module_subdirectory( modules/mobile LIST_SKIPPED_MODULES )
|
# calamares_add_module_subdirectory( modules/os-freebsd LIST_SKIPPED_MODULES )
|
||||||
calamares_add_module_subdirectory( modules/os-freebsd LIST_SKIPPED_MODULES )
|
# calamares_add_module_subdirectory( modules/os-nixos LIST_SKIPPED_MODULES )
|
||||||
calamares_add_module_subdirectory( modules/os-nixos LIST_SKIPPED_MODULES )
|
# calamares_add_module_subdirectory( modules/refind LIST_SKIPPED_MODULES )
|
||||||
calamares_add_module_subdirectory( modules/slowpython LIST_SKIPPED_MODULES ) # Python job
|
# calamares_add_module_subdirectory( modules/slowpython LIST_SKIPPED_MODULES ) # Python job
|
||||||
|
# calamares_add_module_subdirectory( modules/unpackfsc LIST_SKIPPED_MODULES )
|
||||||
|
|
||||||
|
calamares_add_module_subdirectory( modules/basestrap LIST_SKIPPED_MODULES )
|
||||||
|
calamares_add_module_subdirectory( modules/services-artix LIST_SKIPPED_MODULES )
|
||||||
|
# calamares_add_module_subdirectory( modules/services-runit LIST_SKIPPED_MODULES )
|
||||||
|
# calamares_add_module_subdirectory( modules/services-dinit LIST_SKIPPED_MODULES )
|
||||||
|
# calamares_add_module_subdirectory( modules/services-s6 LIST_SKIPPED_MODULES )
|
||||||
|
calamares_add_module_subdirectory( modules/postcfg LIST_SKIPPED_MODULES )
|
||||||
|
calamares_add_module_subdirectory( modules/packagechooser LIST_SKIPPED_MODULES )
|
||||||
|
calamares_add_module_subdirectory( modules/packagechooserq LIST_SKIPPED_MODULES )
|
||||||
|
|
||||||
|
message(STATUS "Calamares extensions ${CALAMARES_EXTENSIONS_VERSION} for Calamares version ${Calamares_VERSION}")
|
||||||
|
|
||||||
# If modules cannot be built, they usually call a macro
|
# If modules cannot be built, they usually call a macro
|
||||||
# which builds a list of explanations; show that list.
|
# which builds a list of explanations; show that list.
|
||||||
calamares_explain_skipped_modules( ${LIST_SKIPPED_MODULES} )
|
calamares_explain_skipped_modules( ${LIST_SKIPPED_MODULES} )
|
||||||
|
|
||||||
### RELEASE SUPPORT
|
|
||||||
#
|
|
||||||
#
|
|
||||||
set( CALAMARES_VERSION ${calamares-extensions_VERSION_MAJOR}.${calamares-extensions_VERSION_MINOR}.${calamares-extensions_VERSION_PATCH} )
|
|
||||||
# In rare cases we have hotfix-releases with a tweak
|
|
||||||
if( calamares-extensions_VERSION_TWEAK )
|
|
||||||
set( CALAMARES_VERSION "${calamares-extensions_VERSION}.${calamares-extensions_VERSION_TWEAK}" )
|
|
||||||
endif()
|
|
||||||
set( CALAMARES_VERSION_SHORT "${CALAMARES_VERSION}" )
|
|
||||||
|
|
||||||
add_custom_target(show-version
|
|
||||||
${CMAKE_COMMAND} -E echo CALAMARES_VERSION=${CALAMARES_VERSION_SHORT}
|
|
||||||
USES_TERMINAL
|
|
||||||
)
|
|
||||||
|
|||||||
90
CMakeModules/ExtendedVersion.cmake
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2014 Teo Mrnjavac <teo@kde.org>
|
||||||
|
# SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
###
|
||||||
|
#
|
||||||
|
# This file defines one function for extending a VERSION-like value
|
||||||
|
# with date and git information (if desired).
|
||||||
|
#
|
||||||
|
# - extend_version( version-string short_var long_var )
|
||||||
|
# Calling this function will copy *version-string* (which would typically
|
||||||
|
# be a semver-style string, like "3.2.40") into the variable *short_var*.
|
||||||
|
# The *version-string* plus date and git information (if git is available),
|
||||||
|
# is copied into the varialbe *long_var*, in the format {version}-{date}-{hash}
|
||||||
|
#
|
||||||
|
# A helper function that may be used independently:
|
||||||
|
#
|
||||||
|
# - get_git_version_info( out_var )
|
||||||
|
# If relevant and possible (e.g. it is a git checkout and git is availablle
|
||||||
|
# in the environment), put git versioning information in *out_var*.
|
||||||
|
#
|
||||||
|
# A convenience function for use from script-mode for version reporting:
|
||||||
|
#
|
||||||
|
# - report_version( version top_dir )
|
||||||
|
# Call this with an intended version string (e.g. "1.1") and
|
||||||
|
# the top-level source directory (e.g. `${CMAKE_CURRENT_LIST_DIR}`
|
||||||
|
# or `${CMAKE_SOURCE_DIR}` .. in script mode, the latter is not defined).
|
||||||
|
#
|
||||||
|
|
||||||
|
function( get_git_version_info out_var )
|
||||||
|
set(CMAKE_VERSION_SOURCE "")
|
||||||
|
if(EXISTS ${CMAKE_SOURCE_DIR}/.git/HEAD)
|
||||||
|
find_program(GIT_EXECUTABLE NAMES git git.cmd)
|
||||||
|
mark_as_advanced(GIT_EXECUTABLE)
|
||||||
|
if(GIT_EXECUTABLE)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} rev-parse --verify -q --short=8 HEAD
|
||||||
|
OUTPUT_VARIABLE head
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
if(head)
|
||||||
|
set(CMAKE_VERSION_SOURCE "${head}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} update-index -q --refresh
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${GIT_EXECUTABLE} diff-index --name-only HEAD --
|
||||||
|
OUTPUT_VARIABLE dirty
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
if(dirty)
|
||||||
|
set(CMAKE_VERSION_SOURCE "${CMAKE_VERSION_SOURCE}-dirty")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
set( ${out_var} "${CMAKE_VERSION_SOURCE}" PARENT_SCOPE )
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function( extend_version version short_var long_var )
|
||||||
|
set( ${short_var} "${version}" PARENT_SCOPE )
|
||||||
|
|
||||||
|
# Additional info for non-release builds which want "long" version info
|
||||||
|
# with date and git information (commit, dirty status).
|
||||||
|
set( _v "${version}" )
|
||||||
|
string( TIMESTAMP CALAMARES_VERSION_DATE "%Y%m%d" )
|
||||||
|
if( CALAMARES_VERSION_DATE GREATER 0 )
|
||||||
|
set( _v ${_v}.${CALAMARES_VERSION_DATE} )
|
||||||
|
endif()
|
||||||
|
get_git_version_info( _gitv )
|
||||||
|
if( _gitv )
|
||||||
|
set( _v "${_v}-${_gitv}" )
|
||||||
|
endif()
|
||||||
|
set( ${long_var} "${_v}" PARENT_SCOPE )
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function( report_version version top_dir )
|
||||||
|
set( CMAKE_SOURCE_DIR ${top_dir} )
|
||||||
|
extend_version( ${version} _vshort _vlong )
|
||||||
|
if ( "x${VERSION_STYLE}" STREQUAL "xshort" )
|
||||||
|
message( "${_vshort}" )
|
||||||
|
else()
|
||||||
|
message( "${_vlong}" )
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
40
CONTRIBUTING.md
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<!-- SPDX-FileCopyrightText: no
|
||||||
|
SPDX-License-Identifier: CC0-1.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Contributing to Calamares Extensions
|
||||||
|
|
||||||
|
Welcome to Calamares! We're happy that you would like to add
|
||||||
|
something to Calamares -- by extending it!
|
||||||
|
This contribution guide is minimal:
|
||||||
|
all the **technical** parts of contributing to
|
||||||
|
Calamares Extensions are the same as [contributing to Calamares](https://github.com/calamares/calamares/CONTRIBUTING.md).
|
||||||
|
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
The Calamares community -- of developers, translators, and downstream (distro) users --
|
||||||
|
aims to be courteous, professional, and inclusive. Harrassment, discriminatory
|
||||||
|
statements and abuse are not tolerated. In general, we apply the
|
||||||
|
[KDE Code of Conduct](https://www.kde.org/code-of-conduct/) and the
|
||||||
|
[GNOME Code of Conduct](https://wiki.gnome.org/Foundation/CodeOfConduct) (the
|
||||||
|
rules of decent behavior in both communities are pretty much the same).
|
||||||
|
|
||||||
|
> See the [CoC section on the wiki](https://github.com/calamares/calamares/wiki#code-of-conduct)
|
||||||
|
> for a longer text. To report a problem, please contact the maintainer,
|
||||||
|
> Adriaan de Groot, or the KDE Community Working Group.
|
||||||
|
|
||||||
|
|
||||||
|
## Join the Conversation
|
||||||
|
|
||||||
|
GitHub Issues are **one** place for discussing Calamares and its extensions if there are concrete
|
||||||
|
problems or a new feature to discuss.
|
||||||
|
Issues are not a help channel.
|
||||||
|
Visit Matrix for help with configuration or compilation.
|
||||||
|
|
||||||
|
Regular Calamares development chit-chat happens in a [Matrix](https://matrix.org/)
|
||||||
|
room, `#calamares:kde.org`. Responsiveness is best during the day
|
||||||
|
in Europe, but feel free to idle.
|
||||||
|
Matrix is persistent, and we'll see your message eventually.
|
||||||
|
|
||||||
|
* [](https://webchat.kde.org/#/room/%23calamares:kde.org)
|
||||||
24
LICENSES/BSD-2-Clause.txt
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
Copyright 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
119
LICENSES/CC0-1.0.txt
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
Creative Commons Legal Code
|
||||||
|
|
||||||
|
CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES
|
||||||
|
NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE
|
||||||
|
AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION
|
||||||
|
ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE
|
||||||
|
OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS
|
||||||
|
LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION
|
||||||
|
OR WORKS PROVIDED HEREUNDER.
|
||||||
|
|
||||||
|
Statement of Purpose
|
||||||
|
|
||||||
|
The laws of most jurisdictions throughout the world automatically confer exclusive
|
||||||
|
Copyright and Related Rights (defined below) upon the creator and subsequent
|
||||||
|
owner(s) (each and all, an "owner") of an original work of authorship and/or
|
||||||
|
a database (each, a "Work").
|
||||||
|
|
||||||
|
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||||
|
purpose of contributing to a commons of creative, cultural and scientific
|
||||||
|
works ("Commons") that the public can reliably and without fear of later claims
|
||||||
|
of infringement build upon, modify, incorporate in other works, reuse and
|
||||||
|
redistribute as freely as possible in any form whatsoever and for any purposes,
|
||||||
|
including without limitation commercial purposes. These owners may contribute
|
||||||
|
to the Commons to promote the ideal of a free culture and the further production
|
||||||
|
of creative, cultural and scientific works, or to gain reputation or greater
|
||||||
|
distribution for their Work in part through the use and efforts of others.
|
||||||
|
|
||||||
|
For these and/or other purposes and motivations, and without any expectation
|
||||||
|
of additional consideration or compensation, the person associating CC0 with
|
||||||
|
a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||||
|
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||||
|
and publicly distribute the Work under its terms, with knowledge of his or
|
||||||
|
her Copyright and Related Rights in the Work and the meaning and intended
|
||||||
|
legal effect of CC0 on those rights.
|
||||||
|
|
||||||
|
1. Copyright and Related Rights. A Work made available under CC0 may be protected
|
||||||
|
by copyright and related or neighboring rights ("Copyright and Related Rights").
|
||||||
|
Copyright and Related Rights include, but are not limited to, the following:
|
||||||
|
|
||||||
|
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||||
|
and translate a Work;
|
||||||
|
|
||||||
|
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||||
|
|
||||||
|
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||||
|
depicted in a Work;
|
||||||
|
|
||||||
|
iv. rights protecting against unfair competition in regards to a Work, subject
|
||||||
|
to the limitations in paragraph 4(a), below;
|
||||||
|
|
||||||
|
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||||
|
in a Work;
|
||||||
|
|
||||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||||
|
European Parliament and of the Council of 11 March 1996 on the legal protection
|
||||||
|
of databases, and under any national implementation thereof, including any
|
||||||
|
amended or successor version of such directive); and
|
||||||
|
|
||||||
|
vii. other similar, equivalent or corresponding rights throughout the world
|
||||||
|
based on applicable law or treaty, and any national implementations thereof.
|
||||||
|
|
||||||
|
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||||
|
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||||
|
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||||
|
and Related Rights and associated claims and causes of action, whether now
|
||||||
|
known or unknown (including existing as well as future claims and causes of
|
||||||
|
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||||
|
duration provided by applicable law or treaty (including future time extensions),
|
||||||
|
(iii) in any current or future medium and for any number of copies, and (iv)
|
||||||
|
for any purpose whatsoever, including without limitation commercial, advertising
|
||||||
|
or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the
|
||||||
|
benefit of each member of the public at large and to the detriment of Affirmer's
|
||||||
|
heirs and successors, fully intending that such Waiver shall not be subject
|
||||||
|
to revocation, rescission, cancellation, termination, or any other legal or
|
||||||
|
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||||
|
as contemplated by Affirmer's express Statement of Purpose.
|
||||||
|
|
||||||
|
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||||
|
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||||
|
shall be preserved to the maximum extent permitted taking into account Affirmer's
|
||||||
|
express Statement of Purpose. In addition, to the extent the Waiver is so
|
||||||
|
judged Affirmer hereby grants to each affected person a royalty-free, non
|
||||||
|
transferable, non sublicensable, non exclusive, irrevocable and unconditional
|
||||||
|
license to exercise Affirmer's Copyright and Related Rights in the Work (i)
|
||||||
|
in all territories worldwide, (ii) for the maximum duration provided by applicable
|
||||||
|
law or treaty (including future time extensions), (iii) in any current or
|
||||||
|
future medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||||
|
including without limitation commercial, advertising or promotional purposes
|
||||||
|
(the "License"). The License shall be deemed effective as of the date CC0
|
||||||
|
was applied by Affirmer to the Work. Should any part of the License for any
|
||||||
|
reason be judged legally invalid or ineffective under applicable law, such
|
||||||
|
partial invalidity or ineffectiveness shall not invalidate the remainder of
|
||||||
|
the License, and in such case Affirmer hereby affirms that he or she will
|
||||||
|
not (i) exercise any of his or her remaining Copyright and Related Rights
|
||||||
|
in the Work or (ii) assert any associated claims and causes of action with
|
||||||
|
respect to the Work, in either case contrary to Affirmer's express Statement
|
||||||
|
of Purpose.
|
||||||
|
|
||||||
|
4. Limitations and Disclaimers.
|
||||||
|
|
||||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered,
|
||||||
|
licensed or otherwise affected by this document.
|
||||||
|
|
||||||
|
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||||
|
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||||
|
including without limitation warranties of title, merchantability, fitness
|
||||||
|
for a particular purpose, non infringement, or the absence of latent or other
|
||||||
|
defects, accuracy, or the present or absence of errors, whether or not discoverable,
|
||||||
|
all to the greatest extent permissible under applicable law.
|
||||||
|
|
||||||
|
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||||
|
that may apply to the Work or any use thereof, including without limitation
|
||||||
|
any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims
|
||||||
|
responsibility for obtaining any necessary consents, permissions or other
|
||||||
|
rights required for any use of the Work.
|
||||||
|
|
||||||
|
d. Affirmer understands and acknowledges that Creative Commons is not a party
|
||||||
|
to this document and has no duty or obligation with respect to this CC0 or
|
||||||
|
use of the Work.
|
||||||
24
README.md
@@ -1,3 +1,7 @@
|
|||||||
|
<!-- SPDX-FileCopyrightText: no
|
||||||
|
SPDX-License-Identifier: CC0-1.0
|
||||||
|
-->
|
||||||
|
|
||||||
# Calamares Branding and Module Examples
|
# Calamares Branding and Module Examples
|
||||||
|
|
||||||
> A *branding component* in Calamares is a description of the
|
> A *branding component* in Calamares is a description of the
|
||||||
@@ -36,7 +40,10 @@ and documentation for the framework that Calamares ships with.
|
|||||||
(probably moreso than the default slideshow).
|
(probably moreso than the default slideshow).
|
||||||
- [`kaos_branding/`](branding/kaos_branding/branding.desc)
|
- [`kaos_branding/`](branding/kaos_branding/branding.desc)
|
||||||
is a copy of the KaOS branding component, which
|
is a copy of the KaOS branding component, which
|
||||||
has translations and a bunch of fancy graphics.
|
has translations and a bunch of fancy graphics for the
|
||||||
|
slideshow. Plus it includes examples of using different
|
||||||
|
QML options for a vertical navigation bar and horizontal
|
||||||
|
sidebar.
|
||||||
- [`samegame/` ](branding/default/branding.desc)
|
- [`samegame/` ](branding/default/branding.desc)
|
||||||
is a copy of the Qt Company "Same Game" QML demo. It
|
is a copy of the Qt Company "Same Game" QML demo. It
|
||||||
shows that **any** QML can be used for branding purposes.
|
shows that **any** QML can be used for branding purposes.
|
||||||
@@ -207,3 +214,18 @@ usually called `main.py` which defines a `run()` function.
|
|||||||
|
|
||||||
The API is loosely documented in the
|
The API is loosely documented in the
|
||||||
[developer guide](https://github.com/calamares/calamares/wiki/Develop-Guide).
|
[developer guide](https://github.com/calamares/calamares/wiki/Develop-Guide).
|
||||||
|
|
||||||
|
# Join the Conversation
|
||||||
|
|
||||||
|
GitHub Issues are **one** place for discussing Calamares (and Calamares Extensions)
|
||||||
|
if there are concrete
|
||||||
|
problems or a new feature to discuss.
|
||||||
|
Issues are not a help channel.
|
||||||
|
Visit Matrix for help with configuration or compilation.
|
||||||
|
|
||||||
|
Regular Calamares development chit-chat happens in a [Matrix](https://matrix.org/)
|
||||||
|
room, `#calamares:kde.org`. Responsiveness is best during the day
|
||||||
|
in Europe, but feel free to idle.
|
||||||
|
Matrix is persistent, and we'll see your message eventually.
|
||||||
|
|
||||||
|
* [](https://webchat.kde.org/#/room/%23calamares:kde.org)
|
||||||
|
|||||||
BIN
branding/artix/artix.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
branding/artix/banner.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
239
branding/artix/branding.desc
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
# SPDX-FileCopyrightText: no
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
#
|
||||||
|
# Product branding information. This influences some global
|
||||||
|
# user-visible aspects of Calamares, such as the product
|
||||||
|
# name, window behavior, and the slideshow during installation.
|
||||||
|
#
|
||||||
|
# Additional styling can be done using the stylesheet.qss
|
||||||
|
# file, also in the branding directory.
|
||||||
|
---
|
||||||
|
componentName: artix
|
||||||
|
|
||||||
|
|
||||||
|
### WELCOME / OVERALL WORDING
|
||||||
|
#
|
||||||
|
# These settings affect some overall phrasing and looks,
|
||||||
|
# which are most visible in the welcome page.
|
||||||
|
|
||||||
|
# This selects between different welcome texts. When false, uses
|
||||||
|
# the traditional "Welcome to the %1 installer.", and when true,
|
||||||
|
# uses "Welcome to the Calamares installer for %1." This allows
|
||||||
|
# to distinguish this installer from other installers for the
|
||||||
|
# same distribution.
|
||||||
|
welcomeStyleCalamares: false
|
||||||
|
|
||||||
|
# Should the welcome image (productWelcome, below) be scaled
|
||||||
|
# up beyond its natural size? If false, the image does not grow
|
||||||
|
# with the window but remains the same size throughout (this
|
||||||
|
# may have surprising effects on HiDPI monitors).
|
||||||
|
welcomeExpandingLogo: true
|
||||||
|
|
||||||
|
### WINDOW CONFIGURATION
|
||||||
|
#
|
||||||
|
# The settings here affect the placement of the Calamares
|
||||||
|
# window through hints to the window manager and initial
|
||||||
|
# sizing of the Calamares window.
|
||||||
|
|
||||||
|
# Size and expansion policy for Calamares.
|
||||||
|
# - "normal" or unset, expand as needed, use *windowSize*
|
||||||
|
# - "fullscreen", start as large as possible, ignore *windowSize*
|
||||||
|
# - "noexpand", don't expand automatically, use *windowSize*
|
||||||
|
windowExpanding: normal
|
||||||
|
|
||||||
|
# Size of Calamares window, expressed as w,h. Both w and h
|
||||||
|
# may be either pixels (suffix px) or font-units (suffix em).
|
||||||
|
# e.g. "800px,600px"
|
||||||
|
# "60em,480px"
|
||||||
|
# This setting is ignored if "fullscreen" is selected for
|
||||||
|
# *windowExpanding*, above. If not set, use constants defined
|
||||||
|
# in CalamaresUtilsGui, 800x520.
|
||||||
|
windowSize: 800px,520px
|
||||||
|
|
||||||
|
# Placement of Calamares window. Either "center" or "free".
|
||||||
|
# Whether "center" actually works does depend on the window
|
||||||
|
# manager in use (and only makes sense if you're not using
|
||||||
|
# *windowExpanding* set to "fullscreen").
|
||||||
|
windowPlacement: center
|
||||||
|
|
||||||
|
### PANELS CONFIGURATION
|
||||||
|
#
|
||||||
|
# Calamares has a main content area, and two panels (navigation
|
||||||
|
# and progress / sidebar). The panels can be controlled individually,
|
||||||
|
# or switched off. If both panels are switched off, the layout of
|
||||||
|
# the main content area loses its margins, on the assumption that
|
||||||
|
# you're doing something special.
|
||||||
|
|
||||||
|
# Kind of sidebar (panel on the left, showing progress).
|
||||||
|
# - "widget" or unset, use traditional sidebar (logo, items)
|
||||||
|
# - "none", hide it entirely
|
||||||
|
# - "qml", use calamares-sidebar.qml from branding folder
|
||||||
|
# In addition, you **may** specify a side, separated by a comma,
|
||||||
|
# from the kind. Valid sides are:
|
||||||
|
# - "left" (if not specified, uses this)
|
||||||
|
# - "right"
|
||||||
|
# - "top"
|
||||||
|
# - "bottom"
|
||||||
|
# For instance, "widget,right" is valid; so is "qml", which defaults
|
||||||
|
# to putting the sidebar on the left. Also valid is "qml,top".
|
||||||
|
# While "widget,top" is valid, the widgets code is **not** flexible
|
||||||
|
# and results will be terrible.
|
||||||
|
sidebar: widget
|
||||||
|
|
||||||
|
# Kind of navigation (button panel on the bottom).
|
||||||
|
# - "widget" or unset, use traditional navigation
|
||||||
|
# - "none", hide it entirely
|
||||||
|
# - "qml", use calamares-navigation.qml from branding folder
|
||||||
|
# In addition, you **may** specify a side, separated by a comma,
|
||||||
|
# from the kind. The same sides are valid as for *sidebar*,
|
||||||
|
# except the default is *bottom*.
|
||||||
|
navigation: widget
|
||||||
|
|
||||||
|
|
||||||
|
### STRINGS, IMAGES AND COLORS
|
||||||
|
#
|
||||||
|
# This section contains the "branding proper" of names
|
||||||
|
# and images, rather than global-look settings.
|
||||||
|
|
||||||
|
# These are strings shown to the user in the user interface.
|
||||||
|
# There is no provision for translating them -- since they
|
||||||
|
# are names, the string is included as-is.
|
||||||
|
#
|
||||||
|
# The four Url strings are the Urls used by the buttons in
|
||||||
|
# the welcome screen, and are not shown to the user. Clicking
|
||||||
|
# on the "Support" button, for instance, opens the link supportUrl.
|
||||||
|
# If a Url is empty, the corresponding button is not shown.
|
||||||
|
#
|
||||||
|
# bootloaderEntryName is how this installation / distro is named
|
||||||
|
# in the boot loader (e.g. in the GRUB menu).
|
||||||
|
#
|
||||||
|
# These strings support substitution from /etc/os-release
|
||||||
|
# if KDE Frameworks 5.58 are available at build-time. When
|
||||||
|
# enabled, ${varname} is replaced by the equivalent value
|
||||||
|
# from os-release. All the supported var-names are in all-caps,
|
||||||
|
# and are listed on the FreeDesktop.org site,
|
||||||
|
# https://www.freedesktop.org/software/systemd/man/os-release.html
|
||||||
|
# Note that ANSI_COLOR and CPE_NAME don't make sense here, and
|
||||||
|
# are not supported (the rest are). Remember to quote the string
|
||||||
|
# if it contains substitutions, or you'll get YAML exceptions.
|
||||||
|
#
|
||||||
|
# The *Url* entries are used on the welcome page, and they
|
||||||
|
# are visible as buttons there if the corresponding *show* keys
|
||||||
|
# are set to "true" (they can also be overridden).
|
||||||
|
strings:
|
||||||
|
productName: Artix Linux
|
||||||
|
shortProductName: Artix
|
||||||
|
version: rolling
|
||||||
|
shortVersion: rolling
|
||||||
|
versionedName: Artix Linux "rolling"
|
||||||
|
shortVersionedName: Artix rolling
|
||||||
|
bootloaderEntryName: Artix
|
||||||
|
productUrl: https://www.artixlinux.org/
|
||||||
|
supportUrl: https://github.com/calamares/calamares/issues
|
||||||
|
knownIssuesUrl: https://calamares.io/about/
|
||||||
|
releaseNotesUrl: https://calamares.io/about/
|
||||||
|
# donateUrl: https://kde.org/community/donations/index.php
|
||||||
|
|
||||||
|
# These images are loaded from the branding module directory.
|
||||||
|
#
|
||||||
|
# productBanner is an optional image, which if present, will be shown
|
||||||
|
# on the welcome page of the application, above the welcome text.
|
||||||
|
# It is intended to have a width much greater than height.
|
||||||
|
# It is displayed at 64px height (also on HiDPI).
|
||||||
|
# Recommended size is 64px tall, and up to 460px wide.
|
||||||
|
# productIcon is used as the window icon, and will (usually) be used
|
||||||
|
# by the window manager to represent the application. This image
|
||||||
|
# should be square, and may be displayed by the window manager
|
||||||
|
# as small as 16x16 (but possibly larger).
|
||||||
|
# productLogo is used as the logo at the top of the left-hand column
|
||||||
|
# which shows the steps to be taken. The image should be square,
|
||||||
|
# and is displayed at 80x80 pixels (also on HiDPI).
|
||||||
|
# productWallpaper is an optional image, which if present, will replace
|
||||||
|
# the normal solid background on every page of the application.
|
||||||
|
# It can be any size and proportion,
|
||||||
|
# and will be tiled to fit the entire window.
|
||||||
|
# For a non-tiled wallpaper, the size should be the same as
|
||||||
|
# the overall window, see *windowSize* above (800x520).
|
||||||
|
# productWelcome is shown on the welcome page of the application in
|
||||||
|
# the middle of the window, below the welcome text. It can be
|
||||||
|
# any size and proportion, and will be scaled to fit inside
|
||||||
|
# the window. Use `welcomeExpandingLogo` to make it non-scaled.
|
||||||
|
# Recommended size is 320x150.
|
||||||
|
#
|
||||||
|
# These filenames can also use substitutions from os-release (see above).
|
||||||
|
images:
|
||||||
|
productBanner: "banner.png"
|
||||||
|
productIcon: "logo.png"
|
||||||
|
productLogo: "logo.png"
|
||||||
|
# productWallpaper: "wallpaper.png"
|
||||||
|
productWelcome: "languages.png"
|
||||||
|
|
||||||
|
# Colors for text and background components.
|
||||||
|
#
|
||||||
|
# - SidebarBackground is the background of the sidebar
|
||||||
|
# - SidebarText is the (foreground) text color
|
||||||
|
# - SidebarBackgroundCurrent sets the background of the current step.
|
||||||
|
# Optional, and defaults to the application palette.
|
||||||
|
# - SidebarTextCurrent is the text color of the current step.
|
||||||
|
#
|
||||||
|
# These colors can **also** be set through the stylesheet, if the
|
||||||
|
# branding component also ships a stylesheet.qss. Then they are
|
||||||
|
# the corresponding CSS attributes of #sidebarApp.
|
||||||
|
style:
|
||||||
|
SidebarBackground: "#292F34"
|
||||||
|
SidebarText: "#FFFFFF"
|
||||||
|
SidebarTextCurrent: "#292F34"
|
||||||
|
SidebarBackgroundCurrent: "#16a3f5"
|
||||||
|
|
||||||
|
### SLIDESHOW
|
||||||
|
#
|
||||||
|
# The slideshow is displayed during execution steps (e.g. when the
|
||||||
|
# installer is actually writing to disk and doing other slow things).
|
||||||
|
|
||||||
|
# The slideshow can be a QML file (recommended) which can display
|
||||||
|
# arbitrary things -- text, images, animations, or even play a game --
|
||||||
|
# during the execution step. The QML **is** abruptly stopped when the
|
||||||
|
# execution step is done, though, so maybe a game isn't a great idea.
|
||||||
|
#
|
||||||
|
# The slideshow can also be a sequence of images (not recommended unless
|
||||||
|
# you don't want QML at all in your Calamares). The images are displayed
|
||||||
|
# at a rate of 1 every 2 seconds during the execution step.
|
||||||
|
#
|
||||||
|
# To configure a QML file, list a single filename:
|
||||||
|
# slideshow: "show.qml"
|
||||||
|
# To configure images, like the filenames (here, as an inline list):
|
||||||
|
# slideshow: [ "/etc/calamares/slideshow/0.png", "/etc/logo.png" ]
|
||||||
|
slideshow: "show.qml"
|
||||||
|
|
||||||
|
# There are two available APIs for a QML slideshow:
|
||||||
|
# - 1 (the default) loads the entire slideshow when the installation-
|
||||||
|
# slideshow page is shown and starts the QML then. The QML
|
||||||
|
# is never stopped (after installation is done, times etc.
|
||||||
|
# continue to fire).
|
||||||
|
# - 2 loads the slideshow on startup and calls onActivate() and
|
||||||
|
# onLeave() in the root object. After the installation is done,
|
||||||
|
# the show is stopped (first by calling onLeave(), then destroying
|
||||||
|
# the QML components).
|
||||||
|
#
|
||||||
|
# An image slideshow does not need to have the API defined.
|
||||||
|
slideshowAPI: 2
|
||||||
|
|
||||||
|
|
||||||
|
# These options are to customize online uploading of logs to pastebins:
|
||||||
|
# - type : Defines the kind of pastebin service to be used. Currently
|
||||||
|
# it accepts two values:
|
||||||
|
# - none : disables the pastebin functionality
|
||||||
|
# - fiche : use fiche pastebin server
|
||||||
|
# - url : Defines the address of pastebin service to be used.
|
||||||
|
# Takes string as input. Important bits are the host and port,
|
||||||
|
# the scheme is not used.
|
||||||
|
# - sizeLimit : Defines maximum size limit (in KiB) of log file to be pasted.
|
||||||
|
# The option must be set, to have the log option work.
|
||||||
|
# Takes integer as input. If < 0, no limit will be forced,
|
||||||
|
# else only last (approximately) 'n' KiB of log file will be pasted.
|
||||||
|
# Please note that upload size may be slightly over the limit (due
|
||||||
|
# to last minute logging), so provide a suitable value.
|
||||||
|
uploadServer :
|
||||||
|
type : "fiche"
|
||||||
|
url : "http://termbin.com:9999"
|
||||||
|
sizeLimit : -1
|
||||||
BIN
branding/artix/browsers.png
Normal file
|
After Width: | Height: | Size: 399 KiB |
BIN
branding/artix/customise.png
Normal file
|
After Width: | Height: | Size: 818 KiB |
BIN
branding/artix/desktops.png
Normal file
|
After Width: | Height: | Size: 151 KiB |
BIN
branding/artix/languages.png
Normal file
|
After Width: | Height: | Size: 84 KiB |
2
branding/artix/languages.png.license
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
SPDX-FileCopyrightText: 2015 Teo Mrnjavac <teo@kde.org>
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
BIN
branding/artix/logo.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
branding/artix/multimedia.png
Normal file
|
After Width: | Height: | Size: 363 KiB |
BIN
branding/artix/office.png
Normal file
|
After Width: | Height: | Size: 359 KiB |
BIN
branding/artix/packages1.png
Normal file
|
After Width: | Height: | Size: 873 KiB |
BIN
branding/artix/packages2.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
branding/artix/productivity.png
Normal file
|
After Width: | Height: | Size: 502 KiB |
BIN
branding/artix/rolling.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
178
branding/artix/show.qml
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
/* === This file is part of Calamares - <http://github.com/calamares> ===
|
||||||
|
*
|
||||||
|
* Copyright 2015, Teo Mrnjavac <teo@kde.org>
|
||||||
|
* Copyright 2016, Luca Giambonini <almack@chakralinux.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 QtQuick 2.0;
|
||||||
|
import calamares.slideshow 1.0;
|
||||||
|
|
||||||
|
/* Tested with slide images of 1800x1200 and 1632x1248 pixels */
|
||||||
|
|
||||||
|
Presentation
|
||||||
|
{
|
||||||
|
id: presentation
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 10000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: presentation.goToNextSlide()
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic0
|
||||||
|
source: "thanks.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic00
|
||||||
|
source: "artix.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic02
|
||||||
|
source: "tools.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic03
|
||||||
|
source: "desktops.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic04
|
||||||
|
source: "productivity.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic06
|
||||||
|
source: "browsers.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic07
|
||||||
|
source: "office.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic08
|
||||||
|
source: "multimedia.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic09
|
||||||
|
source: "web.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic11
|
||||||
|
source: "packages1.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic13
|
||||||
|
source: "packages2.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic15
|
||||||
|
source: "customise.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide {
|
||||||
|
Image {
|
||||||
|
id: pic16
|
||||||
|
source: "rolling.png"
|
||||||
|
width: parent.width * 1.12; height: parent.height * 1.5
|
||||||
|
fillMode: Image.Stretch
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset: -20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
96
branding/artix/stylesheet.qss
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: no
|
||||||
|
* SPDX-License-Identifier: CC0-1.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
A branding component can ship a stylesheet (like this one)
|
||||||
|
which is applied to parts of the Calamares user-interface.
|
||||||
|
In principle, all parts can be styled through CSS.
|
||||||
|
Missing parts should be filed as issues.
|
||||||
|
|
||||||
|
The IDs are based on the object names in the C++ code.
|
||||||
|
You can use the Debug Dialog to find out object names:
|
||||||
|
- Open the debug dialog
|
||||||
|
- Choose tab *Tools*
|
||||||
|
- Click *Widget Tree* button
|
||||||
|
The list of object names is printed in the log.
|
||||||
|
|
||||||
|
Documentation for styling Qt Widgets through a stylesheet
|
||||||
|
can be found at
|
||||||
|
https://doc.qt.io/qt-5/stylesheet-examples.html
|
||||||
|
https://doc.qt.io/qt-5/stylesheet-reference.html
|
||||||
|
In Calamares, styling widget classes is supported (e.g.
|
||||||
|
using `QComboBox` as a selector).
|
||||||
|
|
||||||
|
This example stylesheet has all the actual styling commented out.
|
||||||
|
The examples are not exhaustive.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** Generic Widgets.
|
||||||
|
*
|
||||||
|
* You can style **all** widgets of a given class by selecting
|
||||||
|
* the class name. Some widgets have specialized sub-selectors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
QPushButton { background-color: green; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** Main application window.
|
||||||
|
*
|
||||||
|
* The main application window has the sidebar, which in turn
|
||||||
|
* contains a logo and a list of items -- note that the list
|
||||||
|
* can **not** be styled, since it has its own custom C++
|
||||||
|
* delegate code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#mainApp { }
|
||||||
|
#sidebarApp { }
|
||||||
|
#logoApp { }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** Welcome module.
|
||||||
|
*
|
||||||
|
* There are plenty of parts, but the buttons are the most interesting
|
||||||
|
* ones (donate, release notes, ...). The little icon image can be
|
||||||
|
* styled through *qproperty-icon*, which is a little obscure.
|
||||||
|
* URLs can reference the QRC paths of the Calamares application
|
||||||
|
* or loaded via plugins or within the filesystem. There is no
|
||||||
|
* comprehensive list of available icons, though.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
QPushButton#aboutButton { qproperty-icon: url(:/data/images/release.svg); }
|
||||||
|
#donateButton,
|
||||||
|
#supportButton,
|
||||||
|
#releaseNotesButton,
|
||||||
|
#knownIssuesButton { qproperty-icon: url(:/data/images/help.svg); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** Partitioning module.
|
||||||
|
*
|
||||||
|
* Many moving parts, which you will need to experiment with.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#bootInfoIcon { }
|
||||||
|
#bootInfoLable { }
|
||||||
|
#deviceInfoIcon { }
|
||||||
|
#defineInfoLabel { }
|
||||||
|
#scrollAreaWidgetContents { }
|
||||||
|
#partitionBarView { }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*** Licensing module.
|
||||||
|
*
|
||||||
|
* The licensing module paints individual widgets for each of
|
||||||
|
* the licenses. The item can be collapsed or expanded.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#licenseItem { }
|
||||||
|
#licenseItemFullText { }
|
||||||
|
*/
|
||||||
BIN
branding/artix/thanks.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
branding/artix/tools.png
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
branding/artix/web.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
101
branding/kaos_branding/about.qml
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2020 2022 Anke Boersma <demm@kaosx.us>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import io.calamares.core 1.0
|
||||||
|
import io.calamares.ui 1.0
|
||||||
|
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.0
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Window 2.3
|
||||||
|
|
||||||
|
ApplicationWindow {
|
||||||
|
id: about
|
||||||
|
visible: true
|
||||||
|
width: 760
|
||||||
|
height: 400
|
||||||
|
title: qsTr("About Calamares")
|
||||||
|
|
||||||
|
property var appName: "Calamares"
|
||||||
|
property var appVersion: "3.3 RC"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: textArea
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "#f2f2f2"
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: column
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 560
|
||||||
|
height: 250
|
||||||
|
radius: 10
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: 400
|
||||||
|
height: 250
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("<h1>%1</h1><br/>
|
||||||
|
<strong>%2<br/>
|
||||||
|
for %3</strong><br/><br/>
|
||||||
|
Copyright 2014-2017 Teo Mrnjavac <teo@kde.org><br/>
|
||||||
|
Copyright 2017-2022 Adriaan de Groot <groot@kde.org><br/>
|
||||||
|
Thanks to <a href='https://calamares.io/team/'>the Calamares team</a>
|
||||||
|
and the <a href=\"https://www.transifex.com/kaos/kaos/\">KaOS
|
||||||
|
translators team</a>.<br/><br/>
|
||||||
|
<a href='https://calamares.io/'>Calamares</a>
|
||||||
|
development is sponsored by <br/>
|
||||||
|
<a href='http://www.blue-systems.com/'>Blue Systems</a> -
|
||||||
|
Liberating Software." )
|
||||||
|
.arg(appName)
|
||||||
|
.arg(appVersion)
|
||||||
|
.arg(Branding.string(Branding.VersionedName))
|
||||||
|
|
||||||
|
onLinkActivated: Qt.openUrlExternally(link)
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
font.pointSize: 10
|
||||||
|
anchors.verticalCenterOffset: 10
|
||||||
|
anchors.horizontalCenterOffset: 40
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
x: 8
|
||||||
|
y: 12
|
||||||
|
height: 100
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
source: "squid.png"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
icon.name: "window-close"
|
||||||
|
text: qsTr("Close")
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: about.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,22 +1,32 @@
|
|||||||
---
|
---
|
||||||
componentName: kaos
|
componentName: kaos
|
||||||
|
|
||||||
|
welcomeStyleCalamares: false
|
||||||
|
|
||||||
# Should the welcome image (productWelcome, below) be scaled
|
# Should the welcome image (productWelcome, below) be scaled
|
||||||
# up beyond its natural size?
|
# up beyond its natural size?
|
||||||
welcomeExpandingLogo: true
|
welcomeExpandingLogo: true
|
||||||
|
|
||||||
|
windowExpanding: normal
|
||||||
|
windowSize: 920px,630px
|
||||||
|
windowPlacement: center
|
||||||
|
|
||||||
|
sidebar: qml,bottom
|
||||||
|
navigation: qml,right
|
||||||
|
|
||||||
strings:
|
strings:
|
||||||
productName: KaOS
|
productName: KaOS
|
||||||
shortProductName: KaOS
|
shortProductName: KaOS
|
||||||
version: 2018.03
|
version: 2022.08
|
||||||
shortVersion: KaOS
|
shortVersion: KaOS
|
||||||
versionedName: KaOS 2018.03
|
versionedName: KaOS 2022.08
|
||||||
shortVersionedName: KaOS 2018.03
|
shortVersionedName: KaOS 2018.03
|
||||||
bootloaderEntryName: KaOS
|
bootloaderEntryName: KaOS
|
||||||
productUrl: https://kaosx.us/
|
productUrl: https://kaosx.us/
|
||||||
supportUrl: https://kaosx.us/docs/
|
supportUrl: https://kaosx.us/docs/
|
||||||
knownIssuesUrl: https://kaosx.us/pages/download/#known-issues
|
knownIssuesUrl: https://kaosx.us/pages/download/#known-issues
|
||||||
releaseNotesUrl: https://kaosx.us/pages/release_notes
|
releaseNotesUrl: https://kaosx.us/pages/release_notes
|
||||||
|
donateUrl: https://kaosx.us/about/donors
|
||||||
|
|
||||||
images:
|
images:
|
||||||
productLogo: "kaos.png"
|
productLogo: "kaos.png"
|
||||||
@@ -27,6 +37,7 @@ slideshow: "show.qml"
|
|||||||
slideshowAPI: 1
|
slideshowAPI: 1
|
||||||
|
|
||||||
style:
|
style:
|
||||||
sidebarBackground: "#bdc3c7"
|
SidebarBackground: "#bdc3c7"
|
||||||
sidebarText: "#1F1F1F"
|
SidebarText: "#1F1F1F"
|
||||||
sidebarTextSelect: "#3498DB"
|
SidebarTextCurrent: "#3498DB"
|
||||||
|
SidebarBackgroundCurrent: "#eff0f1"
|
||||||
|
|||||||
224
branding/kaos_branding/calamares-navigation.qml
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
/* Sample of QML navigation.
|
||||||
|
|
||||||
|
SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
|
SPDX-FileCopyrightText: 2021 - 2022 Anke Boersma <demm@kaosx.us>
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
|
This navigation panel is for a "vertical" layout, with
|
||||||
|
mouse areas for next and previous and it includes the logo
|
||||||
|
plus About & Debug buttons.
|
||||||
|
*/
|
||||||
|
import io.calamares.ui 1.0
|
||||||
|
import io.calamares.core 1.0
|
||||||
|
|
||||||
|
import QtQuick 2.3
|
||||||
|
import QtQuick.Controls 2.10
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: navigationBar;
|
||||||
|
color: Branding.styleString( Branding.SidebarBackground );
|
||||||
|
height: parent.height;
|
||||||
|
width:64;
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: buttonBar
|
||||||
|
anchors.fill: parent;
|
||||||
|
spacing: 1
|
||||||
|
|
||||||
|
Image {
|
||||||
|
Layout.topMargin: 1;
|
||||||
|
Layout.bottomMargin:parent.height / 7;
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
|
||||||
|
id: logo;
|
||||||
|
width: 62;
|
||||||
|
height: width; // square
|
||||||
|
source: "file:/" + Branding.imagePath(Branding.ProductLogo);
|
||||||
|
sourceSize.width: width;
|
||||||
|
sourceSize.height: height;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: backArea
|
||||||
|
Layout.fillWidth: true;
|
||||||
|
Layout.preferredHeight: parent.height / 7;
|
||||||
|
color: mouseBack.containsMouse ? "#e6e9ea" : "#d9dcde";
|
||||||
|
enabled: ViewManager.backEnabled;
|
||||||
|
visible: ViewManager.backAndNextVisible;
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseBack
|
||||||
|
anchors.fill: parent;
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("Back")
|
||||||
|
color: Branding.styleString( !backArea.enabled ? Branding.SidebarBackground : (mouseBack.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText ));
|
||||||
|
font.pointSize : 8
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
source: "pan-start-symbolic.svg"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset : 18
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
height: 32
|
||||||
|
opacity: backArea.enabled ? 1 : 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: { ViewManager.back(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: nextArea
|
||||||
|
Layout.preferredHeight: parent.height / 7;
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: mouseNext.containsMouse ? "#f4f5f6" : "#e6e9ea";
|
||||||
|
enabled: ViewManager.nextEnabled;
|
||||||
|
visible: ViewManager.backAndNextVisible;
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseNext
|
||||||
|
anchors.fill: parent;
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("Next")
|
||||||
|
color: Branding.styleString( !nextArea.enabled ? Branding.SidebarBackground : (mouseNext.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText ));
|
||||||
|
font.pointSize : 8
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
source: "pan-end-symbolic.svg"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset : 18
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
height: 32
|
||||||
|
opacity: nextArea.enabled ? 1 : 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: { ViewManager.next(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: cancelArea
|
||||||
|
height: parent.height / 7;
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: mouseCancel.containsMouse ? "#e6e9ea" : "#d9dcde";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ViewManager has settings -- user-controlled via the
|
||||||
|
* branding component, and party based on program state --
|
||||||
|
* whether the quit button should be enabled and visible.
|
||||||
|
*
|
||||||
|
* QML navigation *should* follow this pattern, but can also
|
||||||
|
* add other qualifications. For instance, you may have a
|
||||||
|
* "finished" module that handles quit in its own way, and
|
||||||
|
* want to hide the quit button then. The ViewManager has a
|
||||||
|
* current step and a total count, so compare them:
|
||||||
|
*
|
||||||
|
* visible: ViewManager.quitVisible && ( ViewManager.currentStepIndex < ViewManager.rowCount()-1);
|
||||||
|
*/
|
||||||
|
|
||||||
|
enabled: ViewManager.quitEnabled;
|
||||||
|
visible: ViewManager.quitVisible && ( ViewManager.currentStepIndex < ViewManager.rowCount()-1);
|
||||||
|
|
||||||
|
ToolTip {
|
||||||
|
width: 59
|
||||||
|
visible: mouseCancel.containsMouse
|
||||||
|
timeout: 5000
|
||||||
|
delay: 1000
|
||||||
|
text: ViewManager.quitTooltip;
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseCancel
|
||||||
|
anchors.fill: parent;
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
color: Branding.styleString( !cancelArea.enabled ? Branding.SidebarBackground : (mouseCancel.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarText ));
|
||||||
|
font.pointSize : 8
|
||||||
|
}
|
||||||
|
Image {
|
||||||
|
source: "draw-rectangle.svg"
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.verticalCenterOffset : 18
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
height: 9
|
||||||
|
opacity: cancelArea.enabled ? 1 : 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: { ViewManager.quit(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: debugArea
|
||||||
|
Layout.fillWidth: true;
|
||||||
|
height: 35
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||||
|
color: Branding.styleString( mouseAreaDebug.containsMouse ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground);
|
||||||
|
visible: debug.enabled
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseAreaDebug
|
||||||
|
anchors.fill: parent;
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("Debug")
|
||||||
|
color: Branding.styleString( mouseAreaDebug.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarBackground );
|
||||||
|
font.pointSize : 8
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: debug.toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: aboutArea
|
||||||
|
Layout.fillWidth: true;
|
||||||
|
height: 35
|
||||||
|
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
|
||||||
|
color: Branding.styleString( mouseAreaAbout.containsMouse ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground);
|
||||||
|
visible: true
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseAreaAbout
|
||||||
|
anchors.fill: parent;
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
hoverEnabled: true
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: qsTr("About")
|
||||||
|
ToolTip {
|
||||||
|
visible: mouseAreaAbout.containsMouse
|
||||||
|
delay: 1000
|
||||||
|
text: qsTr("Info about Calamares")
|
||||||
|
}
|
||||||
|
color: Branding.styleString( mouseAreaAbout.containsMouse ? Branding.SidebarTextCurrent : Branding.SidebarBackgroundCurrent );
|
||||||
|
font.pointSize : 8
|
||||||
|
}
|
||||||
|
|
||||||
|
property variant window;
|
||||||
|
onClicked: {
|
||||||
|
var component = Qt.createComponent("about.qml");
|
||||||
|
window = component.createObject();
|
||||||
|
window.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
branding/kaos_branding/calamares-sidebar.qml
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/* Sample of QML progress tree.
|
||||||
|
|
||||||
|
SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
|
SPDX-FileCopyrightText: 2021 - 2022 Anke Boersma <demm@kaosx.us>
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
|
The progress tree (actually a list) is "horizontal" in this example,
|
||||||
|
with the steps going to the right.
|
||||||
|
*/
|
||||||
|
import io.calamares.ui 1.0
|
||||||
|
import io.calamares.core 1.0
|
||||||
|
|
||||||
|
import QtQuick 2.3
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: sideBar;
|
||||||
|
color: Branding.styleString( Branding.SidebarBackground );
|
||||||
|
height: 48;
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent;
|
||||||
|
spacing: 2;
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: ViewManager
|
||||||
|
Rectangle {
|
||||||
|
Layout.leftMargin: 0;
|
||||||
|
Layout.fillWidth: true;
|
||||||
|
Layout.alignment: Qt.AlignTop;
|
||||||
|
height: 42;
|
||||||
|
radius: 0;
|
||||||
|
color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarBackgroundCurrent : Branding.SidebarBackground );
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter;
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
x: parent.x + 12;
|
||||||
|
color: Branding.styleString( index == ViewManager.currentStepIndex ? Branding.SidebarTextCurrent : Branding.SidebarText );
|
||||||
|
text: display;
|
||||||
|
font.pointSize : index == ViewManager.currentStepIndex ? 10 : 9
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
height: 2
|
||||||
|
width: 800
|
||||||
|
anchors.bottom: parent.bottom;
|
||||||
|
border.color: Branding.styleString(ViewManager.currentStepIndex === index ? Branding.SidebarTextCurrent : (ViewManager.currentStepIndex >= index ? Branding.SidebarTextCurrent : Branding.SidebarBackgroundCurrent))
|
||||||
|
border.width: 3
|
||||||
|
|
||||||
|
Image {
|
||||||
|
source: "pan-up-symbolic.svg"
|
||||||
|
id: image
|
||||||
|
anchors.verticalCenter: parent.verticalCenter;
|
||||||
|
anchors.verticalCenterOffset : -3
|
||||||
|
x: parent.x + 35;
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
height: 32
|
||||||
|
visible: index == ViewManager.currentStepIndex ? true : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
branding/kaos_branding/draw-rectangle.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22"><path d="m2 1034.36v16h16v-16z" fill="#566060" transform="translate(1-1031.36)"/></svg>
|
||||||
|
After Width: | Height: | Size: 147 B |
@@ -1,3 +1,6 @@
|
|||||||
|
# SPDX-FileCopyrightText: no
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
#
|
||||||
foreach( lang ast ca cs de en es es_AR fr hu id_ID nl_NL pl pt_BR pt_PT ro_RO ru sr_RS tr_TR zh_CN )
|
foreach( lang ast ca cs de en es es_AR fr hu id_ID nl_NL pl pt_BR pt_PT ro_RO ru sr_RS tr_TR zh_CN )
|
||||||
list( APPEND TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/calamares-${COMPONENT_NAME}_${lang}.ts" )
|
list( APPEND TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/calamares-${COMPONENT_NAME}_${lang}.ts" )
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 292 KiB After Width: | Height: | Size: 106 KiB |
15
branding/kaos_branding/pan-end-symbolic.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||||
|
<svg height="16" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" version="1.1" width="16" xmlns="http://www.w3.org/2000/svg" enable-background="new">
|
||||||
|
<metadata id="metadata90"/>
|
||||||
|
<defs id="defs7386">
|
||||||
|
<linearGradient id="linearGradient5606" osb:paint="solid">
|
||||||
|
<stop id="stop5608"/>
|
||||||
|
</linearGradient>
|
||||||
|
<filter inkscape:collect="always" color-interpolation-filters="sRGB" id="filter7554">
|
||||||
|
<feBlend inkscape:collect="always" id="feBlend7556" in2="BackgroundImage" mode="darken"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<g inkscape:groupmode="layer" id="layer12" inkscape:label="actions" transform="translate(-445.0002,-129)">
|
||||||
|
<path inkscape:connector-curvature="0" d="m 451.0002,142 5,-5 -5,-5 z" id="path6412" sodipodi:nodetypes="cccc" fill="#555555"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 896 B |
15
branding/kaos_branding/pan-start-symbolic.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||||
|
<svg height="16" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" version="1.1" width="16" xmlns="http://www.w3.org/2000/svg" enable-background="new">
|
||||||
|
<metadata id="metadata90"/>
|
||||||
|
<defs id="defs7386">
|
||||||
|
<linearGradient id="linearGradient5606" osb:paint="solid">
|
||||||
|
<stop id="stop5608"/>
|
||||||
|
</linearGradient>
|
||||||
|
<filter inkscape:collect="always" color-interpolation-filters="sRGB" id="filter7554">
|
||||||
|
<feBlend inkscape:collect="always" id="feBlend7556" in2="BackgroundImage" mode="darken"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<g inkscape:groupmode="layer" id="layer12" inkscape:label="actions" transform="translate(-425.0002,-129)">
|
||||||
|
<path inkscape:connector-curvature="0" d="m 435.0002,142 -5,-5 5,-5 z" id="path6400-8" sodipodi:nodetypes="cccc" fill="#555555"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 898 B |
15
branding/kaos_branding/pan-up-symbolic.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||||
|
<svg height="16" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" version="1.1" width="16" xmlns="http://www.w3.org/2000/svg" enable-background="new">
|
||||||
|
<metadata id="metadata90"/>
|
||||||
|
<defs id="defs7386">
|
||||||
|
<linearGradient id="linearGradient5606" osb:paint="solid">
|
||||||
|
<stop id="stop5608"/>
|
||||||
|
</linearGradient>
|
||||||
|
<filter inkscape:collect="always" color-interpolation-filters="sRGB" id="filter7554">
|
||||||
|
<feBlend inkscape:collect="always" id="feBlend7556" in2="BackgroundImage" mode="darken"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
<g inkscape:groupmode="layer" id="layer12" inkscape:label="actions" transform="translate(-465.0002,-129.00001)">
|
||||||
|
<path inkscape:connector-curvature="0" d="m 478.0002,139 -5,-5 -5,5 z" id="path6418" sodipodi:nodetypes="cccc" fill="#3498DB"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 902 B |
@@ -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 2015, Teo Mrnjavac <teo@kde.org>
|
* Copyright 2015, Teo Mrnjavac <teo@kde.org>
|
||||||
|
* Copyright 2015-2018, Anke Boersma <demm@kaosx.us>
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@@ -24,13 +25,12 @@ Presentation
|
|||||||
id: presentation
|
id: presentation
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: advanceTimer
|
|
||||||
interval: 5000
|
interval: 5000
|
||||||
running: false
|
running: false
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: presentation.goToNextSlide()
|
onTriggered: presentation.goToNextSlide()
|
||||||
}
|
}
|
||||||
|
|
||||||
Slide {
|
Slide {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ Presentation
|
|||||||
id: background
|
id: background
|
||||||
source: "1.svg"
|
source: "1.svg"
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
anchors.verticalCenterOffset: 0
|
anchors.verticalCenterOffset: 0
|
||||||
@@ -96,15 +96,15 @@ Presentation
|
|||||||
anchors.horizontalCenterOffset: -100
|
anchors.horizontalCenterOffset: -100
|
||||||
font.pixelSize: parent.width *.015
|
font.pixelSize: parent.width *.015
|
||||||
color: 'white'
|
color: 'white'
|
||||||
text: qsTr("The default Office Suite is Calligra.<br/>"+
|
text: qsTr("The default Office Suite is LibreOffice.<br/>"+
|
||||||
"LibreOffice is available in the repositories. <br/>")
|
"Calligra is available in the repositories. <br/>")
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
width: 450
|
width: 450
|
||||||
horizontalAlignment: Text.AlignLeft
|
horizontalAlignment: Text.AlignLeft
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Slide {
|
Slide {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ Presentation
|
|||||||
font.pixelSize: parent.width *.015
|
font.pixelSize: parent.width *.015
|
||||||
color: 'white'
|
color: 'white'
|
||||||
text: qsTr("Qt/KDE specific internet applications include the <br/>"+
|
text: qsTr("Qt/KDE specific internet applications include the <br/>"+
|
||||||
"Qupzilla web-browser and kde-telepathy for <br/>"+
|
"Falkon web-browser and kde-telepathy for <br/>"+
|
||||||
"chat and Instant Messaging. <br/>")
|
"chat and Instant Messaging. <br/>")
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
width: 450
|
width: 450
|
||||||
@@ -128,7 +128,7 @@ Presentation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Slide {
|
Slide {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ Presentation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Slide {
|
Slide {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
@@ -172,6 +172,4 @@ Presentation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: advanceTimer.running = true
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
# NOTE: this is largely a copy of the release script for Calamares,
|
# NOTE: this is largely a copy of the release script for Calamares,
|
||||||
# with not-applicable parts (such as translation-freeze) either
|
# with not-applicable parts (such as translation-freeze) either
|
||||||
# commented-out, or skipped with if(false).
|
# commented-out, or skipped with if(false).
|
||||||
# NOTE: this script contains Linuxisms (in particular, expects GNU mktemp(1))
|
# NOTE: this script may contain Linuxisms
|
||||||
#
|
#
|
||||||
# This attempts to perform the different steps of the RELEASE.md
|
# This attempts to perform the different steps of the RELEASE.md
|
||||||
# document automatically. It's not tested on other machines or
|
# document automatically. It's not tested on other machines or
|
||||||
@@ -93,7 +93,7 @@ fi
|
|||||||
### Setup
|
### Setup
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
BUILDDIR=$(mktemp -d --suffix=-build --tmpdir=.)
|
BUILDDIR=$(mktemp -d -p . -t build.XXXXX)
|
||||||
|
|
||||||
### Build with default compiler
|
### Build with default compiler
|
||||||
#
|
#
|
||||||
@@ -140,30 +140,34 @@ fi
|
|||||||
### Get version number for this release
|
### Get version number for this release
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
V=$( cd "$BUILDDIR" && make show-version | grep ^CALAMARES_VERSION | sed s/^[A-Z_]*=// )
|
V=$( cmake -DVERSION_STYLE=short -P CMakeLists.txt 2>&1 )
|
||||||
test -n "$V" || { echo "Could not obtain version in $BUILDDIR ." ; exit 1 ; }
|
test -n "$V" || { echo "Could not obtain version in $BUILDDIR ." ; exit 1 ; }
|
||||||
|
|
||||||
### Create signed tag
|
### Create signed tag
|
||||||
#
|
#
|
||||||
# This is the signing key ID associated with the GitHub account adriaandegroot,
|
# This is the signing key ID associated with the GitHub account adriaandegroot,
|
||||||
# which is used to create all "verified" tags in the Calamares repo.
|
# which is used to create all "verified" tags in the Calamares repo.
|
||||||
KEY_ID="CFDDC96F12B1915C"
|
#
|
||||||
|
KEY_ID="328D742D8807A435"
|
||||||
git tag -u "$KEY_ID" -m "Release v$V" "v$V" || { echo "Could not sign tag v$V." ; exit 1 ; }
|
git tag -u "$KEY_ID" -m "Release v$V" "v$V" || { echo "Could not sign tag v$V." ; exit 1 ; }
|
||||||
|
|
||||||
### Create the tarball
|
### Create the tarball
|
||||||
#
|
#
|
||||||
|
# Create the tarball, compute SHA256 for later reporting, and
|
||||||
|
# sign the tarball so the signature can be uploaded separately.
|
||||||
#
|
#
|
||||||
TAR_V="$TARBALL_PREFIX-$V"
|
TAR_V="$TARBALL_PREFIX-$V"
|
||||||
TAR_FILE="$TAR_V.tar.gz"
|
TAR_FILE="$TAR_V.tar.gz"
|
||||||
git archive -o "$TAR_FILE" --prefix "$TAR_V/" "v$V" || { echo "Could not create tarball." ; exit 1 ; }
|
git archive -o "$TAR_FILE" --prefix "$TAR_V/" "v$V" || { echo "Could not create tarball." ; exit 1 ; }
|
||||||
test -f "$TAR_FILE" || { echo "Tarball was not created." ; exit 1 ; }
|
test -f "$TAR_FILE" || { echo "Tarball was not created." ; exit 1 ; }
|
||||||
SHA256=$(sha256sum "$TAR_FILE" | cut -d" " -f1)
|
SHA256=$(sha256sum "$TAR_FILE" | cut -d" " -f1)
|
||||||
|
gpg -s -u $KEY_ID --detach --armor $TAR_FILE # Sign the tarball
|
||||||
|
|
||||||
### Build the tarball
|
### Build the tarball
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
D=$(date +%Y%m%d-%H%M%S)
|
D=$(date +%Y%m%d-%H%M%S)
|
||||||
TMPDIR=$(mktemp -d --suffix="-calamares-$D")
|
TMPDIR=$(mktemp -d -p . -t calamares.XXXXX)
|
||||||
test -d "$TMPDIR" || { echo "Could not create tarball-build directory." ; exit 1 ; }
|
test -d "$TMPDIR" || { echo "Could not create tarball-build directory." ; exit 1 ; }
|
||||||
tar xzf "$TAR_FILE" -C "$TMPDIR" || { echo "Could not unpack tarball." ; exit 1 ; }
|
tar xzf "$TAR_FILE" -C "$TMPDIR" || { echo "Could not unpack tarball." ; exit 1 ; }
|
||||||
test -d "$TMPDIR/$TAR_V" || { echo "Tarball did not contain source directory." ; exit 1 ; }
|
test -d "$TMPDIR/$TAR_V" || { echo "Tarball did not contain source directory." ; exit 1 ; }
|
||||||
@@ -183,7 +187,6 @@ rm -rf "$TMPDIR" # From tarball
|
|||||||
cat <<EOF
|
cat <<EOF
|
||||||
# Next steps for this release:
|
# Next steps for this release:
|
||||||
git push origin v$V
|
git push origin v$V
|
||||||
gpg -s -u $KEY_ID --detach --armor $TAR_FILE # Sign the tarball
|
|
||||||
# Upload tarball $TAR_FILE and the signature $TAR_FILE.asc
|
# Upload tarball $TAR_FILE and the signature $TAR_FILE.asc
|
||||||
# Announce via https://github.com/calamares/$PROJECT_NAME/releases/new
|
# Announce via https://github.com/calamares/$PROJECT_NAME/releases/new
|
||||||
# SHA256: $SHA256
|
# SHA256: $SHA256
|
||||||
|
|||||||
@@ -5,12 +5,7 @@
|
|||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
#
|
#
|
||||||
# Calls astyle with settings matching Calamares coding style
|
# Calls astyle with settings matching Calamares coding style
|
||||||
# Requires astyle >= 2.04 and clang-format-7 -8 or -9
|
# Requires astyle >= 2.04 and clang-format-8 or later
|
||||||
#
|
|
||||||
# Clang-format-10 is **not** supported, since it changes a default
|
|
||||||
# that re-introduces a space into empty function bodies; this
|
|
||||||
# can be turned off with a style setting, but that breaks
|
|
||||||
# older format versions which don't recognize the setting.
|
|
||||||
#
|
#
|
||||||
# You can pass in directory names, in which case the files
|
# You can pass in directory names, in which case the files
|
||||||
# in that directory (NOT below it) are processed.
|
# in that directory (NOT below it) are processed.
|
||||||
@@ -20,9 +15,16 @@ LC_ALL=C
|
|||||||
LC_NUMERIC=C
|
LC_NUMERIC=C
|
||||||
export LANG LC_ALL LC_NUMERIC
|
export LANG LC_ALL LC_NUMERIC
|
||||||
|
|
||||||
|
BASEDIR=$(dirname $0)
|
||||||
|
TOPDIR=$( cd $BASEDIR/.. && pwd -P )
|
||||||
|
test -d "$BASEDIR" || { echo "! Could not determine base for $0" ; exit 1 ; }
|
||||||
|
test -d "$TOPDIR" || { echo "! Cound not determine top-level source dir" ; exit 1 ; }
|
||||||
|
test -f "$TOPDIR/.clang-format.base" || { echo "! No .clang-format support files in $TOPDIR" ; exit 1 ; }
|
||||||
|
|
||||||
AS=$( which astyle )
|
AS=$( which astyle )
|
||||||
|
|
||||||
CF_VERSIONS="clang-format-7 clang-format-8 clang-format70 clang-format80 clang-format90 clang-format-9.0.1 clang-format"
|
# Allow specifying CF_VERSIONS outside already
|
||||||
|
CF_VERSIONS="$CF_VERSIONS clang-format-8 clang-format80 clang-format90 clang-format-9.0.1 clang-format"
|
||||||
for _cf in $CF_VERSIONS
|
for _cf in $CF_VERSIONS
|
||||||
do
|
do
|
||||||
# Not an error if this particular clang-format isn't found
|
# Not an error if this particular clang-format isn't found
|
||||||
@@ -35,14 +37,39 @@ test -n "$CF" || { echo "! No clang-format ($CF_VERSIONS) found in PATH"; exit 1
|
|||||||
test -x "$AS" || { echo "! $AS is not executable."; exit 1 ; }
|
test -x "$AS" || { echo "! $AS is not executable."; exit 1 ; }
|
||||||
test -x "$CF" || { echo "! $CF is not executable."; exit 1 ; }
|
test -x "$CF" || { echo "! $CF is not executable."; exit 1 ; }
|
||||||
|
|
||||||
unmangle_clang_format=""
|
### CLANG-FORMAT-WRANGLING
|
||||||
if expr `"$CF" --version | tr -dc '[^.0-9]' | cut -d . -f 1` '<' 10 > /dev/null ; then
|
#
|
||||||
:
|
# Version 7 and earlier doesn't understand all the options we would like
|
||||||
else
|
# Version 8 is ok
|
||||||
unmangle_clang_format=$( dirname $0 )/../.clang-format
|
# Version 9 is ok
|
||||||
echo "SpaceInEmptyBlock: false" >> "$unmangle_clang_format"
|
# Later versions change some defaults so need extra wrangling.
|
||||||
fi
|
# .. there are extra files that are appended to the settings, per
|
||||||
|
# .. clang-format version.
|
||||||
|
|
||||||
|
format_version=`"$CF" --version | tr -dc '[^.0-9]' | cut -d . -f 1`
|
||||||
|
case "$format_version" in
|
||||||
|
[0-7] )
|
||||||
|
echo "! Clang-format version 8+ required"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
[89] )
|
||||||
|
:
|
||||||
|
;;
|
||||||
|
* )
|
||||||
|
echo "! Clang-format version '$format_version' unsupported."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
_fmt="$TOPDIR/.clang-format"
|
||||||
|
cp "$_fmt.base" "$_fmt"
|
||||||
|
for f in "$extra_settings" ; do
|
||||||
|
test -f "$_fmt.$f" && cat "$_fmt.$f" >> "$_fmt"
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
### FILE PROCESSING
|
||||||
|
#
|
||||||
|
#
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
any_dirs=no
|
any_dirs=no
|
||||||
@@ -54,7 +81,7 @@ done
|
|||||||
style_some()
|
style_some()
|
||||||
{
|
{
|
||||||
if test -n "$*" ; then
|
if test -n "$*" ; then
|
||||||
$AS --options=$(dirname $0)/astylerc --quiet "$@"
|
$AS --options=$BASEDIR/astylerc --quiet "$@"
|
||||||
$CF -i -style=file "$@"
|
$CF -i -style=file "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -72,6 +99,7 @@ else
|
|||||||
style_some "$@"
|
style_some "$@"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test -n "$unmangle_clang_format" ; then
|
### CLANG-FORMAT-WRANGLING
|
||||||
sed -i.bak '/^SpaceInEmptyBlock/d' "$unmangle_clang_format"
|
#
|
||||||
fi
|
# Restore the original .clang-format
|
||||||
|
cp "$_fmt.base" "$_fmt"
|
||||||
|
|||||||
75
modules/basestrap/basestrap.conf
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# SPDX-FileCopyrightText: no
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
#
|
||||||
|
# The configuration for the package manager starts with the
|
||||||
|
# *backend* key, which picks one of the backends to use.
|
||||||
|
# In `main.py` there is a base class `PackageManager`.
|
||||||
|
# Implementations must subclass that and set a (class-level)
|
||||||
|
# property *backend* to the name of the backend (e.g. "dummy").
|
||||||
|
# That property is used to match against the *backend* key here.
|
||||||
|
#
|
||||||
|
# You will have to add such a class for your package manager.
|
||||||
|
# It is fairly simple Python code. The API is described in the
|
||||||
|
# abstract methods in class `PackageManager`. Mostly, the only
|
||||||
|
# trick is to figure out the correct commands to use, and in particular,
|
||||||
|
# whether additional switches are required or not. Some package managers
|
||||||
|
# have more installer-friendly defaults than others, e.g., DNF requires
|
||||||
|
# passing --disablerepo=* -C to allow removing packages without Internet
|
||||||
|
# connectivity, and it also returns an error exit code if the package did
|
||||||
|
# not exist to begin with.
|
||||||
|
---
|
||||||
|
#
|
||||||
|
# Which package manager to use, options are:
|
||||||
|
# - pacman - Pacman
|
||||||
|
#
|
||||||
|
# Not actually a package manager, but suitable for testing:
|
||||||
|
# - dummy - Dummy manager, only logs
|
||||||
|
#
|
||||||
|
backend: dummy
|
||||||
|
|
||||||
|
# pacman specific options
|
||||||
|
#
|
||||||
|
# *num_retries* should be a positive integer which specifies the
|
||||||
|
# number of times the call to pacman will be retried in the event of a
|
||||||
|
# failure. If it is missing, it will be set to 0.
|
||||||
|
#
|
||||||
|
# *disable_download_timeout* is a boolean that, when true, includes
|
||||||
|
# the flag --disable-download-timeout on calls to pacman. When missing,
|
||||||
|
# false is assumed.
|
||||||
|
#
|
||||||
|
# *needed_only* is a boolean that includes the pacman argument --needed
|
||||||
|
# when set to true. If missing, false is assumed.
|
||||||
|
# *handle_keyrings* is a boolean that includes initializing and populating keyrings
|
||||||
|
# when set to true. If missing, false is assumed.
|
||||||
|
|
||||||
|
pacman:
|
||||||
|
num_retries: 0
|
||||||
|
disable_download_timeout: false
|
||||||
|
needed_only: false
|
||||||
|
handle_keyrings: false
|
||||||
|
copy_pacconf: false
|
||||||
|
requirements:
|
||||||
|
- name: /etc
|
||||||
|
mode: "0o755"
|
||||||
|
- name: /var
|
||||||
|
mode: "0o755"
|
||||||
|
- name: /var/cache
|
||||||
|
mode: "0o755"
|
||||||
|
- name: /var/cache/pacman
|
||||||
|
mode: "0o755"
|
||||||
|
- name: /var/cache/pacman/pkg
|
||||||
|
mode: "0o755"
|
||||||
|
- name: /var/lib
|
||||||
|
mode: "0o755"
|
||||||
|
- name: /var/lib/pacman
|
||||||
|
mode: "0o755"
|
||||||
|
keyrings:
|
||||||
|
- artix
|
||||||
|
|
||||||
|
# the artix base package allows selection of the init system tied to elogind
|
||||||
|
# this option is artix specific
|
||||||
|
# base_init: elogind
|
||||||
|
|
||||||
|
operations:
|
||||||
|
- install:
|
||||||
|
- base
|
||||||
552
modules/basestrap/main.py
Normal file
@@ -0,0 +1,552 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||||
|
# SPDX-FileCopyrightText: 2015-2017 Teo Mrnjavac <teo@kde.org>
|
||||||
|
# SPDX-FileCopyrightText: 2016-2017 Kyle Robbertze <kyle@aims.ac.za>
|
||||||
|
# SPDX-FileCopyrightText: 2017 Alf Gaida <agaida@siduction.org>
|
||||||
|
# SPDX-FileCopyrightText: 2018 Adriaan de Groot <groot@kde.org>
|
||||||
|
# SPDX-FileCopyrightText: 2018 Philip Müller <philm@manjaro.org>
|
||||||
|
# SPDX-FileCopyrightText: 2023 Artoo <artoo@artixlinux.org>
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
#
|
||||||
|
# Calamares is Free Software: see the License-Identifier above.
|
||||||
|
#
|
||||||
|
|
||||||
|
import abc
|
||||||
|
from string import Template
|
||||||
|
import os, shutil, subprocess, sys
|
||||||
|
|
||||||
|
import libcalamares
|
||||||
|
from libcalamares.utils import host_env_process_output, target_env_process_output
|
||||||
|
from libcalamares.utils import gettext_path, gettext_languages
|
||||||
|
from os.path import join
|
||||||
|
|
||||||
|
import gettext
|
||||||
|
_translation = gettext.translation("calamares-python",
|
||||||
|
localedir=gettext_path(),
|
||||||
|
languages=gettext_languages(),
|
||||||
|
fallback=True)
|
||||||
|
_ = _translation.gettext
|
||||||
|
_n = _translation.ngettext
|
||||||
|
|
||||||
|
|
||||||
|
total_packages = 0 # For the entire job
|
||||||
|
completed_packages = 0 # Done so far for this job
|
||||||
|
group_packages = 0 # One group of packages from an -install or -remove entry
|
||||||
|
|
||||||
|
# A PM object may set this to a string (take care of translations!)
|
||||||
|
# to override the string produced by pretty_status_message()
|
||||||
|
custom_status_message = None
|
||||||
|
|
||||||
|
INSTALL = object()
|
||||||
|
REMOVE = object()
|
||||||
|
mode_packages = None # Changes to INSTALL or REMOVE
|
||||||
|
|
||||||
|
|
||||||
|
def _change_mode(mode):
|
||||||
|
global mode_packages
|
||||||
|
mode_packages = mode
|
||||||
|
libcalamares.job.setprogress(completed_packages * 1.0 / total_packages)
|
||||||
|
|
||||||
|
|
||||||
|
def pretty_name():
|
||||||
|
return _("Install packages.")
|
||||||
|
|
||||||
|
|
||||||
|
def pretty_status_message():
|
||||||
|
if custom_status_message is not None:
|
||||||
|
return custom_status_message
|
||||||
|
if not group_packages:
|
||||||
|
if (total_packages > 0):
|
||||||
|
# Outside the context of an operation
|
||||||
|
s = _("Processing packages (%(count)d / %(total)d)")
|
||||||
|
else:
|
||||||
|
s = _("Install packages.")
|
||||||
|
|
||||||
|
elif mode_packages is INSTALL:
|
||||||
|
s = _n("Installing one package.",
|
||||||
|
"Installing %(num)d packages.", group_packages)
|
||||||
|
elif mode_packages is REMOVE:
|
||||||
|
s = _n("Removing one package.",
|
||||||
|
"Removing %(num)d packages.", group_packages)
|
||||||
|
else:
|
||||||
|
# No mode, generic description
|
||||||
|
s = _("Install packages.")
|
||||||
|
|
||||||
|
return s % {"num": group_packages,
|
||||||
|
"count": completed_packages,
|
||||||
|
"total": total_packages}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PackageManager(metaclass=abc.ABCMeta):
|
||||||
|
"""
|
||||||
|
Package manager base class. A subclass implements package management
|
||||||
|
for a specific backend, and must have a class property `backend`
|
||||||
|
with the string identifier for that backend.
|
||||||
|
|
||||||
|
Subclasses are collected below to populate the list of possible
|
||||||
|
backends.
|
||||||
|
"""
|
||||||
|
backend = None
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def install(self, pkgs, from_local=False):
|
||||||
|
"""
|
||||||
|
Install a list of packages (named) into the system.
|
||||||
|
Although this handles lists, in practice it is called
|
||||||
|
with one package at a time.
|
||||||
|
|
||||||
|
@param pkgs: list[str]
|
||||||
|
list of package names
|
||||||
|
@param from_local: bool
|
||||||
|
if True, then these are local packages (on disk) and the
|
||||||
|
pkgs names are paths.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def remove(self, pkgs):
|
||||||
|
"""
|
||||||
|
Removes packages.
|
||||||
|
|
||||||
|
@param pkgs: list[str]
|
||||||
|
list of package names
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def run(self, script):
|
||||||
|
if script != "":
|
||||||
|
host_env_process_output(script.split(" "))
|
||||||
|
|
||||||
|
def install_package(self, packagedata, from_local=False):
|
||||||
|
"""
|
||||||
|
Install a package from a single entry in the install list.
|
||||||
|
This can be either a single package name, or an object
|
||||||
|
with pre- and post-scripts. If @p packagedata is a dict,
|
||||||
|
it is assumed to follow the documented structure.
|
||||||
|
|
||||||
|
@param packagedata: str|dict
|
||||||
|
@param from_local: bool
|
||||||
|
see install.from_local
|
||||||
|
"""
|
||||||
|
if isinstance(packagedata, str):
|
||||||
|
self.install([packagedata], from_local=from_local)
|
||||||
|
else:
|
||||||
|
self.run(packagedata["pre-script"])
|
||||||
|
self.install([packagedata["package"]], from_local=from_local)
|
||||||
|
self.run(packagedata["post-script"])
|
||||||
|
|
||||||
|
def remove_package(self, packagedata):
|
||||||
|
"""
|
||||||
|
Remove a package from a single entry in the remove list.
|
||||||
|
This can be either a single package name, or an object
|
||||||
|
with pre- and post-scripts. If @p packagedata is a dict,
|
||||||
|
it is assumed to follow the documented structure.
|
||||||
|
|
||||||
|
@param packagedata: str|dict
|
||||||
|
"""
|
||||||
|
if isinstance(packagedata, str):
|
||||||
|
self.remove([packagedata])
|
||||||
|
else:
|
||||||
|
self.run(packagedata["pre-script"])
|
||||||
|
self.remove([packagedata["package"]])
|
||||||
|
self.run(packagedata["post-script"])
|
||||||
|
|
||||||
|
def operation_install(self, package_list, from_local=False):
|
||||||
|
"""
|
||||||
|
Installs the list of packages named in @p package_list .
|
||||||
|
These can be strings -- plain package names -- or
|
||||||
|
structures (with a pre- and post-install step).
|
||||||
|
|
||||||
|
This operation is called for "critical" packages,
|
||||||
|
which are expected to succeed, or fail, all together.
|
||||||
|
However, if there are packages with pre- or post-scripts,
|
||||||
|
then packages are installed one-by-one instead.
|
||||||
|
|
||||||
|
NOTE: package managers may reimplement this method
|
||||||
|
NOTE: exceptions are expected to leave this method, to indicate
|
||||||
|
failure of the installation.
|
||||||
|
"""
|
||||||
|
if all([isinstance(x, str) for x in package_list]):
|
||||||
|
self.install(package_list, from_local=from_local)
|
||||||
|
else:
|
||||||
|
for package in package_list:
|
||||||
|
self.install_package(package, from_local=from_local)
|
||||||
|
|
||||||
|
def operation_try_install(self, package_list):
|
||||||
|
"""
|
||||||
|
Installs the list of packages named in @p package_list .
|
||||||
|
These can be strings -- plain package names -- or
|
||||||
|
structures (with a pre- and post-install step).
|
||||||
|
|
||||||
|
This operation is called for "non-critical" packages,
|
||||||
|
which can succeed or fail without affecting the overall installation.
|
||||||
|
Packages are installed one-by-one to support package managers
|
||||||
|
that do not have a "install as much as you can" mode.
|
||||||
|
|
||||||
|
NOTE: package managers may reimplement this method
|
||||||
|
NOTE: no package-installation exceptions should be raised
|
||||||
|
"""
|
||||||
|
# we make a separate package manager call for each package so a
|
||||||
|
# single failing package won't stop all of them
|
||||||
|
for package in package_list:
|
||||||
|
try:
|
||||||
|
self.install_package(package)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
libcalamares.utils.warning("Could not install package %s" % package)
|
||||||
|
|
||||||
|
def operation_remove(self, package_list):
|
||||||
|
"""
|
||||||
|
Removes the list of packages named in @p package_list .
|
||||||
|
These can be strings -- plain package names -- or
|
||||||
|
structures (with a pre- and post-install step).
|
||||||
|
|
||||||
|
This operation is called for "critical" packages, which are
|
||||||
|
expected to succeed or fail all together.
|
||||||
|
However, if there are packages with pre- or post-scripts,
|
||||||
|
then packages are removed one-by-one instead.
|
||||||
|
|
||||||
|
NOTE: package managers may reimplement this method
|
||||||
|
NOTE: exceptions should be raised to indicate failure
|
||||||
|
"""
|
||||||
|
if all([isinstance(x, str) for x in package_list]):
|
||||||
|
self.remove(package_list)
|
||||||
|
else:
|
||||||
|
for package in package_list:
|
||||||
|
self.remove_package(package)
|
||||||
|
|
||||||
|
def operation_try_remove(self, package_list):
|
||||||
|
"""
|
||||||
|
Same relation as try_install has to install, except it removes
|
||||||
|
packages instead. Packages are removed one-by-one.
|
||||||
|
|
||||||
|
NOTE: package managers may reimplement this method
|
||||||
|
NOTE: no package-installation exceptions should be raised
|
||||||
|
"""
|
||||||
|
for package in package_list:
|
||||||
|
try:
|
||||||
|
self.remove_package(package)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
libcalamares.utils.warning("Could not remove package %s" % package)
|
||||||
|
|
||||||
|
### PACKAGE MANAGER IMPLEMENTATIONS
|
||||||
|
#
|
||||||
|
# Keep these alphabetical (presumably both by class name and backend name),
|
||||||
|
# even the Dummy implementation.
|
||||||
|
#
|
||||||
|
|
||||||
|
class PMPacman(PackageManager):
|
||||||
|
backend = "pacman"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
import re
|
||||||
|
progress_match = re.compile("^\\((\\d+)/(\\d+)\\)")
|
||||||
|
|
||||||
|
def line_cb(line):
|
||||||
|
if line.startswith(":: "):
|
||||||
|
self.in_package_changes = "package" in line or "hooks" in line
|
||||||
|
else:
|
||||||
|
if self.in_package_changes and line.endswith("...\n"):
|
||||||
|
# Update the message, untranslated; do not change the
|
||||||
|
# progress percentage, since there may be more "installing..."
|
||||||
|
# lines in the output for the group, than packages listed
|
||||||
|
# explicitly. We don't know how to calculate proper progress.
|
||||||
|
global custom_status_message
|
||||||
|
custom_status_message = "pacman: " + line.strip()
|
||||||
|
libcalamares.job.setprogress(self.progress_fraction)
|
||||||
|
libcalamares.utils.debug(line)
|
||||||
|
|
||||||
|
self.in_package_changes = False
|
||||||
|
self.line_cb = line_cb
|
||||||
|
|
||||||
|
pacman = libcalamares.job.configuration.get("pacman", None)
|
||||||
|
if pacman is None:
|
||||||
|
pacman = dict()
|
||||||
|
if type(pacman) is not dict:
|
||||||
|
libcalamares.utils.warning("Job configuration *pacman* will be ignored.")
|
||||||
|
pacman = dict()
|
||||||
|
self.pacman_num_retries = pacman.get("num_retries", 0)
|
||||||
|
self.pacman_disable_timeout = pacman.get("disable_download_timeout", False)
|
||||||
|
self.pacman_needed_only = pacman.get("needed_only", False)
|
||||||
|
self.pacman_key = pacman.get("handle_keyrings", False)
|
||||||
|
self.pacman_pacconf = pacman.get("copy_pacconf", False)
|
||||||
|
self.pacman_requirements = pacman.get("requirements", [])
|
||||||
|
self.pacman_keyrings = pacman.get("keyrings", [])
|
||||||
|
|
||||||
|
def reset_progress(self):
|
||||||
|
self.in_package_changes = False
|
||||||
|
# These are globals
|
||||||
|
self.progress_fraction = (completed_packages * 1.0 / total_packages)
|
||||||
|
|
||||||
|
def run_pacman(self, command, callback=False):
|
||||||
|
"""
|
||||||
|
Call pacman in a loop until it is successful or the number of retries is exceeded
|
||||||
|
:param command: The pacman command to run
|
||||||
|
:param callback: An optional boolean that indicates if this pacman run should use the callback
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
pacman_count = 0
|
||||||
|
while pacman_count <= self.pacman_num_retries:
|
||||||
|
pacman_count += 1
|
||||||
|
try:
|
||||||
|
if False: # callback:
|
||||||
|
host_env_process_output(command, self.line_cb)
|
||||||
|
else:
|
||||||
|
host_env_process_output(command)
|
||||||
|
|
||||||
|
return
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
if pacman_count <= self.pacman_num_retries:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def install(self, pkgs, from_local=False):
|
||||||
|
|
||||||
|
install_root = libcalamares.globalstorage.value("rootMountPoint")
|
||||||
|
|
||||||
|
cal_umask = os.umask(0)
|
||||||
|
for target in self.pacman_requirements:
|
||||||
|
dest = install_root + target["name"]
|
||||||
|
if not os.path.exists(dest):
|
||||||
|
mod = int(target["mode"],8)
|
||||||
|
os.mkdir(dest, mode=mod)
|
||||||
|
libcalamares.utils.debug("Mode: {!s}".format(oct(mod)))
|
||||||
|
libcalamares.utils.debug("Created: {!s}".format(dest))
|
||||||
|
|
||||||
|
path = join(install_root, "run")
|
||||||
|
os.chmod(path, 0o755)
|
||||||
|
os.umask(cal_umask)
|
||||||
|
|
||||||
|
f = "etc/resolv.conf"
|
||||||
|
if os.path.exists(join("/",f)):
|
||||||
|
shutil.copy2(join("/",f), join(install_root, f))
|
||||||
|
|
||||||
|
command = ["pacman"]
|
||||||
|
|
||||||
|
cachedir = join(install_root, "var/cache/pacman/pkg")
|
||||||
|
dbdir = join(install_root, "var/lib/pacman")
|
||||||
|
pacman_args = ["--root", install_root, "--dbpath", dbdir, "--cachedir", cachedir]
|
||||||
|
command.extend(pacman_args)
|
||||||
|
|
||||||
|
# Don't ask for user intervention, take the default action
|
||||||
|
command.append("--noconfirm")
|
||||||
|
|
||||||
|
# Don't report download progress for each file
|
||||||
|
command.append("--noprogressbar")
|
||||||
|
|
||||||
|
if self.pacman_needed_only is True:
|
||||||
|
command.append("--needed")
|
||||||
|
|
||||||
|
if self.pacman_disable_timeout is True:
|
||||||
|
command.append("--disable-download-timeout")
|
||||||
|
|
||||||
|
if from_local:
|
||||||
|
command.append("-U")
|
||||||
|
else:
|
||||||
|
command.append("-Sy")
|
||||||
|
|
||||||
|
command += pkgs
|
||||||
|
|
||||||
|
libcalamares.utils.debug("Command: {!s}".format(command))
|
||||||
|
|
||||||
|
self.reset_progress()
|
||||||
|
self.run_pacman(command, True)
|
||||||
|
|
||||||
|
if self.pacman_key:
|
||||||
|
self.init_keyring()
|
||||||
|
self.populate_keyring()
|
||||||
|
|
||||||
|
if self.pacman_pacconf:
|
||||||
|
f = "etc/pacman.conf"
|
||||||
|
if os.path.exists(join("/",f)):
|
||||||
|
shutil.copy2(join("/",f), join(install_root, f))
|
||||||
|
|
||||||
|
def remove(self, pkgs):
|
||||||
|
self.reset_progress()
|
||||||
|
self.run_pacman(["pacman", "-Rs", "--noconfirm"] + pkgs, True)
|
||||||
|
|
||||||
|
def init_keyring(self):
|
||||||
|
target_env_process_output(["pacman-key", "--init"])
|
||||||
|
|
||||||
|
def populate_keyring(self):
|
||||||
|
target_env_process_output(["pacman-key", "--populate"] + self.pacman_keyrings)
|
||||||
|
|
||||||
|
# Collect all the subclasses of PackageManager defined above,
|
||||||
|
# and index them based on the backend property of each class.
|
||||||
|
backend_managers = [
|
||||||
|
(c.backend, c)
|
||||||
|
for c in globals().values()
|
||||||
|
if type(c) is abc.ABCMeta and issubclass(c, PackageManager) and c.backend]
|
||||||
|
|
||||||
|
|
||||||
|
def subst_locale(plist):
|
||||||
|
"""
|
||||||
|
Returns a locale-aware list of packages, based on @p plist.
|
||||||
|
Package names that contain LOCALE are localized with the
|
||||||
|
BCP47 name of the chosen system locale; if the system
|
||||||
|
locale is 'en' (e.g. English, US) then these localized
|
||||||
|
packages are dropped from the list.
|
||||||
|
|
||||||
|
@param plist: list[str|dict]
|
||||||
|
Candidate packages to install.
|
||||||
|
@return: list[str|dict]
|
||||||
|
"""
|
||||||
|
locale = libcalamares.globalstorage.value("locale")
|
||||||
|
if not locale:
|
||||||
|
# It is possible to skip the locale-setting entirely.
|
||||||
|
# Then pretend it is "en", so that {LOCALE}-decorated
|
||||||
|
# package names are removed from the list.
|
||||||
|
locale = "en"
|
||||||
|
|
||||||
|
ret = []
|
||||||
|
for packagedata in plist:
|
||||||
|
if isinstance(packagedata, str):
|
||||||
|
packagename = packagedata
|
||||||
|
else:
|
||||||
|
packagename = packagedata["package"]
|
||||||
|
|
||||||
|
# Update packagename: substitute LOCALE, and drop packages
|
||||||
|
# if locale is en and LOCALE is in the package name.
|
||||||
|
if locale != "en":
|
||||||
|
packagename = Template(packagename).safe_substitute(LOCALE=locale)
|
||||||
|
elif 'LOCALE' in packagename:
|
||||||
|
packagename = None
|
||||||
|
|
||||||
|
if packagename is not None:
|
||||||
|
# Put it back in packagedata
|
||||||
|
if isinstance(packagedata, str):
|
||||||
|
packagedata = packagename
|
||||||
|
else:
|
||||||
|
packagedata["package"] = packagename
|
||||||
|
|
||||||
|
ret.append(packagedata)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def run_operations(pkgman, entry):
|
||||||
|
"""
|
||||||
|
Call package manager with suitable parameters for the given
|
||||||
|
package actions.
|
||||||
|
|
||||||
|
:param pkgman: PackageManager
|
||||||
|
This is the manager that does the actual work.
|
||||||
|
:param entry: dict
|
||||||
|
Keys are the actions -- e.g. "install" -- to take, and the values
|
||||||
|
are the (list of) packages to apply the action to. The actions are
|
||||||
|
not iterated in a specific order, so it is recommended to use only
|
||||||
|
one action per dictionary. The list of packages may be package
|
||||||
|
names (strings) or package information dictionaries with pre-
|
||||||
|
and post-scripts.
|
||||||
|
"""
|
||||||
|
global group_packages, completed_packages, mode_packages
|
||||||
|
|
||||||
|
for key in entry.keys():
|
||||||
|
package_list = subst_locale(entry[key])
|
||||||
|
group_packages = len(package_list)
|
||||||
|
if key == "install":
|
||||||
|
_change_mode(INSTALL)
|
||||||
|
pkgman.operation_install(package_list)
|
||||||
|
elif key == "try_install":
|
||||||
|
_change_mode(INSTALL)
|
||||||
|
pkgman.operation_try_install(package_list)
|
||||||
|
elif key == "remove":
|
||||||
|
_change_mode(REMOVE)
|
||||||
|
pkgman.operation_remove(package_list)
|
||||||
|
elif key == "try_remove":
|
||||||
|
_change_mode(REMOVE)
|
||||||
|
pkgman.operation_try_remove(package_list)
|
||||||
|
elif key == "localInstall":
|
||||||
|
_change_mode(INSTALL)
|
||||||
|
pkgman.operation_install(package_list, from_local=True)
|
||||||
|
elif key == "source":
|
||||||
|
libcalamares.utils.debug("Package-list from {!s}".format(entry[key]))
|
||||||
|
else:
|
||||||
|
libcalamares.utils.warning("Unknown package-operation key {!s}".format(key))
|
||||||
|
completed_packages += len(package_list)
|
||||||
|
libcalamares.job.setprogress(completed_packages * 1.0 / total_packages)
|
||||||
|
libcalamares.utils.debug("Pretty name: {!s}, setting progress..".format(pretty_name()))
|
||||||
|
|
||||||
|
group_packages = 0
|
||||||
|
_change_mode(None)
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
"""
|
||||||
|
Calls routine with detected package manager to install locale packages
|
||||||
|
or remove drivers not needed on the installed system.
|
||||||
|
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
global mode_packages, total_packages, completed_packages, group_packages
|
||||||
|
|
||||||
|
backend = libcalamares.job.configuration.get("backend")
|
||||||
|
|
||||||
|
for identifier, impl in backend_managers:
|
||||||
|
if identifier == backend:
|
||||||
|
pkgman = impl()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return "Bad backend", "backend=\"{}\"".format(backend)
|
||||||
|
|
||||||
|
if not libcalamares.globalstorage.value("hasInternet"):
|
||||||
|
libcalamares.utils.warning( "Package installation has been skipped: no internet" )
|
||||||
|
return None
|
||||||
|
|
||||||
|
operations = libcalamares.job.configuration.get("operations", [])
|
||||||
|
# if libcalamares.globalstorage.contains("packageOperations"):
|
||||||
|
# operations += libcalamares.globalstorage.value("packageOperations")
|
||||||
|
|
||||||
|
if libcalamares.job.configuration.get("base_init"):
|
||||||
|
base_init = libcalamares.job.configuration.get("base_init", None)
|
||||||
|
|
||||||
|
if libcalamares.globalstorage.contains("netinstallAdd"):
|
||||||
|
data = libcalamares.globalstorage.value("netinstallAdd")
|
||||||
|
init_provider = data[0]["name"]
|
||||||
|
libcalamares.utils.debug("Init provider: {!s}".format(init_provider))
|
||||||
|
|
||||||
|
if base_init is not None:
|
||||||
|
init_pkg = "-".join([base_init, init_provider])
|
||||||
|
libcalamares.utils.debug("Package added: {!s}".format(init_pkg))
|
||||||
|
operations[0]["install"].append(init_pkg)
|
||||||
|
|
||||||
|
if init_provider is not None:
|
||||||
|
libcalamares.globalstorage.insert("initProvider", init_provider)
|
||||||
|
|
||||||
|
libcalamares.globalstorage.insert("packageOperationsBasestrap", operations)
|
||||||
|
|
||||||
|
mode_packages = None
|
||||||
|
total_packages = 0
|
||||||
|
completed_packages = 0
|
||||||
|
for op in operations:
|
||||||
|
for packagelist in op.values():
|
||||||
|
total_packages += len(subst_locale(packagelist))
|
||||||
|
|
||||||
|
if not total_packages:
|
||||||
|
# Avoids potential divide-by-zero in progress reporting
|
||||||
|
return None
|
||||||
|
|
||||||
|
for entry in operations:
|
||||||
|
group_packages = 0
|
||||||
|
libcalamares.utils.debug(pretty_name())
|
||||||
|
try:
|
||||||
|
run_operations(pkgman, entry)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
libcalamares.utils.warning(str(e))
|
||||||
|
libcalamares.utils.debug("stdout:" + str(e.stdout))
|
||||||
|
libcalamares.utils.debug("stderr:" + str(e.stderr))
|
||||||
|
return (_("Package Manager error"),
|
||||||
|
_("The package manager could not make changes to the installed system. The command <pre>{!s}</pre> returned error code {!s}.")
|
||||||
|
.format(e.cmd, e.returncode))
|
||||||
|
|
||||||
|
mode_packages = None
|
||||||
|
|
||||||
|
libcalamares.job.setprogress(1.0)
|
||||||
|
|
||||||
|
return None
|
||||||
7
modules/basestrap/module.desc
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# SPDX-FileCopyrightText: no
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
---
|
||||||
|
type: "job"
|
||||||
|
name: "basestrap"
|
||||||
|
interface: "python"
|
||||||
|
script: "main.py"
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
# The FileKeeper plugin preserves files from the live system
|
|
||||||
# to the target system. It is particularly suited for copying
|
|
||||||
# the log file(s) for post-installation or post-mortem examination.
|
|
||||||
|
|
||||||
calamares_add_plugin( filekeeper
|
|
||||||
TYPE job
|
|
||||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
|
||||||
SOURCES
|
|
||||||
FileKeeper.cpp
|
|
||||||
SHARED_LIB
|
|
||||||
)
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
*
|
|
||||||
* Copyright 2018, 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 "FileKeeper.h"
|
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
#include <GlobalStorage.h>
|
|
||||||
#include <JobQueue.h>
|
|
||||||
|
|
||||||
#include <utils/Logger.h>
|
|
||||||
|
|
||||||
FileKeeperJob::FileKeeperJob( QObject* parent )
|
|
||||||
: Calamares::CppJob( parent )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FileKeeperJob::~FileKeeperJob() {}
|
|
||||||
|
|
||||||
|
|
||||||
QString
|
|
||||||
FileKeeperJob::prettyName() const
|
|
||||||
{
|
|
||||||
return tr( "File keeper Job" );
|
|
||||||
}
|
|
||||||
|
|
||||||
Calamares::JobResult
|
|
||||||
FileKeeperJob::exec()
|
|
||||||
{
|
|
||||||
return Calamares::JobResult::ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FileKeeperJob::setConfigurationMap( const QVariantMap& configurationMap )
|
|
||||||
{
|
|
||||||
Q_UNUSED( configurationMap );
|
|
||||||
}
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( FileKeeperJobFactory, registerPlugin< FileKeeperJob >(); )
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
*
|
|
||||||
* Copyright 2018, 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 FILEKEEPER_H
|
|
||||||
#define FILEKEEPER_H
|
|
||||||
|
|
||||||
#include <CppJob.h>
|
|
||||||
#include <DllMacro.h>
|
|
||||||
#include <utils/PluginFactory.h>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QVariantMap>
|
|
||||||
|
|
||||||
class PLUGINDLLEXPORT FileKeeperJob : public Calamares::CppJob
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit FileKeeperJob( QObject* parent = nullptr );
|
|
||||||
virtual ~FileKeeperJob() override;
|
|
||||||
|
|
||||||
QString prettyName() const override;
|
|
||||||
|
|
||||||
Calamares::JobResult exec() override;
|
|
||||||
|
|
||||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( FileKeeperJobFactory )
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
if( NOT Calamares_WITH_QML )
|
|
||||||
calamares_skip_module( "freebsddisk (QML is not supported in this build)" )
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
calamares_add_plugin( freebsddisk
|
|
||||||
TYPE viewmodule
|
|
||||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
|
||||||
SOURCES
|
|
||||||
FreeBSDDiskViewStep.cpp
|
|
||||||
RESOURCES
|
|
||||||
freebsddisk.qrc
|
|
||||||
SHARED_LIB
|
|
||||||
)
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
* License-Filename: LICENSES/GPL-3.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "FreeBSDDiskViewStep.h"
|
|
||||||
|
|
||||||
FreeBSDDiskViewStep::FreeBSDDiskViewStep( QObject* parent )
|
|
||||||
: Calamares::QmlViewStep( parent )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
FreeBSDDiskViewStep::~FreeBSDDiskViewStep() {}
|
|
||||||
|
|
||||||
QString
|
|
||||||
FreeBSDDiskViewStep::prettyName() const
|
|
||||||
{
|
|
||||||
return tr( "Disk Setup" );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
FreeBSDDiskViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
|
||||||
{
|
|
||||||
Calamares::QmlViewStep::setConfigurationMap( configurationMap ); // call parent implementation last
|
|
||||||
}
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( FreeBSDDiskViewStepFactory, registerPlugin< FreeBSDDiskViewStep >(); )
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
* License-Filename: LICENSES/GPL-3.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef FREEBSDDISKVIEWSTEP_H
|
|
||||||
#define FREEBSDDISKVIEWSTEP_H
|
|
||||||
|
|
||||||
#include "DllMacro.h"
|
|
||||||
#include "utils/PluginFactory.h"
|
|
||||||
#include "viewpages/QmlViewStep.h"
|
|
||||||
|
|
||||||
class PLUGINDLLEXPORT FreeBSDDiskViewStep : public Calamares::QmlViewStep
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
FreeBSDDiskViewStep( QObject* parent = nullptr );
|
|
||||||
virtual ~FreeBSDDiskViewStep() override;
|
|
||||||
|
|
||||||
QString prettyName() const override;
|
|
||||||
|
|
||||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( FreeBSDDiskViewStepFactory )
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
# The *freebsddisk* module can be used to pick a disk
|
|
||||||
# as an installer step. This module supports ZFSroot
|
|
||||||
# on one whole disk, and UFSroot on one whole disk.
|
|
||||||
#
|
|
||||||
---
|
|
||||||
qmlSearch: both
|
|
||||||
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
* License-Filename: LICENSES/GPL-3.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
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 {
|
|
||||||
Text {
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 10
|
|
||||||
text: "Select a disk on which to install FreeBSD."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<!DOCTYPE RCC><RCC version="1.0">
|
|
||||||
<qresource>
|
|
||||||
<file alias="freebsddisk.qml">freebsddisk.qml</file>
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
calamares_add_plugin( mobile
|
|
||||||
TYPE viewmodule
|
|
||||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
|
||||||
SOURCES
|
|
||||||
Config.cpp
|
|
||||||
MobileQmlViewStep.cpp
|
|
||||||
PartitionJob.cpp
|
|
||||||
UsersJob.cpp
|
|
||||||
RESOURCES
|
|
||||||
mobile.qrc
|
|
||||||
SHARED_LIB
|
|
||||||
)
|
|
||||||
@@ -1,198 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
#include "Config.h"
|
|
||||||
#include "PartitionJob.h"
|
|
||||||
#include "UsersJob.h"
|
|
||||||
|
|
||||||
#include "ViewManager.h"
|
|
||||||
#include "utils/Variant.h"
|
|
||||||
|
|
||||||
#include <QVariant>
|
|
||||||
|
|
||||||
Config::Config( QObject* parent )
|
|
||||||
: QObject( parent )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setConfigurationMap( const QVariantMap& cfgMap )
|
|
||||||
{
|
|
||||||
using namespace CalamaresUtils;
|
|
||||||
|
|
||||||
m_osName = getString( cfgMap, "osName", "(unknown)" );
|
|
||||||
m_arch = getString( cfgMap, "arch", "(unknown)" );
|
|
||||||
m_device = getString( cfgMap, "device", "(unknown)" );
|
|
||||||
m_userInterface = getString( cfgMap, "userInterface", "(unknown)" );
|
|
||||||
m_version = getString( cfgMap, "version", "(unknown)" );
|
|
||||||
m_username = getString( cfgMap, "username", "user" );
|
|
||||||
m_userPasswordNumeric = getBool( cfgMap, "userPasswordNumeric", true );
|
|
||||||
|
|
||||||
m_builtinVirtualKeyboard = getBool( cfgMap, "builtinVirtualKeyboard", true );
|
|
||||||
|
|
||||||
m_featureSshd = getBool( cfgMap, "featureSshd", true );
|
|
||||||
m_featureFsType = getBool( cfgMap, "featureFsType", false );
|
|
||||||
|
|
||||||
m_cmdLuksFormat = getString( cfgMap, "cmdLuksFormat", "cryptsetup luksFormat --use-random" );
|
|
||||||
m_cmdLuksOpen = getString( cfgMap, "cmdLuksOpen", "cryptsetup luksOpen" );
|
|
||||||
m_cmdMount = getString( cfgMap, "cmdMount", "mount" );
|
|
||||||
m_targetDeviceRoot = getString( cfgMap, "targetDeviceRoot", "/dev/unknown" );
|
|
||||||
m_targetDeviceRootInternal = getString( cfgMap, "targetDeviceRootInternal", "" );
|
|
||||||
|
|
||||||
m_cmdMkfsRootBtrfs = getString( cfgMap, "cmdMkfsRootBtrfs", "mkfs.btrfs -L 'unknownOS_root'" );
|
|
||||||
m_cmdMkfsRootExt4 = getString( cfgMap, "cmdMkfsRootExt4", "mkfs.ext4 -L 'unknownOS_root'" );
|
|
||||||
m_cmdMkfsRootF2fs = getString( cfgMap, "cmdMkfsRootF2fs", "mkfs.f2fs -l 'unknownOS_root'" );
|
|
||||||
m_fsList = getStringList( cfgMap, "fsModel", QStringList { "ext4", "f2fs", "btrfs" } );
|
|
||||||
m_defaultFs = getString( cfgMap, "defaultFs", "ext4" );
|
|
||||||
m_fsIndex = m_fsList.indexOf( m_defaultFs );
|
|
||||||
m_fsType = m_defaultFs;
|
|
||||||
|
|
||||||
m_cmdInternalStoragePrepare = getString( cfgMap, "cmdInternalStoragePrepare", "ondev-internal-storage-prepare" );
|
|
||||||
m_cmdPasswd = getString( cfgMap, "cmdPasswd", "passwd" );
|
|
||||||
m_cmdSshdEnable = getString( cfgMap, "cmdSshdEnable", "systemctl enable sshd.service" );
|
|
||||||
m_cmdSshdDisable = getString( cfgMap, "cmdSshdDisable", "systemctl disable sshd.service" );
|
|
||||||
m_cmdSshdUseradd = getString( cfgMap, "cmdSshdUseradd", "useradd -G wheel -m" );
|
|
||||||
}
|
|
||||||
|
|
||||||
Calamares::JobList
|
|
||||||
Config::createJobs()
|
|
||||||
{
|
|
||||||
QList< Calamares::job_ptr > list;
|
|
||||||
QString cmdSshd = m_isSshEnabled ? m_cmdSshdEnable : m_cmdSshdDisable;
|
|
||||||
|
|
||||||
/* Put users job in queue (should run after unpackfs) */
|
|
||||||
Calamares::Job* j = new UsersJob( m_featureSshd,
|
|
||||||
m_cmdPasswd,
|
|
||||||
cmdSshd,
|
|
||||||
m_cmdSshdUseradd,
|
|
||||||
m_isSshEnabled,
|
|
||||||
m_username,
|
|
||||||
m_userPassword,
|
|
||||||
m_sshdUsername,
|
|
||||||
m_sshdPassword );
|
|
||||||
list.append( Calamares::job_ptr( j ) );
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::runPartitionJobThenLeave( bool b )
|
|
||||||
{
|
|
||||||
Calamares::ViewManager* v = Calamares::ViewManager::instance();
|
|
||||||
QString cmdMkfsRoot;
|
|
||||||
if ( m_fsType == QStringLiteral( "btrfs" ) )
|
|
||||||
{
|
|
||||||
cmdMkfsRoot = m_cmdMkfsRootBtrfs;
|
|
||||||
}
|
|
||||||
else if ( m_fsType == QStringLiteral( "f2fs" ) )
|
|
||||||
{
|
|
||||||
cmdMkfsRoot = m_cmdMkfsRootF2fs;
|
|
||||||
}
|
|
||||||
else if ( m_fsType == QStringLiteral( "ext4" ) )
|
|
||||||
{
|
|
||||||
cmdMkfsRoot = m_cmdMkfsRootExt4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v->onInstallationFailed( "Unknown filesystem: '" + m_fsType + "'", "" );
|
|
||||||
}
|
|
||||||
/* HACK: run partition job
|
|
||||||
* The "mobile" module has two jobs, the partition job and the users job.
|
|
||||||
* If we added both of them in Config::createJobs(), Calamares would run
|
|
||||||
* them right after each other. But we need the "unpackfs" module to run
|
|
||||||
* inbetween, that's why as workaround, the partition job is started here.
|
|
||||||
* To solve this properly, we would need to place the partition job in an
|
|
||||||
* own module and pass everything via globalstorage. But then we might as
|
|
||||||
* well refactor everything so we can unify the mobile's partition job with
|
|
||||||
* the proper partition job from Calamares. */
|
|
||||||
Calamares::Job* j = new PartitionJob( m_cmdInternalStoragePrepare,
|
|
||||||
m_cmdLuksFormat,
|
|
||||||
m_cmdLuksOpen,
|
|
||||||
cmdMkfsRoot,
|
|
||||||
m_cmdMount,
|
|
||||||
m_targetDeviceRoot,
|
|
||||||
m_targetDeviceRootInternal,
|
|
||||||
m_installFromExternalToInternal,
|
|
||||||
m_isFdeEnabled,
|
|
||||||
m_fdePassword );
|
|
||||||
Calamares::JobResult res = j->exec();
|
|
||||||
|
|
||||||
if ( res )
|
|
||||||
{
|
|
||||||
v->next();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v->onInstallationFailed( res.message(), res.details() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setUserPassword( const QString& userPassword )
|
|
||||||
{
|
|
||||||
m_userPassword = userPassword;
|
|
||||||
emit userPasswordChanged( m_userPassword );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setSshdUsername( const QString& sshdUsername )
|
|
||||||
{
|
|
||||||
m_sshdUsername = sshdUsername;
|
|
||||||
emit sshdUsernameChanged( m_sshdUsername );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setSshdPassword( const QString& sshdPassword )
|
|
||||||
{
|
|
||||||
m_sshdPassword = sshdPassword;
|
|
||||||
emit sshdPasswordChanged( m_sshdPassword );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setIsSshEnabled( const bool isSshEnabled )
|
|
||||||
{
|
|
||||||
m_isSshEnabled = isSshEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setFdePassword( const QString& fdePassword )
|
|
||||||
{
|
|
||||||
m_fdePassword = fdePassword;
|
|
||||||
emit fdePasswordChanged( m_fdePassword );
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setIsFdeEnabled( const bool isFdeEnabled )
|
|
||||||
{
|
|
||||||
m_isFdeEnabled = isFdeEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setInstallFromExternalToInternal( const bool val )
|
|
||||||
{
|
|
||||||
m_installFromExternalToInternal = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setFsType( int idx )
|
|
||||||
{
|
|
||||||
if ( idx >= 0 && idx < m_fsList.length() )
|
|
||||||
{
|
|
||||||
setFsType( m_fsList[ idx ] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void
|
|
||||||
Config::setFsType( const QString& fsType )
|
|
||||||
{
|
|
||||||
if ( fsType != m_fsType )
|
|
||||||
{
|
|
||||||
m_fsType = fsType;
|
|
||||||
emit fsTypeChanged( m_fsType );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Config::setFsIndex( const int fsIndex )
|
|
||||||
{
|
|
||||||
m_fsIndex = fsIndex;
|
|
||||||
emit fsIndexChanged( m_fsIndex );
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Job.h"
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class Config : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
/* installer UI */
|
|
||||||
Q_PROPERTY( bool builtinVirtualKeyboard READ builtinVirtualKeyboard CONSTANT FINAL )
|
|
||||||
|
|
||||||
/* welcome */
|
|
||||||
Q_PROPERTY( QString osName READ osName CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString arch READ arch CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString device READ device CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString userInterface READ userInterface CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString version READ version CONSTANT FINAL )
|
|
||||||
|
|
||||||
/* default user */
|
|
||||||
Q_PROPERTY( QString username READ username CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString userPassword READ userPassword WRITE setUserPassword NOTIFY userPasswordChanged )
|
|
||||||
Q_PROPERTY( bool userPasswordNumeric READ userPasswordNumeric CONSTANT FINAL )
|
|
||||||
|
|
||||||
/* ssh server + credentials */
|
|
||||||
Q_PROPERTY( bool featureSshd READ featureSshd CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString sshdUsername READ sshdUsername WRITE setSshdUsername NOTIFY sshdUsernameChanged )
|
|
||||||
Q_PROPERTY( QString sshdPassword READ sshdPassword WRITE setSshdPassword NOTIFY sshdPasswordChanged )
|
|
||||||
Q_PROPERTY( bool isSshEnabled READ isSshEnabled WRITE setIsSshEnabled )
|
|
||||||
|
|
||||||
/* full disk encryption */
|
|
||||||
Q_PROPERTY( QString fdePassword READ fdePassword WRITE setFdePassword NOTIFY fdePasswordChanged )
|
|
||||||
Q_PROPERTY( bool isFdeEnabled READ isFdeEnabled WRITE setIsFdeEnabled )
|
|
||||||
|
|
||||||
/* filesystem selection */
|
|
||||||
Q_PROPERTY( QString fsType READ fsType WRITE setFsType NOTIFY fsTypeChanged )
|
|
||||||
Q_PROPERTY( bool featureFsType READ featureFsType CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QStringList fsList READ fsList CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString defaultFs READ defaultFs CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( int fsIndex READ fsIndex WRITE setFsIndex NOTIFY fsIndexChanged )
|
|
||||||
|
|
||||||
/* partition job */
|
|
||||||
Q_PROPERTY( bool runPartitionJobThenLeave READ runPartitionJobThenLeaveDummy WRITE runPartitionJobThenLeave )
|
|
||||||
Q_PROPERTY( QString cmdInternalStoragePrepare READ cmdInternalStoragePrepare CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString cmdLuksFormat READ cmdLuksFormat CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString cmdLuksOpen READ cmdLuksOpen CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString cmdMount READ cmdMount CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString targetDeviceRoot READ targetDeviceRoot CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString targetDeviceRootInternal READ targetDeviceRootInternal CONSTANT FINAL )
|
|
||||||
Q_PROPERTY(
|
|
||||||
bool installFromExternalToInternal READ installFromExternalToInternal WRITE setInstallFromExternalToInternal )
|
|
||||||
|
|
||||||
/* users job */
|
|
||||||
Q_PROPERTY( QString cmdSshdEnable READ cmdSshdEnable CONSTANT FINAL )
|
|
||||||
Q_PROPERTY( QString cmdSshdDisable READ cmdSshdDisable CONSTANT FINAL )
|
|
||||||
|
|
||||||
public:
|
|
||||||
Config( QObject* parent = nullptr );
|
|
||||||
void setConfigurationMap( const QVariantMap& );
|
|
||||||
Calamares::JobList createJobs();
|
|
||||||
|
|
||||||
/* installer UI */
|
|
||||||
bool builtinVirtualKeyboard() { return m_builtinVirtualKeyboard; }
|
|
||||||
|
|
||||||
/* welcome */
|
|
||||||
QString osName() const { return m_osName; }
|
|
||||||
QString arch() const { return m_arch; }
|
|
||||||
QString device() const { return m_device; }
|
|
||||||
QString userInterface() const { return m_userInterface; }
|
|
||||||
QString version() const { return m_version; }
|
|
||||||
|
|
||||||
/* default user */
|
|
||||||
QString username() const { return m_username; }
|
|
||||||
QString userPassword() const { return m_userPassword; }
|
|
||||||
void setUserPassword( const QString& userPassword );
|
|
||||||
bool userPasswordNumeric() const { return m_userPasswordNumeric; }
|
|
||||||
|
|
||||||
/* ssh server + credetials */
|
|
||||||
bool featureSshd() { return m_featureSshd; }
|
|
||||||
QString sshdUsername() const { return m_sshdUsername; }
|
|
||||||
QString sshdPassword() const { return m_sshdPassword; }
|
|
||||||
bool isSshEnabled() { return m_isSshEnabled; }
|
|
||||||
void setSshdUsername( const QString& sshdUsername );
|
|
||||||
void setSshdPassword( const QString& sshdPassword );
|
|
||||||
void setIsSshEnabled( bool isSshEnabled );
|
|
||||||
|
|
||||||
/* full disk encryption */
|
|
||||||
QString fdePassword() const { return m_fdePassword; }
|
|
||||||
bool isFdeEnabled() { return m_isFdeEnabled; }
|
|
||||||
void setFdePassword( const QString& fdePassword );
|
|
||||||
void setIsFdeEnabled( bool isFdeEnabled );
|
|
||||||
|
|
||||||
/* filesystem selection */
|
|
||||||
bool featureFsType() { return m_featureFsType; };
|
|
||||||
QString fsType() const { return m_fsType; };
|
|
||||||
void setFsType( int idx );
|
|
||||||
void setFsType( const QString& fsType );
|
|
||||||
QStringList fsList() const { return m_fsList; };
|
|
||||||
int fsIndex() const { return m_fsIndex; };
|
|
||||||
void setFsIndex( const int fsIndex );
|
|
||||||
QString defaultFs() const { return m_defaultFs; };
|
|
||||||
|
|
||||||
/* partition job */
|
|
||||||
bool runPartitionJobThenLeaveDummy() { return 0; }
|
|
||||||
void runPartitionJobThenLeave( bool b );
|
|
||||||
QString cmdInternalStoragePrepare() const { return m_cmdInternalStoragePrepare; }
|
|
||||||
QString cmdLuksFormat() const { return m_cmdLuksFormat; }
|
|
||||||
QString cmdLuksOpen() const { return m_cmdLuksOpen; }
|
|
||||||
QString cmdMkfsRootBtrfs() const { return m_cmdMkfsRootBtrfs; }
|
|
||||||
QString cmdMkfsRootExt4() const { return m_cmdMkfsRootExt4; }
|
|
||||||
QString cmdMkfsRootF2fs() const { return m_cmdMkfsRootF2fs; }
|
|
||||||
QString cmdMount() const { return m_cmdMount; }
|
|
||||||
QString targetDeviceRoot() const { return m_targetDeviceRoot; }
|
|
||||||
QString targetDeviceRootInternal() const { return m_targetDeviceRootInternal; }
|
|
||||||
bool installFromExternalToInternal() { return m_installFromExternalToInternal; }
|
|
||||||
void setInstallFromExternalToInternal( const bool val );
|
|
||||||
|
|
||||||
/* users job */
|
|
||||||
QString cmdPasswd() const { return m_cmdPasswd; }
|
|
||||||
QString cmdSshdEnable() const { return m_cmdSshdEnable; }
|
|
||||||
QString cmdSshdDisable() const { return m_cmdSshdDisable; }
|
|
||||||
QString cmdSshdUseradd() const { return m_cmdSshdUseradd; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
/* installer UI */
|
|
||||||
bool m_builtinVirtualKeyboard;
|
|
||||||
|
|
||||||
/* welcome */
|
|
||||||
QString m_osName;
|
|
||||||
QString m_arch;
|
|
||||||
QString m_device;
|
|
||||||
QString m_userInterface;
|
|
||||||
QString m_version;
|
|
||||||
|
|
||||||
/* default user */
|
|
||||||
QString m_username;
|
|
||||||
QString m_userPassword;
|
|
||||||
bool m_userPasswordNumeric;
|
|
||||||
|
|
||||||
/* ssh server + credentials */
|
|
||||||
bool m_featureSshd = false;
|
|
||||||
QString m_sshdUsername;
|
|
||||||
QString m_sshdPassword;
|
|
||||||
bool m_isSshEnabled = false;
|
|
||||||
|
|
||||||
/* full disk encryption */
|
|
||||||
QString m_fdePassword;
|
|
||||||
bool m_isFdeEnabled = false;
|
|
||||||
|
|
||||||
/* filesystem selection */
|
|
||||||
bool m_featureFsType = false;
|
|
||||||
QString m_defaultFs;
|
|
||||||
QString m_fsType;
|
|
||||||
// Index of the currently selected filesystem in UI.
|
|
||||||
int m_fsIndex = -1;
|
|
||||||
QStringList m_fsList;
|
|
||||||
|
|
||||||
/* partition job */
|
|
||||||
QString m_cmdInternalStoragePrepare;
|
|
||||||
QString m_cmdLuksFormat;
|
|
||||||
QString m_cmdLuksOpen;
|
|
||||||
QString m_cmdMkfsRootBtrfs;
|
|
||||||
QString m_cmdMkfsRootExt4;
|
|
||||||
QString m_cmdMkfsRootF2fs;
|
|
||||||
QString m_cmdMount;
|
|
||||||
QString m_targetDeviceRoot;
|
|
||||||
QString m_targetDeviceRootInternal;
|
|
||||||
bool m_installFromExternalToInternal = false;
|
|
||||||
|
|
||||||
/* users job */
|
|
||||||
QString m_cmdPasswd;
|
|
||||||
QString m_cmdSshdEnable;
|
|
||||||
QString m_cmdSshdDisable;
|
|
||||||
QString m_cmdSshdUseradd;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
/* booleans we don't read from QML (like isSshEnabled) don't need a signal */
|
|
||||||
|
|
||||||
/* default user */
|
|
||||||
void userPasswordChanged( QString userPassword );
|
|
||||||
|
|
||||||
/* ssh server + credentials */
|
|
||||||
void sshdUsernameChanged( QString sshdUsername );
|
|
||||||
void sshdPasswordChanged( QString sshdPassword );
|
|
||||||
|
|
||||||
/* full disk encryption */
|
|
||||||
void fdePasswordChanged( QString fdePassword );
|
|
||||||
|
|
||||||
void fsTypeChanged( QString fsType );
|
|
||||||
void fsIndexChanged( int fsIndex );
|
|
||||||
};
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
#include "MobileQmlViewStep.h"
|
|
||||||
|
|
||||||
#include "GlobalStorage.h"
|
|
||||||
|
|
||||||
#include "locale/LabelModel.h"
|
|
||||||
#include "utils/Dirs.h"
|
|
||||||
#include "utils/Logger.h"
|
|
||||||
#include "utils/Variant.h"
|
|
||||||
|
|
||||||
#include "Branding.h"
|
|
||||||
#include "modulesystem/ModuleManager.h"
|
|
||||||
|
|
||||||
#include <QProcess>
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( MobileQmlViewStepFactory, registerPlugin< MobileQmlViewStep >(); )
|
|
||||||
|
|
||||||
void
|
|
||||||
MobileQmlViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
|
||||||
{
|
|
||||||
m_config->setConfigurationMap( configurationMap );
|
|
||||||
Calamares::QmlViewStep::setConfigurationMap( configurationMap );
|
|
||||||
}
|
|
||||||
|
|
||||||
MobileQmlViewStep::MobileQmlViewStep( QObject* parent )
|
|
||||||
: Calamares::QmlViewStep( parent )
|
|
||||||
, m_config( new Config( this ) )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MobileQmlViewStep::onLeave()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
MobileQmlViewStep::isNextEnabled() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
MobileQmlViewStep::isBackEnabled() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
MobileQmlViewStep::isAtBeginning() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
MobileQmlViewStep::isAtEnd() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Calamares::JobList
|
|
||||||
MobileQmlViewStep::jobs() const
|
|
||||||
{
|
|
||||||
return m_config->createJobs();
|
|
||||||
}
|
|
||||||
|
|
||||||
QObject*
|
|
||||||
MobileQmlViewStep::getConfig()
|
|
||||||
{
|
|
||||||
return m_config;
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
#ifndef PARTITION_QMLVIEWSTEP_H
|
|
||||||
#define PARTITION_QMLVIEWSTEP_H
|
|
||||||
#include "Config.h"
|
|
||||||
|
|
||||||
#include "utils/PluginFactory.h"
|
|
||||||
#include "viewpages/QmlViewStep.h"
|
|
||||||
|
|
||||||
#include <DllMacro.h>
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QVariantMap>
|
|
||||||
|
|
||||||
class PLUGINDLLEXPORT MobileQmlViewStep : public Calamares::QmlViewStep
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit MobileQmlViewStep( QObject* parent = nullptr );
|
|
||||||
|
|
||||||
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;
|
|
||||||
void onLeave() override;
|
|
||||||
QObject* getConfig() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Config* m_config;
|
|
||||||
};
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( MobileQmlViewStepFactory )
|
|
||||||
|
|
||||||
#endif // PARTITION_QMLVIEWSTEP_H
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
#include "PartitionJob.h"
|
|
||||||
|
|
||||||
#include "GlobalStorage.h"
|
|
||||||
#include "JobQueue.h"
|
|
||||||
#include "Settings.h"
|
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
|
||||||
#include "utils/Logger.h"
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFileInfo>
|
|
||||||
|
|
||||||
|
|
||||||
PartitionJob::PartitionJob( const QString& cmdInternalStoragePrepare,
|
|
||||||
const QString& cmdLuksFormat,
|
|
||||||
const QString& cmdLuksOpen,
|
|
||||||
const QString& cmdMkfsRoot,
|
|
||||||
const QString& cmdMount,
|
|
||||||
const QString& targetDeviceRoot,
|
|
||||||
const QString& targetDeviceRootInternal,
|
|
||||||
bool installFromExternalToInternal,
|
|
||||||
bool isFdeEnabled,
|
|
||||||
const QString& password )
|
|
||||||
: Calamares::Job()
|
|
||||||
, m_cmdInternalStoragePrepare( cmdInternalStoragePrepare )
|
|
||||||
, m_cmdLuksFormat( cmdLuksFormat )
|
|
||||||
, m_cmdLuksOpen( cmdLuksOpen )
|
|
||||||
, m_cmdMkfsRoot( cmdMkfsRoot )
|
|
||||||
, m_cmdMount( cmdMount )
|
|
||||||
, m_targetDeviceRoot( targetDeviceRoot )
|
|
||||||
, m_targetDeviceRootInternal( targetDeviceRootInternal )
|
|
||||||
, m_installFromExternalToInternal( installFromExternalToInternal )
|
|
||||||
, m_isFdeEnabled( isFdeEnabled )
|
|
||||||
, m_password( password )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QString
|
|
||||||
PartitionJob::prettyName() const
|
|
||||||
{
|
|
||||||
return "Creating and formatting installation partition";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fill the "global storage", so the following jobs (like unsquashfs) work.
|
|
||||||
The code is similar to modules/partition/jobs/FillGlobalStorageJob.cpp in
|
|
||||||
Calamares. */
|
|
||||||
void
|
|
||||||
FillGlobalStorage( const QString device, const QString pathMount )
|
|
||||||
{
|
|
||||||
using namespace Calamares;
|
|
||||||
|
|
||||||
GlobalStorage* gs = JobQueue::instance()->globalStorage();
|
|
||||||
QVariantList partitions;
|
|
||||||
QVariantMap partition;
|
|
||||||
|
|
||||||
/* See mapForPartition() in FillGlobalStorageJob.cpp */
|
|
||||||
partition[ "device" ] = device;
|
|
||||||
partition[ "mountPoint" ] = "/";
|
|
||||||
partition[ "claimed" ] = true;
|
|
||||||
|
|
||||||
/* Ignored by calamares modules used in combination with the "mobile"
|
|
||||||
* module, so we can get away with leaving them empty for now. */
|
|
||||||
partition[ "uuid" ] = "";
|
|
||||||
partition[ "fsName" ] = "";
|
|
||||||
partition[ "fs" ] = "";
|
|
||||||
|
|
||||||
partitions << partition;
|
|
||||||
gs->insert( "partitions", partitions );
|
|
||||||
gs->insert( "rootMountPoint", pathMount );
|
|
||||||
}
|
|
||||||
|
|
||||||
Calamares::JobResult
|
|
||||||
PartitionJob::exec()
|
|
||||||
{
|
|
||||||
using namespace Calamares;
|
|
||||||
using namespace CalamaresUtils;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
const QString pathMount = "/mnt/install";
|
|
||||||
const QString cryptName = "calamares_crypt";
|
|
||||||
QString cryptDev = "/dev/mapper/" + cryptName;
|
|
||||||
QString passwordStdin = m_password + "\n";
|
|
||||||
QString dev = m_targetDeviceRoot;
|
|
||||||
QList< QPair< QStringList, QString > > commands = {};
|
|
||||||
|
|
||||||
if ( m_installFromExternalToInternal )
|
|
||||||
{
|
|
||||||
dev = m_targetDeviceRootInternal;
|
|
||||||
|
|
||||||
commands.append( {
|
|
||||||
{ { "sh", "-c", m_cmdInternalStoragePrepare }, QString() },
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
commands.append( { { { "mkdir", "-p", pathMount }, QString() } } );
|
|
||||||
|
|
||||||
if ( m_isFdeEnabled )
|
|
||||||
{
|
|
||||||
commands.append( {
|
|
||||||
{ { "sh", "-c", m_cmdLuksFormat + " " + dev }, passwordStdin },
|
|
||||||
{ { "sh", "-c", m_cmdLuksOpen + " " + dev + " " + cryptName }, passwordStdin },
|
|
||||||
{ { "sh", "-c", m_cmdMkfsRoot + " " + cryptDev }, QString() },
|
|
||||||
{ { "sh", "-c", m_cmdMount + " " + cryptDev + " " + pathMount }, QString() },
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
commands.append( { { { "sh", "-c", m_cmdMkfsRoot + " " + dev }, QString() },
|
|
||||||
{ { "sh", "-c", m_cmdMount + " " + dev + " " + pathMount }, QString() } } );
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ( auto command, commands )
|
|
||||||
{
|
|
||||||
const QStringList args = command.first;
|
|
||||||
const QString stdInput = command.second;
|
|
||||||
const QString pathRoot = "/";
|
|
||||||
|
|
||||||
ProcessResult res
|
|
||||||
= System::runCommand( System::RunLocation::RunInHost, args, pathRoot, stdInput, chrono::seconds( 120 ) );
|
|
||||||
if ( res.getExitCode() )
|
|
||||||
{
|
|
||||||
return JobResult::error( "Command failed:<br><br>"
|
|
||||||
"'"
|
|
||||||
+ args.join( " " )
|
|
||||||
+ "'<br><br>"
|
|
||||||
" with output:<br><br>"
|
|
||||||
"'"
|
|
||||||
+ res.getOutput() + "'" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FillGlobalStorage( m_isFdeEnabled ? cryptDev : dev, pathMount );
|
|
||||||
return JobResult::ok();
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
#pragma once
|
|
||||||
#include "Job.h"
|
|
||||||
|
|
||||||
|
|
||||||
class PartitionJob : public Calamares::Job
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
PartitionJob( const QString& cmdInternalStoragePrepare,
|
|
||||||
const QString& cmdLuksFormat,
|
|
||||||
const QString& cmdLuksOpen,
|
|
||||||
const QString& cmdMkfsRoot,
|
|
||||||
const QString& cmdMount,
|
|
||||||
const QString& targetDeviceRoot,
|
|
||||||
const QString& targetDeviceRootInternal,
|
|
||||||
bool installFromExternalToInternal,
|
|
||||||
bool isFdeEnabled,
|
|
||||||
const QString& password );
|
|
||||||
|
|
||||||
QString prettyName() const override;
|
|
||||||
Calamares::JobResult exec() override;
|
|
||||||
|
|
||||||
Calamares::JobList createJobs();
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_cmdInternalStoragePrepare;
|
|
||||||
QString m_cmdLuksFormat;
|
|
||||||
QString m_cmdLuksOpen;
|
|
||||||
QString m_cmdMkfsRoot;
|
|
||||||
QString m_cmdMount;
|
|
||||||
QString m_targetDeviceRoot;
|
|
||||||
QString m_targetDeviceRootInternal;
|
|
||||||
bool m_installFromExternalToInternal;
|
|
||||||
bool m_isFdeEnabled;
|
|
||||||
QString m_password;
|
|
||||||
};
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
#include "UsersJob.h"
|
|
||||||
|
|
||||||
#include "GlobalStorage.h"
|
|
||||||
#include "JobQueue.h"
|
|
||||||
#include "Settings.h"
|
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
|
||||||
#include "utils/Logger.h"
|
|
||||||
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFileInfo>
|
|
||||||
|
|
||||||
|
|
||||||
UsersJob::UsersJob( bool featureSshd,
|
|
||||||
const QString& cmdPasswd,
|
|
||||||
const QString& cmdSshd,
|
|
||||||
const QString& cmdSshdUseradd,
|
|
||||||
bool isSshEnabled,
|
|
||||||
const QString& username,
|
|
||||||
const QString& password,
|
|
||||||
const QString& sshdUsername,
|
|
||||||
const QString& sshdPassword )
|
|
||||||
: Calamares::Job()
|
|
||||||
, m_featureSshd( featureSshd )
|
|
||||||
, m_cmdPasswd( cmdPasswd )
|
|
||||||
, m_cmdSshd( cmdSshd )
|
|
||||||
, m_cmdSshdUseradd( cmdSshdUseradd )
|
|
||||||
, m_isSshEnabled( isSshEnabled )
|
|
||||||
, m_username( username )
|
|
||||||
, m_password( password )
|
|
||||||
, m_sshdUsername( sshdUsername )
|
|
||||||
, m_sshdPassword( sshdPassword )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QString
|
|
||||||
UsersJob::prettyName() const
|
|
||||||
{
|
|
||||||
return "Configuring users";
|
|
||||||
}
|
|
||||||
|
|
||||||
Calamares::JobResult
|
|
||||||
UsersJob::exec()
|
|
||||||
{
|
|
||||||
using namespace Calamares;
|
|
||||||
using namespace CalamaresUtils;
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
QList< QPair< QStringList, QString > > commands = {
|
|
||||||
{ { "sh", "-c", m_cmdPasswd + " " + m_username }, m_password + "\n" + m_password + "\n" },
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( m_featureSshd )
|
|
||||||
{
|
|
||||||
commands.append( { { "sh", "-c", m_cmdSshd }, QString() } );
|
|
||||||
|
|
||||||
if ( m_isSshEnabled )
|
|
||||||
{
|
|
||||||
commands.append( { { "sh", "-c", m_cmdSshdUseradd + " " + m_sshdUsername }, QString() } );
|
|
||||||
commands.append(
|
|
||||||
{ { "sh", "-c", m_cmdPasswd + " " + m_sshdUsername }, m_sshdPassword + "\n" + m_sshdPassword + "\n" } );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ( auto command, commands )
|
|
||||||
{
|
|
||||||
auto location = System::RunLocation::RunInTarget;
|
|
||||||
const QString pathRoot = "/";
|
|
||||||
const QStringList args = command.first;
|
|
||||||
const QString stdInput = command.second;
|
|
||||||
|
|
||||||
ProcessResult res = System::runCommand( location, args, pathRoot, stdInput, chrono::seconds( 30 ) );
|
|
||||||
if ( res.getExitCode() )
|
|
||||||
{
|
|
||||||
return JobResult::error( "Command failed:<br><br>"
|
|
||||||
"'"
|
|
||||||
+ args.join( " " )
|
|
||||||
+ "'<br><br>"
|
|
||||||
" with output:<br><br>"
|
|
||||||
"'"
|
|
||||||
+ res.getOutput() + "'" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return JobResult::ok();
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
#pragma once
|
|
||||||
#include "Job.h"
|
|
||||||
|
|
||||||
|
|
||||||
class UsersJob : public Calamares::Job
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
UsersJob( bool featureSshd,
|
|
||||||
const QString& cmdPasswd,
|
|
||||||
const QString& cmdSshd,
|
|
||||||
const QString& cmdSshdUseradd,
|
|
||||||
bool isSshEnabled,
|
|
||||||
const QString& username,
|
|
||||||
const QString& password,
|
|
||||||
const QString& sshdUsername,
|
|
||||||
const QString& sshdPassword );
|
|
||||||
|
|
||||||
QString prettyName() const override;
|
|
||||||
Calamares::JobResult exec() override;
|
|
||||||
|
|
||||||
Calamares::JobList createJobs();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_featureSshd;
|
|
||||||
QString m_cmdPasswd;
|
|
||||||
QString m_cmdSshd;
|
|
||||||
QString m_cmdSshdUseradd;
|
|
||||||
bool m_isSshEnabled;
|
|
||||||
QString m_username;
|
|
||||||
QString m_password;
|
|
||||||
QString m_sshdUsername;
|
|
||||||
QString m_sshdPassword;
|
|
||||||
};
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: mainText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 30
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
text: "To protect your data in case your device gets stolen," +
|
|
||||||
" it is recommended to enable full disk encryption.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"If you enable full disk encryption, you will be asked for" +
|
|
||||||
" a password. Without this password, it is not possible to" +
|
|
||||||
" boot your device or access any data on it. Make sure that" +
|
|
||||||
" you don't lose this password!"
|
|
||||||
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: firstButton
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: mainText.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Enable")
|
|
||||||
onClicked: {
|
|
||||||
config.isFdeEnabled = true;
|
|
||||||
navNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: firstButton.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Disable")
|
|
||||||
onClicked: {
|
|
||||||
config.isFdeEnabled = false;
|
|
||||||
navNextFeature();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: password
|
|
||||||
anchors.top: parent.top
|
|
||||||
placeholderText: qsTr("Password")
|
|
||||||
inputMethodHints: Qt.ImhPreferLowercase
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
onTextChanged: validatePassword(password, passwordRepeat,
|
|
||||||
errorText)
|
|
||||||
text: config.fdePassword
|
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(activeFocus) {
|
|
||||||
Qt.inputMethod.update(Qt.ImQueryInput);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: passwordRepeat
|
|
||||||
anchors.top: password.bottom
|
|
||||||
placeholderText: qsTr("Password (repeat)")
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
onTextChanged: validatePassword(password, passwordRepeat,
|
|
||||||
errorText)
|
|
||||||
text: config.fdePassword
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: errorText
|
|
||||||
anchors.top: passwordRepeat.bottom
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: errorText.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Continue")
|
|
||||||
onClicked: {
|
|
||||||
if (validatePassword(password, passwordRepeat, errorText)) {
|
|
||||||
config.fdePassword = password.text;
|
|
||||||
navNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Undef <calamares@undef.tools>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: mainText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 30
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
text: "Select the filesystem for root partition. If unsure, leave the default."
|
|
||||||
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
ComboBox {
|
|
||||||
id: fsTypeCB
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: mainText.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
height: 60
|
|
||||||
editable: false
|
|
||||||
model: config.fsList
|
|
||||||
/* Save the current state on selection so it is there when the back button is pressed */
|
|
||||||
onActivated: config.fsType = fsTypeCB.currentText;
|
|
||||||
Component.onCompleted: fsTypeCB.currentIndex = find( config.fsType, Qt.MatchContains );
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: fsTypeCB.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Continue")
|
|
||||||
onClicked: {
|
|
||||||
config.fsType = fsTypeCB.currentText;
|
|
||||||
navNextFeature();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: mainText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 30
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
text: (function() {
|
|
||||||
var ret = "Once you hit 'install', the installation will begin." +
|
|
||||||
" It will typically take a few minutes. Do not power off the" +
|
|
||||||
" device until it is done.<br><br>";
|
|
||||||
|
|
||||||
if (config.installFromExternalToInternal) {
|
|
||||||
ret += "<b>After the installation, your device will shutdown" +
|
|
||||||
" automatically. You must remove the external storage" +
|
|
||||||
" (SD card) before booting again.</b>" +
|
|
||||||
"<br><br>" +
|
|
||||||
"Otherwise, your device will boot into the installer" +
|
|
||||||
" again, and not into the installed system."
|
|
||||||
} else {
|
|
||||||
ret += "Afterwards, it will reboot into the installed system.";
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}())
|
|
||||||
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: firstButton
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: mainText.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Install")
|
|
||||||
onClicked: navFinish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: mainText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 30
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
text: "The installation was started from an external storage medium." +
|
|
||||||
"<br>" +
|
|
||||||
"You can either install to the same medium and overwrite the" +
|
|
||||||
" installer, or install to the internal storage.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"Where would you like to install " + config.osName + "?"
|
|
||||||
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: firstButton
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: mainText.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Internal (eMMC)")
|
|
||||||
onClicked: {
|
|
||||||
config.installFromExternalToInternal = true;
|
|
||||||
navNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: firstButton.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("External (SD card)")
|
|
||||||
onClicked: {
|
|
||||||
config.installFromExternalToInternal = false;
|
|
||||||
navNextFeature();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: mainText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 30
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
text: "Are you sure that you want to overwrite the internal storage?" +
|
|
||||||
"<br><br>" +
|
|
||||||
"<b>All existing data on the device will be lost!</b>"
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: firstButton
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: mainText.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Yes")
|
|
||||||
onClicked: {
|
|
||||||
navNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: firstButton.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("No")
|
|
||||||
onClicked: {
|
|
||||||
navBack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
# Commented out values are defaults.
|
|
||||||
# All commands are running with 'sh -c'.
|
|
||||||
---
|
|
||||||
#######
|
|
||||||
### Target OS information
|
|
||||||
#######
|
|
||||||
|
|
||||||
## Operating System Name
|
|
||||||
# osName: "(unknown)"
|
|
||||||
|
|
||||||
## User Interface name (e.g. Plasma Mobile)
|
|
||||||
# userInterface: "(unknown)"
|
|
||||||
|
|
||||||
## User Interface assumes that the password is numeric (as of writing, this is
|
|
||||||
## the case with Plasma Mobile and Phosh)
|
|
||||||
# userPasswordNumeric: true
|
|
||||||
|
|
||||||
## OS version
|
|
||||||
# version: "(unknown)"
|
|
||||||
|
|
||||||
## Default username (for which the password will be set)
|
|
||||||
# username: "user"
|
|
||||||
|
|
||||||
#######
|
|
||||||
### Target device information
|
|
||||||
#######
|
|
||||||
|
|
||||||
## Architecture (e.g. aarch64)
|
|
||||||
# arch: "(unknown)"
|
|
||||||
|
|
||||||
## Name of the device (e.g. PinePhone)
|
|
||||||
# device: "(unknown)"
|
|
||||||
|
|
||||||
## Partition that will be formatted and mounted (optionally with FDE) for the
|
|
||||||
## rootfs
|
|
||||||
# targetDeviceRoot: "/dev/unknown"
|
|
||||||
|
|
||||||
## Partition that will be formatted and mounted (optionally with FDE) for the
|
|
||||||
## rootfs, on internal storage. The installer OS must not set this, if it was
|
|
||||||
## booted from the internal storage (this is not checked in the mobile
|
|
||||||
## module!).
|
|
||||||
## If this is set, the user gets asked whether they want to install on internal
|
|
||||||
## or external storage. If the user chose internal storage,
|
|
||||||
## cmdInternalStoragePrepare (see below) runs before this partition gets
|
|
||||||
## formatted (see below). A note is displayed, that the device is powered off
|
|
||||||
## after installation and that the user should remove the external storage
|
|
||||||
## medium. So you need to adjust the installer OS to poweroff in that case, and
|
|
||||||
## not reboot. See postmarketos-ondev.git for reference.
|
|
||||||
# targetDeviceRootInternal: ""
|
|
||||||
|
|
||||||
######
|
|
||||||
### Installer Features
|
|
||||||
######
|
|
||||||
|
|
||||||
## Ask whether sshd should be enabled or not. If enabled, add a dedicated ssh
|
|
||||||
## user with proper username and password and suggest to change to key-based
|
|
||||||
## authentication after installation.
|
|
||||||
# featureSshd: true
|
|
||||||
|
|
||||||
## Ask the user, which filesystem to use.
|
|
||||||
# featureFsType: false
|
|
||||||
## Filesystems that the user can choose from.
|
|
||||||
#fsModel:
|
|
||||||
# - ext4
|
|
||||||
# - f2fs
|
|
||||||
# - btrfs
|
|
||||||
## Default filesystem to display in the dialog. If featureFsType is disabled,
|
|
||||||
## this gets used without asking the user.
|
|
||||||
# defaultFs: ext4
|
|
||||||
|
|
||||||
## Start Qt's virtual keyboard within the mobile module. Disable if you bring
|
|
||||||
## your own virtual keyboard (e.g. svkbd).
|
|
||||||
# builtinVirtualKeyboard: true
|
|
||||||
|
|
||||||
#######
|
|
||||||
### Commands running in the installer OS
|
|
||||||
#######
|
|
||||||
|
|
||||||
## Format the target partition with LUKS
|
|
||||||
## Arguments: <device>
|
|
||||||
## Stdin: password with \n
|
|
||||||
# cmdLuksFormat: "cryptsetup luksFormat --use-random"
|
|
||||||
|
|
||||||
## Open the formatted partition
|
|
||||||
## Arguments: <device> <mapping name>
|
|
||||||
## Stdin: password with \n
|
|
||||||
# cmdLuksOpen: "cryptsetup luksOpen"
|
|
||||||
|
|
||||||
## Format the rootfs with a file system
|
|
||||||
## Arguments: <device>
|
|
||||||
## Btrfs: to allow snapshots to work on the root subvolume, it is recommended that this
|
|
||||||
## command be a script which will create a subvolume and make it default
|
|
||||||
## An example can be found at:
|
|
||||||
## https://gitlab.com/mobian1/calamares-settings-mobian/-/merge_requests/2/diffs#diff-content-dde34f5f1c89e3dea63608c553bbc452dedf428f
|
|
||||||
# cmdMkfsRootBtrfs: "mkfs.btrfs -L 'unknownOS_root'"
|
|
||||||
# cmdMkfsRootExt4: "mkfs.ext4 -L 'unknownOS_root'"
|
|
||||||
# cmdMkfsRootF2fs: "mkfs.f2fs -l 'unknownOS_root'"
|
|
||||||
|
|
||||||
## Mount the partition after formatting with file system
|
|
||||||
## Arguments: <device> <mountpoint>
|
|
||||||
# cmdMount: "mount"
|
|
||||||
|
|
||||||
## When user selects installation from external storage to internal storage
|
|
||||||
## (see targetDeviceRootInternal above), use this command to prepare the
|
|
||||||
## internal storage medium. The command must create a partition table with
|
|
||||||
## two partitions (boot, root) and fill the boot partition. See the
|
|
||||||
## ondev-internal-storage-prepare.sh in postmarketos-ondev as example.
|
|
||||||
# cmdInternalStoragePrepare: "ondev-internal-storage-prepare"
|
|
||||||
|
|
||||||
#######
|
|
||||||
### Commands running in the target OS (chroot)
|
|
||||||
#######
|
|
||||||
|
|
||||||
## Set the password for default user and sshd user
|
|
||||||
## Arguments: <username>
|
|
||||||
## Stdin: password twice, each time with \n
|
|
||||||
# cmdPasswd: "passwd"
|
|
||||||
|
|
||||||
## Enable or disable sshd
|
|
||||||
# cmdSshdEnable: "systemctl enable sshd.service"
|
|
||||||
# cmdSshdDisable: "systemctl disable sshd.service"
|
|
||||||
|
|
||||||
## Create the user for sshd
|
|
||||||
## Arguments: <username>
|
|
||||||
# cmdSshdUseradd: "useradd -G wheel -m"
|
|
||||||
@@ -1,423 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Page
|
|
||||||
{
|
|
||||||
property var screen: "welcome"
|
|
||||||
property var screenPrevious: []
|
|
||||||
property var titles: {
|
|
||||||
"welcome": null, /* titlebar disabled */
|
|
||||||
"install_target": "Installation target",
|
|
||||||
"install_target_confirm": "Warning",
|
|
||||||
"user_pass": "User password",
|
|
||||||
"ssh_confirm": "SSH server",
|
|
||||||
"ssh_credentials": "SSH credentials",
|
|
||||||
"fs_selection": "Root filesystem",
|
|
||||||
"fde_confirm": "Full disk encryption",
|
|
||||||
"fde_pass": "Full disk encryption",
|
|
||||||
"install_confirm": "Ready to install",
|
|
||||||
"wait": null
|
|
||||||
}
|
|
||||||
property var features: [
|
|
||||||
{"name": "welcome",
|
|
||||||
"screens": ["welcome"]},
|
|
||||||
{"name": "installTarget",
|
|
||||||
"screens": ["install_target", "install_target_confirm"]},
|
|
||||||
{"name": "userPassword",
|
|
||||||
"screens": ["user_pass"]},
|
|
||||||
{"name": "sshd",
|
|
||||||
"screens": ["ssh_confirm", "ssh_credentials"]},
|
|
||||||
{"name": "fsType",
|
|
||||||
"screens": ["fs_selection"]},
|
|
||||||
{"name": "fde",
|
|
||||||
"screens": ["fde_confirm", "fde_pass"]},
|
|
||||||
{"name": "installConfirm",
|
|
||||||
"screens": ["install_confirm", "wait"]}
|
|
||||||
]
|
|
||||||
property var featureIdByScreen: (function() {
|
|
||||||
/* Put "features" above into an index of screen name -> feature id:
|
|
||||||
* featureIdByScreen = {"welcome": 0, "user_pass": 1, ...} */
|
|
||||||
var ret = {};
|
|
||||||
for (var i=0; i<features.length; i++) {
|
|
||||||
for (var j=0; j<features[i]["screens"].length; j++) {
|
|
||||||
ret[ features[i]["screens"][j] ] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}())
|
|
||||||
/* Only allow characters, that can be typed in with osk-sdl
|
|
||||||
* (src/keyboard.cpp). Details in big comment in validatePassword(). */
|
|
||||||
property var allowed_chars:
|
|
||||||
/* layer 0 */ "abcdefghijklmnopqrstuvwxyz" +
|
|
||||||
/* layer 1 */ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
|
||||||
/* layer 2 */ "1234567890" + "@#$%&-_+()" + ",\"':;!?" +
|
|
||||||
/* layer 3 */ "~`|·√πτ÷×¶" + "©®£€¥^°*{}" + "\\/<>=[]" +
|
|
||||||
/* bottom row */ " ."
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: appContainer
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: inputPanel.top
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: mobileNavigation
|
|
||||||
width: parent.width
|
|
||||||
height: 60
|
|
||||||
color: "#e6e4e1"
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
border.width: 1
|
|
||||||
border.color: "#a7a7a7"
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
spacing: 6
|
|
||||||
|
|
||||||
Button {
|
|
||||||
Layout.leftMargin: 6
|
|
||||||
id: mobileBack
|
|
||||||
text: "<"
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
implicitWidth: 32
|
|
||||||
implicitHeight: 30
|
|
||||||
border.color: "#c1bab5"
|
|
||||||
border.width: 1
|
|
||||||
radius: 4
|
|
||||||
color: mobileBack.down ? "#dbdbdb" : "#f2f2f2"
|
|
||||||
}
|
|
||||||
|
|
||||||
onClicked: navBack()
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
implicitHeight: 30
|
|
||||||
Layout.fillWidth: true
|
|
||||||
color: "#e6e4e1"
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: mobileTitle
|
|
||||||
text: ""
|
|
||||||
color: "#303638"
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
color: "#e6e4e1"
|
|
||||||
Layout.rightMargin: 6
|
|
||||||
implicitWidth: 32
|
|
||||||
implicitHeight: 30
|
|
||||||
id: filler
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: load
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: mobileNavigation.bottom
|
|
||||||
anchors.right: parent.right
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
InputPanel {
|
|
||||||
id: inputPanel
|
|
||||||
y: Qt.inputMethod.visible ? parent.height - inputPanel.height : parent.height
|
|
||||||
visible: config.builtinVirtualKeyboard
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: timer
|
|
||||||
}
|
|
||||||
|
|
||||||
function skipFeatureInstallTarget() {
|
|
||||||
return config.targetDeviceRootInternal == "";
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Navigation related */
|
|
||||||
function navTo(name, historyPush=true) {
|
|
||||||
console.log("Navigating to screen: " + name);
|
|
||||||
if (historyPush)
|
|
||||||
screenPrevious.push(screen);
|
|
||||||
screen = name;
|
|
||||||
load.source = name + ".qml";
|
|
||||||
mobileNavigation.visible = (titles[name] !== null);
|
|
||||||
mobileTitle.text = "<b>" + titles[name] + "</b>";
|
|
||||||
Qt.inputMethod.hide();
|
|
||||||
}
|
|
||||||
function navFinish() {
|
|
||||||
/* Show a waiting screen and wait a second (so it can render). The big
|
|
||||||
* comment in Config.cpp::runPartitionJobThenLeave() explains why this
|
|
||||||
* is necessary. */
|
|
||||||
navTo("wait");
|
|
||||||
timer.interval = 1000;
|
|
||||||
timer.repeat = false;
|
|
||||||
timer.triggered.connect(function() {
|
|
||||||
/* Trigger Config.cpp::runPartitionJobThenLeave(). (We could expose
|
|
||||||
* the function directly with qmlRegisterSingletonType somehow, but
|
|
||||||
* I haven't seen existing Calamares code do that with the Config
|
|
||||||
* object, so just use the side effect of setting the variable, as
|
|
||||||
* done in existing code of Calamares modules.) */
|
|
||||||
config.runPartitionJobThenLeave = 1
|
|
||||||
});
|
|
||||||
timer.start();
|
|
||||||
}
|
|
||||||
function navNextFeature() {
|
|
||||||
var id;
|
|
||||||
|
|
||||||
/* Skip disabled features */
|
|
||||||
for (id = featureIdByScreen[screen] + 1; id < features.length; id++) {
|
|
||||||
/* First letter uppercase */
|
|
||||||
var name = features[id]["name"];
|
|
||||||
var nameUp = name.charAt(0).toUpperCase() + name.slice(1);
|
|
||||||
|
|
||||||
/* Check config.Feature<Name> */
|
|
||||||
var configOption = "feature" + nameUp;
|
|
||||||
if (config[configOption] === false) {
|
|
||||||
console.log("Skipping feature (disabled in config): " + name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check skipFeature<Name>() */
|
|
||||||
var funcName = "skipFeature" + nameUp;
|
|
||||||
if (eval("typeof " + funcName) === "function"
|
|
||||||
&& eval(funcName + "()")) {
|
|
||||||
console.log("Skipping feature (skip function): " + name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Navigating to feature: " + features[id]["name"]);
|
|
||||||
return navTo(features[id]["screens"][0]);
|
|
||||||
}
|
|
||||||
function navNext() {
|
|
||||||
var featureId = featureIdByScreen[screen];
|
|
||||||
var featureScreens = features[featureId]["screens"];
|
|
||||||
for (var i = 0; i<featureScreens.length; i++) {
|
|
||||||
/* Seek ahead until i is current screen */
|
|
||||||
if (featureScreens[i] != screen)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Navigate to next screen in same feature */
|
|
||||||
if (i + 1 < featureScreens.length) {
|
|
||||||
var screenNext = featureScreens[i + 1];
|
|
||||||
return navTo(screenNext);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Screen is last in feature */
|
|
||||||
return navNextFeature();
|
|
||||||
}
|
|
||||||
console.log("ERROR: navNext() failed for screen: " + screen);
|
|
||||||
}
|
|
||||||
function navBack() {
|
|
||||||
if (screenPrevious.length)
|
|
||||||
return navTo(screenPrevious.pop(), false);
|
|
||||||
ViewManager.back();
|
|
||||||
}
|
|
||||||
function onActivate() {
|
|
||||||
navTo(screen, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Input validation: show/clear failures */
|
|
||||||
function validationFailure(errorText, message="") {
|
|
||||||
errorText.text = message;
|
|
||||||
errorText.visible = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
function validationFailureClear(errorText) {
|
|
||||||
errorText.text = "";
|
|
||||||
errorText.visible = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Input validation: user-screens (user_pass, ssh_credentials) */
|
|
||||||
function validatePin(userPin, userPinRepeat, errorText) {
|
|
||||||
var pin = userPin.text;
|
|
||||||
var repeat = userPinRepeat.text;
|
|
||||||
|
|
||||||
if (pin == "")
|
|
||||||
return validationFailure(errorText);
|
|
||||||
|
|
||||||
if (!pin.match(/^[0-9]*$/))
|
|
||||||
return validationFailure(errorText,
|
|
||||||
"Only digits are allowed.");
|
|
||||||
|
|
||||||
if (pin.length < 5)
|
|
||||||
return validationFailure(errorText,
|
|
||||||
"Too short: needs at least 5 digits.");
|
|
||||||
|
|
||||||
if (repeat == "")
|
|
||||||
return validationFailure(errorText);
|
|
||||||
|
|
||||||
if (repeat != pin)
|
|
||||||
return validationFailure(errorText,
|
|
||||||
"The PINs don't match.");
|
|
||||||
|
|
||||||
return validationFailureClear(errorText);
|
|
||||||
}
|
|
||||||
function validateSshdUsername(username, errorText) {
|
|
||||||
var name = username.text;
|
|
||||||
var reserved = [ /* FIXME: make configurable */
|
|
||||||
config.username,
|
|
||||||
"adm",
|
|
||||||
"at ",
|
|
||||||
"bin",
|
|
||||||
"colord",
|
|
||||||
"cron",
|
|
||||||
"cyrus",
|
|
||||||
"daemon",
|
|
||||||
"ftp",
|
|
||||||
"games",
|
|
||||||
"geoclue",
|
|
||||||
"guest",
|
|
||||||
"halt",
|
|
||||||
"lightdm",
|
|
||||||
"lp",
|
|
||||||
"mail",
|
|
||||||
"man",
|
|
||||||
"messagebus",
|
|
||||||
"news",
|
|
||||||
"nobody",
|
|
||||||
"ntp",
|
|
||||||
"operator",
|
|
||||||
"polkitd",
|
|
||||||
"postmaster",
|
|
||||||
"pulse",
|
|
||||||
"root",
|
|
||||||
"shutdown",
|
|
||||||
"smmsp",
|
|
||||||
"squid",
|
|
||||||
"sshd",
|
|
||||||
"sync",
|
|
||||||
"uucp",
|
|
||||||
"vpopmail",
|
|
||||||
"xfs",
|
|
||||||
]
|
|
||||||
|
|
||||||
/* Validate characters */
|
|
||||||
for (var i=0; i<name.length; i++) {
|
|
||||||
if (i) {
|
|
||||||
if (!name[i].match(/^[a-z0-9_-]$/))
|
|
||||||
return validationFailure(errorText,
|
|
||||||
"Characters must be lowercase" +
|
|
||||||
" letters, numbers,<br>" +
|
|
||||||
" underscores or minus signs.");
|
|
||||||
} else {
|
|
||||||
if (!name[i].match(/^[a-z_]$/))
|
|
||||||
return validationFailure(errorText,
|
|
||||||
"First character must be a" +
|
|
||||||
" lowercase letter or an" +
|
|
||||||
" underscore.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Validate against reserved usernames */
|
|
||||||
for (var i=0;i<reserved.length;i++) {
|
|
||||||
if (name == reserved[i])
|
|
||||||
return validationFailure(errorText, "Username '" +
|
|
||||||
reserved[i] +
|
|
||||||
"' is reserved.")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Passed */
|
|
||||||
return validationFailureClear(errorText);
|
|
||||||
}
|
|
||||||
function validateSshdPassword(password, passwordRepeat, errorText) {
|
|
||||||
var pass = password.text;
|
|
||||||
var repeat = passwordRepeat.text;
|
|
||||||
|
|
||||||
if (pass == "")
|
|
||||||
return validationFailure(errorText);
|
|
||||||
|
|
||||||
if (pass.length < 8)
|
|
||||||
return validationFailure(errorText,
|
|
||||||
"Too short: needs at least 8" +
|
|
||||||
" characters.");
|
|
||||||
|
|
||||||
if (repeat == "")
|
|
||||||
return validationFailure(errorText);
|
|
||||||
|
|
||||||
if (pass != repeat)
|
|
||||||
return validationFailure(errorText, "Passwords don't match.");
|
|
||||||
|
|
||||||
return validationFailureClear(errorText);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Input validation: fde_pass */
|
|
||||||
function check_chars(input) {
|
|
||||||
for (var i = 0; i < input.length; i++) {
|
|
||||||
if (allowed_chars.indexOf(input[i]) == -1)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
function allowed_chars_multiline() {
|
|
||||||
/* return allowed_chars split across multiple lines */
|
|
||||||
var step = 20;
|
|
||||||
var ret = "";
|
|
||||||
for (var i = 0; i < allowed_chars.length + step; i += step)
|
|
||||||
ret += allowed_chars.slice(i, i + step) + "\n";
|
|
||||||
return ret.trim();
|
|
||||||
}
|
|
||||||
function validatePassword(password, passwordRepeat, errorText) {
|
|
||||||
var pass = password.text;
|
|
||||||
var repeat = passwordRepeat.text;
|
|
||||||
|
|
||||||
if (pass == "")
|
|
||||||
return validationFailure(errorText);
|
|
||||||
|
|
||||||
/* This function gets called for the FDE password and for the user
|
|
||||||
* password. As of writing, all distributions shipping the mobile
|
|
||||||
* module are using osk-sdl to type in the FDE password after the
|
|
||||||
* installation, and another keyboard after booting up, to type in the
|
|
||||||
* user password. The osk-sdl password has the same keys as
|
|
||||||
* squeekboard's default layout, and other keyboards should be able to
|
|
||||||
* type these characters in as well. For now, verify that the password
|
|
||||||
* only contains characters that can be typed in by osk-sdl. If you
|
|
||||||
* need this to be more sophisticated, feel free to submit patches to
|
|
||||||
* make this more configurable. */
|
|
||||||
if (!check_chars(pass))
|
|
||||||
return validationFailure(errorText,
|
|
||||||
"The password must only contain" +
|
|
||||||
" these characters, others can possibly" +
|
|
||||||
" not be typed in after installation:\n" +
|
|
||||||
"\n" +
|
|
||||||
allowed_chars_multiline());
|
|
||||||
|
|
||||||
if (pass.length < 8)
|
|
||||||
return validationFailure(errorText,
|
|
||||||
"Too short: needs at least 8" +
|
|
||||||
" characters.");
|
|
||||||
|
|
||||||
if (repeat == "")
|
|
||||||
return validationFailure(errorText);
|
|
||||||
|
|
||||||
if (pass != repeat)
|
|
||||||
return validationFailure(errorText, "Passwords don't match.");
|
|
||||||
|
|
||||||
return validationFailureClear(errorText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<!DOCTYPE RCC><RCC version="1.0">
|
|
||||||
<qresource>
|
|
||||||
<file>mobile.qml</file>
|
|
||||||
|
|
||||||
<file>welcome.qml</file>
|
|
||||||
|
|
||||||
<file>install_target.qml</file> <!-- install from external to internal? -->
|
|
||||||
<file>install_target_confirm.qml</file> <!-- overwrite internal storage? -->
|
|
||||||
|
|
||||||
<file>user_pass.qml</file> <!-- default user: password -->
|
|
||||||
<file>ssh_confirm.qml</file> <!-- sshd: enable or not? -->
|
|
||||||
<file>ssh_credentials.qml</file> <!-- sshd user: username, password -->
|
|
||||||
<file>fs_selection.qml</file> <!-- filesystem selection -->
|
|
||||||
|
|
||||||
<file>fde_confirm.qml</file> <!-- enable FDE or not? -->
|
|
||||||
<file>fde_pass.qml</file> <!-- FDE password (optional) -->
|
|
||||||
<file>install_confirm.qml</file> <!-- final confirmation before install -->
|
|
||||||
|
|
||||||
<file>wait.qml</file> <!-- please wait while partitioning -->
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: mainText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 30
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
text: "If you don't know what SSH is, choose 'disable'.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"With 'enable', you will be asked for a second username and" +
|
|
||||||
" password. You will be able to login to the SSH server with" +
|
|
||||||
" these credentials via USB (172.16.42.1), Wi-Fi and possibly" +
|
|
||||||
" cellular network. It is recommended to replace the password" +
|
|
||||||
" with an SSH key after the installation.<br>" +
|
|
||||||
"<br>" +
|
|
||||||
"More information:<br>" +
|
|
||||||
"https://postmarketos.org/ssh"
|
|
||||||
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: firstButton
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: mainText.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Enable")
|
|
||||||
onClicked: {
|
|
||||||
config.isSshEnabled = true;
|
|
||||||
navNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: firstButton.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Disable")
|
|
||||||
onClicked: {
|
|
||||||
config.isSshEnabled = false;
|
|
||||||
navNextFeature();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: username
|
|
||||||
anchors.top: parent.top
|
|
||||||
placeholderText: qsTr("SSH username")
|
|
||||||
inputMethodHints: Qt.ImhPreferLowercase
|
|
||||||
onTextChanged: validateSshdUsername(username, errorTextUsername)
|
|
||||||
text: config.sshdUsername
|
|
||||||
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(activeFocus) {
|
|
||||||
Qt.inputMethod.update(Qt.ImQueryInput);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: errorTextUsername
|
|
||||||
anchors.top: username.bottom
|
|
||||||
visible: false
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: password
|
|
||||||
anchors.top: errorTextUsername.bottom
|
|
||||||
placeholderText: qsTr("SSH password")
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
onTextChanged: validateSshdPassword(password, passwordRepeat,
|
|
||||||
errorTextPassword)
|
|
||||||
text: config.sshdPassword
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: passwordRepeat
|
|
||||||
anchors.top: password.bottom
|
|
||||||
placeholderText: qsTr("SSH password (repeat)")
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
onTextChanged: validateSshdPassword(password, passwordRepeat,
|
|
||||||
errorTextPassword)
|
|
||||||
text: config.sshdPassword
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: errorTextPassword
|
|
||||||
anchors.top: passwordRepeat.bottom
|
|
||||||
visible: false
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: errorTextPassword.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Continue")
|
|
||||||
onClicked: {
|
|
||||||
if (validateSshdUsername(username, errorTextUsername) &&
|
|
||||||
validateSshdPassword(password, passwordRepeat,
|
|
||||||
errorTextPassword)) {
|
|
||||||
config.sshdUsername = username.text;
|
|
||||||
config.sshdPassword = password.text;
|
|
||||||
|
|
||||||
navNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Item {
|
|
||||||
property var placeholder: (config.userPasswordNumeric
|
|
||||||
? "PIN"
|
|
||||||
: "Password")
|
|
||||||
property var hints: (config.userPasswordNumeric
|
|
||||||
? Qt.ImhDigitsOnly
|
|
||||||
: Qt.ImhPreferLowercase)
|
|
||||||
property var validateFunc: (config.userPasswordNumeric
|
|
||||||
? validatePin
|
|
||||||
: validatePassword);
|
|
||||||
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: description
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 30
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
text: (function() {
|
|
||||||
if (config.userPasswordNumeric) {
|
|
||||||
return "Set the numeric password of your user. The" +
|
|
||||||
" lockscreen will ask for this PIN. This is" +
|
|
||||||
" <i>not</i> the PIN of your SIM card. Make sure to" +
|
|
||||||
" remember it.";
|
|
||||||
} else {
|
|
||||||
return "Set the password of your user. The lockscreen will" +
|
|
||||||
" ask for this password. Make sure to remember it.";
|
|
||||||
}
|
|
||||||
}())
|
|
||||||
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: userPass
|
|
||||||
anchors.top: description.bottom
|
|
||||||
placeholderText: qsTr(placeholder)
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
onTextChanged: validateFunc(userPass, userPassRepeat, errorText)
|
|
||||||
text: config.userPassword
|
|
||||||
|
|
||||||
/* Let the virtual keyboard change to digits only */
|
|
||||||
inputMethodHints: hints
|
|
||||||
onActiveFocusChanged: {
|
|
||||||
if(activeFocus) {
|
|
||||||
Qt.inputMethod.update(Qt.ImQueryInput)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: userPassRepeat
|
|
||||||
anchors.top: userPass.bottom
|
|
||||||
placeholderText: qsTr(placeholder + " (repeat)")
|
|
||||||
inputMethodHints: hints
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
onTextChanged: validateFunc(userPass, userPassRepeat, errorText)
|
|
||||||
text: config.userPassword
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.top: userPassRepeat.bottom
|
|
||||||
id: errorText
|
|
||||||
visible: false
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: errorText.bottom
|
|
||||||
anchors.topMargin: 40
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Continue")
|
|
||||||
onClicked: {
|
|
||||||
if (validateFunc(userPass, userPassRepeat, errorText)) {
|
|
||||||
config.userPassword = userPass.text;
|
|
||||||
navNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Page
|
|
||||||
{
|
|
||||||
id: fdeWait
|
|
||||||
|
|
||||||
Item {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: logo
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 50
|
|
||||||
height: 250
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
source: "file:///usr/share/calamares/branding/default-mobile/logo.png"
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
id: waitText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: logo.bottom
|
|
||||||
anchors.topMargin: 150
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
text: "Formatting and mounting target partition. This may" +
|
|
||||||
" take up to two minutes, please be patient."
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2020 Oliver Smith <ollieparanoid@postmarketos.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
||||||
import io.calamares.core 1.0
|
|
||||||
import io.calamares.ui 1.0
|
|
||||||
|
|
||||||
import QtQuick 2.10
|
|
||||||
import QtQuick.Controls 2.10
|
|
||||||
import QtQuick.Layouts 1.3
|
|
||||||
import org.kde.kirigami 2.7 as Kirigami
|
|
||||||
import QtGraphicalEffects 1.0
|
|
||||||
import QtQuick.Window 2.3
|
|
||||||
import QtQuick.VirtualKeyboard 2.1
|
|
||||||
|
|
||||||
Page
|
|
||||||
{
|
|
||||||
id: welcome
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: appContainer
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: logo
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: 50
|
|
||||||
height: 250
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
source: "file:///usr/share/calamares/branding/default-mobile/logo.png"
|
|
||||||
}
|
|
||||||
Text {
|
|
||||||
id: mainText
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: logo.bottom
|
|
||||||
anchors.topMargin: 50
|
|
||||||
horizontalAlignment: Text.AlignRight
|
|
||||||
text: "You are about to install<br>" +
|
|
||||||
"<b>" + config.osName +
|
|
||||||
" " + config.version + "</b><br>" +
|
|
||||||
"user interface " +
|
|
||||||
"<b>" + config.userInterface + "</b><br>" +
|
|
||||||
"architecture " +
|
|
||||||
"<b>" + config.arch + "</b><br>" +
|
|
||||||
"on your " +
|
|
||||||
"<b>" + config.device + "</b><br>"
|
|
||||||
width: 500
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: mainText.bottom
|
|
||||||
anchors.topMargin: 50
|
|
||||||
width: 500
|
|
||||||
|
|
||||||
text: qsTr("Continue")
|
|
||||||
onClicked: navNext()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# The OS-FreeBSD module does "all the things" in a FreeBSD installation.
|
|
||||||
# Since the other modules -- users, fstab, grub, pretty much all of them
|
|
||||||
# -- are Linux-specific, it doesn't make much sense to fork each of them
|
|
||||||
# or provide alternatives, so instead we have one module that completes
|
|
||||||
# a FreeBSD installation based on the GlobalStorage values set by
|
|
||||||
# Calamares viewmodules.
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
# License-Filename: LICENSE
|
|
||||||
#
|
|
||||||
|
|
||||||
calamares_add_plugin( os-freebsd
|
|
||||||
TYPE job
|
|
||||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
|
||||||
SOURCES
|
|
||||||
FreeBSDJob.cpp
|
|
||||||
SHARED_LIB
|
|
||||||
NO_CONFIG
|
|
||||||
)
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
* License-Filename: LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "FreeBSDJob.h"
|
|
||||||
|
|
||||||
#include "CalamaresVersion.h"
|
|
||||||
#include "GlobalStorage.h"
|
|
||||||
#include "JobQueue.h"
|
|
||||||
#include "utils/Logger.h"
|
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
|
|
||||||
FreeBSDJob::FreeBSDJob( QObject* parent )
|
|
||||||
: Calamares::CppJob( parent )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FreeBSDJob::~FreeBSDJob() {}
|
|
||||||
|
|
||||||
|
|
||||||
QString
|
|
||||||
FreeBSDJob::prettyName() const
|
|
||||||
{
|
|
||||||
return tr( "FreeBSD Installation Job" );
|
|
||||||
}
|
|
||||||
|
|
||||||
Calamares::JobResult
|
|
||||||
FreeBSDJob::exec()
|
|
||||||
{
|
|
||||||
emit progress( 0.1 );
|
|
||||||
cDebug() << "[FREEBSD]";
|
|
||||||
|
|
||||||
Calamares::JobQueue::instance()->globalStorage()->debugDump();
|
|
||||||
emit progress( 0.5 );
|
|
||||||
|
|
||||||
QThread::sleep( 3 );
|
|
||||||
emit progress( 1.0 );
|
|
||||||
|
|
||||||
return Calamares::JobResult::ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
FreeBSDJob::setConfigurationMap( const QVariantMap& configurationMap )
|
|
||||||
{
|
|
||||||
// TODO: actually fetch something from that configuration
|
|
||||||
m_configurationMap = configurationMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( FreeBSDJobFactory, registerPlugin< FreeBSDJob >(); )
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
*
|
|
||||||
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
* License-Filename: LICENSE
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FREEBSDJOB_H
|
|
||||||
#define FREEBSDJOB_H
|
|
||||||
|
|
||||||
#include "CppJob.h"
|
|
||||||
#include "DllMacro.h"
|
|
||||||
#include "utils/PluginFactory.h"
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QVariantMap>
|
|
||||||
|
|
||||||
|
|
||||||
class PLUGINDLLEXPORT FreeBSDJob : public Calamares::CppJob
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit FreeBSDJob( QObject* parent = nullptr );
|
|
||||||
virtual ~FreeBSDJob() override;
|
|
||||||
|
|
||||||
QString prettyName() const override;
|
|
||||||
|
|
||||||
Calamares::JobResult exec() override;
|
|
||||||
|
|
||||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QVariantMap m_configurationMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( FreeBSDJobFactory )
|
|
||||||
|
|
||||||
#endif // FREEBSDJOB_H
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# === This file is part of Calamares - <https://github.com/calamares> ===
|
|
||||||
#
|
|
||||||
# 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/>.
|
|
||||||
#
|
|
||||||
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
# License-Filename: LICENSE
|
|
||||||
#
|
|
||||||
|
|
||||||
"""
|
|
||||||
=== NixOS Configuration
|
|
||||||
|
|
||||||
NixOS has its own "do all the things" configuration file which
|
|
||||||
declaratively handles what things need to be done in the target
|
|
||||||
system, and it has an existing tool to "execute" that declarative
|
|
||||||
specification. This module takes configuration values set by
|
|
||||||
Calamares viewmodules (e.g. the users module) and puts
|
|
||||||
them into the configuration file in the target system,
|
|
||||||
and then runs the necessary NixOS specific tools.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import libcalamares
|
|
||||||
import os
|
|
||||||
from time import gmtime, strftime, sleep
|
|
||||||
|
|
||||||
import gettext
|
|
||||||
_ = gettext.translation("calamares-python",
|
|
||||||
localedir=libcalamares.utils.gettext_path(),
|
|
||||||
languages=libcalamares.utils.gettext_languages(),
|
|
||||||
fallback=True).gettext
|
|
||||||
|
|
||||||
|
|
||||||
def pretty_name():
|
|
||||||
return _("NixOS Configuration.")
|
|
||||||
|
|
||||||
|
|
||||||
def run():
|
|
||||||
"""NixOS Configuration."""
|
|
||||||
libcalamares.utils.debug("LocaleDir=" +
|
|
||||||
str(libcalamares.utils.gettext_path()))
|
|
||||||
libcalamares.utils.debug("Languages=" +
|
|
||||||
str(libcalamares.utils.gettext_languages()))
|
|
||||||
|
|
||||||
# TODO: probably want to use the job configuration
|
|
||||||
# with a key "stage" to distinguish generate-config
|
|
||||||
# from execute-config; maybe it wants an "all" as well
|
|
||||||
# to do both.
|
|
||||||
accumulator = "*** Job configuration\n"
|
|
||||||
accumulator += str(libcalamares.job.configuration)
|
|
||||||
libcalamares.utils.debug(accumulator)
|
|
||||||
|
|
||||||
accumulator = "*** GlobalStorage configuration\n"
|
|
||||||
accumulator += "count: " + str(libcalamares.globalstorage.count()) + "\n"
|
|
||||||
accumulator += "keys: {}\n".format(str(libcalamares.globalstorage.keys()))
|
|
||||||
libcalamares.utils.debug(accumulator)
|
|
||||||
|
|
||||||
libcalamares.utils.debug("Run NixOS tools.")
|
|
||||||
|
|
||||||
libcalamares.job.setprogress( 0.1 )
|
|
||||||
sleep(1)
|
|
||||||
libcalamares.job.setprogress( 0.5 )
|
|
||||||
sleep(1)
|
|
||||||
libcalamares.job.setprogress( 1.0 )
|
|
||||||
|
|
||||||
sleep(3)
|
|
||||||
|
|
||||||
# To indicate an error, return a tuple of:
|
|
||||||
# (message, detailed-error-message)
|
|
||||||
return None
|
|
||||||
68
modules/packagechooser/CMakeLists.txt
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
#
|
||||||
|
find_package(${qtname} COMPONENTS Core Gui Widgets REQUIRED)
|
||||||
|
set(_extra_libraries "")
|
||||||
|
set(_extra_src "")
|
||||||
|
|
||||||
|
### OPTIONAL AppData XML support in PackageModel
|
||||||
|
#
|
||||||
|
#
|
||||||
|
option(BUILD_APPDATA "Support appdata: items in PackageChooser (requires QtXml)" ON)
|
||||||
|
if(BUILD_APPDATA)
|
||||||
|
find_package(${qtname} COMPONENTS Xml)
|
||||||
|
if(TARGET ${qtname}::Xml)
|
||||||
|
add_definitions(-DHAVE_APPDATA)
|
||||||
|
list(APPEND _extra_libraries ${qtname}::Xml)
|
||||||
|
list(APPEND _extra_src ItemAppData.cpp)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
### OPTIONAL AppStream support in PackageModel
|
||||||
|
#
|
||||||
|
#
|
||||||
|
option(BUILD_APPSTREAM "Support appstream: items in PackageChooser (requires libappstream-qt)" ON)
|
||||||
|
if(BUILD_APPSTREAM)
|
||||||
|
find_package(AppStreamQt)
|
||||||
|
set_package_properties(
|
||||||
|
AppStreamQt
|
||||||
|
PROPERTIES
|
||||||
|
DESCRIPTION "Support for AppStream (cache) data"
|
||||||
|
URL "https://github.com/ximion/appstream"
|
||||||
|
PURPOSE "AppStream provides package data"
|
||||||
|
TYPE OPTIONAL
|
||||||
|
)
|
||||||
|
if(AppStreamQt_FOUND)
|
||||||
|
add_definitions(-DHAVE_APPSTREAM_VERSION=${AppStreamQt_VERSION_MAJOR})
|
||||||
|
list(APPEND _extra_libraries AppStreamQt)
|
||||||
|
list(APPEND _extra_src ItemAppStream.cpp)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
calamares_add_plugin(packagechooser
|
||||||
|
TYPE viewmodule
|
||||||
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
|
SOURCES
|
||||||
|
Config.cpp
|
||||||
|
PackageChooserPage.cpp
|
||||||
|
PackageChooserViewStep.cpp
|
||||||
|
PackageModel.cpp
|
||||||
|
${_extra_src}
|
||||||
|
RESOURCES
|
||||||
|
packagechooser.qrc
|
||||||
|
UI
|
||||||
|
page_package.ui
|
||||||
|
LINK_PRIVATE_LIBRARIES
|
||||||
|
${_extra_libraries}
|
||||||
|
SHARED_LIB
|
||||||
|
)
|
||||||
|
|
||||||
|
# include(CalamaresAddTest)
|
||||||
|
# calamares_add_test(
|
||||||
|
# packagechoosertest
|
||||||
|
# GUI
|
||||||
|
# SOURCES Tests.cpp
|
||||||
|
# LIBRARIES calamares_viewmodule_packagechooser ${_extra_libraries}
|
||||||
|
# )
|
||||||
361
modules/packagechooser/Config.cpp
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2021 Anke Boersma <demm@kaosx.us>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_APPDATA
|
||||||
|
#include "ItemAppData.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_APPSTREAM_VERSION
|
||||||
|
#include "ItemAppStream.h"
|
||||||
|
#include <AppStreamQt/pool.h>
|
||||||
|
#include <memory>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
#include "compat/Variant.h"
|
||||||
|
#include "packages/Globals.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
/** @brief This removes any values from @p groups that match @p source
|
||||||
|
*
|
||||||
|
* This is used to remove duplicates from the netinstallAdd structure
|
||||||
|
* It iterates over @p groups and for each map in the list, if the
|
||||||
|
* "source" element matches @p source, it is removed from the returned
|
||||||
|
* list.
|
||||||
|
*/
|
||||||
|
static QVariantList
|
||||||
|
pruneNetinstallAdd( const QString& source, const QVariant& groups )
|
||||||
|
{
|
||||||
|
QVariantList newGroupList;
|
||||||
|
const QVariantList groupList = groups.toList();
|
||||||
|
for ( const QVariant& group : groupList )
|
||||||
|
{
|
||||||
|
QVariantMap groupMap = group.toMap();
|
||||||
|
if ( groupMap.value( "source", "" ).toString() != source )
|
||||||
|
{
|
||||||
|
newGroupList.append( groupMap );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newGroupList;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NamedEnumTable< PackageChooserMode >&
|
||||||
|
packageChooserModeNames()
|
||||||
|
{
|
||||||
|
static const NamedEnumTable< PackageChooserMode > names {
|
||||||
|
{ "optional", PackageChooserMode::Optional },
|
||||||
|
{ "required", PackageChooserMode::Required },
|
||||||
|
{ "optionalmultiple", PackageChooserMode::OptionalMultiple },
|
||||||
|
{ "requiredmultiple", PackageChooserMode::RequiredMultiple },
|
||||||
|
// and a bunch of aliases
|
||||||
|
{ "zero-or-one", PackageChooserMode::Optional },
|
||||||
|
{ "radio", PackageChooserMode::Required },
|
||||||
|
{ "one", PackageChooserMode::Required },
|
||||||
|
{ "set", PackageChooserMode::OptionalMultiple },
|
||||||
|
{ "zero-or-more", PackageChooserMode::OptionalMultiple },
|
||||||
|
{ "multiple", PackageChooserMode::RequiredMultiple },
|
||||||
|
{ "one-or-more", PackageChooserMode::RequiredMultiple }
|
||||||
|
};
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NamedEnumTable< PackageChooserMethod >&
|
||||||
|
PackageChooserMethodNames()
|
||||||
|
{
|
||||||
|
static const NamedEnumTable< PackageChooserMethod > names {
|
||||||
|
{ "legacy", PackageChooserMethod::Legacy },
|
||||||
|
{ "custom", PackageChooserMethod::Legacy },
|
||||||
|
{ "contextualprocess", PackageChooserMethod::Legacy },
|
||||||
|
{ "packages", PackageChooserMethod::Packages },
|
||||||
|
{ "netinstall-add", PackageChooserMethod::NetAdd },
|
||||||
|
{ "netinstall-select", PackageChooserMethod::NetSelect },
|
||||||
|
};
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::Config( QObject* parent )
|
||||||
|
: Calamares::ModuleSystem::Config( parent )
|
||||||
|
, m_model( new PackageListModel( this ) )
|
||||||
|
, m_mode( PackageChooserMode::Required )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::~Config() {}
|
||||||
|
|
||||||
|
const PackageItem&
|
||||||
|
Config::introductionPackage() const
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < m_model->packageCount(); ++i )
|
||||||
|
{
|
||||||
|
const auto& package = m_model->packageData( i );
|
||||||
|
if ( package.isNonePackage() )
|
||||||
|
{
|
||||||
|
return package;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PackageItem* defaultIntroduction = nullptr;
|
||||||
|
if ( !defaultIntroduction )
|
||||||
|
{
|
||||||
|
const auto name = QT_TR_NOOP( "Package Selection" );
|
||||||
|
const auto description
|
||||||
|
= QT_TR_NOOP( "Please pick a product from the list. The selected product will be installed." );
|
||||||
|
defaultIntroduction = new PackageItem( QString(), name, description );
|
||||||
|
defaultIntroduction->screenshot = QPixmap( QStringLiteral( ":/images/no-selection.png" ) );
|
||||||
|
defaultIntroduction->name = Calamares::Locale::TranslatedString( name, metaObject()->className() );
|
||||||
|
defaultIntroduction->description
|
||||||
|
= Calamares::Locale::TranslatedString( description, metaObject()->className() );
|
||||||
|
}
|
||||||
|
return *defaultIntroduction;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QString
|
||||||
|
make_gs_key( const Calamares::ModuleSystem::InstanceKey& key )
|
||||||
|
{
|
||||||
|
return QStringLiteral( "packagechooser_" ) + key.id();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Config::updateGlobalStorage( const QStringList& selected ) const
|
||||||
|
{
|
||||||
|
if ( m_packageChoice.has_value() )
|
||||||
|
{
|
||||||
|
cWarning() << "Inconsistent package choices -- both model and single-selection QML";
|
||||||
|
}
|
||||||
|
if ( m_method == PackageChooserMethod::Legacy )
|
||||||
|
{
|
||||||
|
QString value = selected.join( ',' );
|
||||||
|
Calamares::JobQueue::instance()->globalStorage()->insert( make_gs_key( m_defaultId ), value );
|
||||||
|
cDebug() << m_defaultId << "selected" << value;
|
||||||
|
}
|
||||||
|
else if ( m_method == PackageChooserMethod::Packages )
|
||||||
|
{
|
||||||
|
QStringList packageNames = m_model->getInstallPackagesForNames( selected );
|
||||||
|
cDebug() << m_defaultId << "packages to install" << packageNames;
|
||||||
|
Calamares::Packages::setGSPackageAdditions(
|
||||||
|
Calamares::JobQueue::instance()->globalStorage(), m_defaultId, packageNames );
|
||||||
|
}
|
||||||
|
else if ( m_method == PackageChooserMethod::NetAdd )
|
||||||
|
{
|
||||||
|
QVariantList netinstallDataList = m_model->getNetinstallDataForNames( selected );
|
||||||
|
if ( netinstallDataList.isEmpty() )
|
||||||
|
{
|
||||||
|
cWarning() << "No netinstall information found for " << selected;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If an earlier packagechooser instance added this data to global storage, combine them
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
if ( gs->contains( "netinstallAdd" ) )
|
||||||
|
{
|
||||||
|
netinstallDataList
|
||||||
|
+= pruneNetinstallAdd( QStringLiteral( "packageChooser" ), gs->value( "netinstallAdd" ) );
|
||||||
|
}
|
||||||
|
gs->insert( "netinstallAdd", netinstallDataList );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( m_method == PackageChooserMethod::NetSelect )
|
||||||
|
{
|
||||||
|
cDebug() << m_defaultId << "groups to select in netinstall" << selected;
|
||||||
|
QStringList newSelected = selected;
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
|
||||||
|
// If an earlier packagechooser instance added this data to global storage, combine them
|
||||||
|
if ( gs->contains( "netinstallSelect" ) )
|
||||||
|
{
|
||||||
|
auto selectedOrig = gs->value( "netinstallSelect" );
|
||||||
|
if ( selectedOrig.canConvert< QStringList >() )
|
||||||
|
{
|
||||||
|
newSelected += selectedOrig.toStringList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "Invalid NetinstallSelect data in global storage. Earlier selections purged";
|
||||||
|
}
|
||||||
|
gs->remove( "netinstallSelect" );
|
||||||
|
}
|
||||||
|
gs->insert( "netinstallSelect", newSelected );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "Unknown packagechooser method" << smash( m_method );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Config::updateGlobalStorage() const
|
||||||
|
{
|
||||||
|
if ( m_model->packageCount() > 0 )
|
||||||
|
{
|
||||||
|
cWarning() << "Inconsistent package choices -- both model and single-selection QML";
|
||||||
|
}
|
||||||
|
if ( m_method == PackageChooserMethod::Legacy )
|
||||||
|
{
|
||||||
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
|
if ( m_packageChoice.has_value() )
|
||||||
|
{
|
||||||
|
gs->insert( make_gs_key( m_defaultId ), m_packageChoice.value() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gs->remove( make_gs_key( m_defaultId ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( m_method == PackageChooserMethod::Packages )
|
||||||
|
{
|
||||||
|
cWarning() << "Unsupported single-selection packagechooser method 'Packages'";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cWarning() << "Unknown packagechooser method" << smash( m_method );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Config::setPackageChoice( const QString& packageChoice )
|
||||||
|
{
|
||||||
|
if ( packageChoice.isEmpty() )
|
||||||
|
{
|
||||||
|
m_packageChoice.reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_packageChoice = packageChoice;
|
||||||
|
}
|
||||||
|
emit packageChoiceChanged( m_packageChoice.value_or( QString() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
Config::prettyName() const
|
||||||
|
{
|
||||||
|
return m_stepName ? m_stepName->get() : tr( "Packages" );
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
Config::prettyStatus() const
|
||||||
|
{
|
||||||
|
return tr( "Install option: <strong>%1</strong>" ).arg( m_packageChoice.value_or( tr( "None" ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fillModel( PackageListModel* model, const QVariantList& items )
|
||||||
|
{
|
||||||
|
if ( items.isEmpty() )
|
||||||
|
{
|
||||||
|
cWarning() << "No *items* for PackageChooser module.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_APPSTREAM_VERSION
|
||||||
|
std::unique_ptr< AppStream::Pool > pool;
|
||||||
|
bool poolOk = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cDebug() << "Loading PackageChooser model items from config";
|
||||||
|
int item_index = 0;
|
||||||
|
for ( const auto& item_it : items )
|
||||||
|
{
|
||||||
|
++item_index;
|
||||||
|
QVariantMap item_map = item_it.toMap();
|
||||||
|
if ( item_map.isEmpty() )
|
||||||
|
{
|
||||||
|
cWarning() << "PackageChooser entry" << item_index << "is not valid.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( item_map.contains( "appdata" ) )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_XML
|
||||||
|
model->addPackage( fromAppData( item_map ) );
|
||||||
|
#else
|
||||||
|
cWarning() << "Loading AppData XML is not supported.";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if ( item_map.contains( "appstream" ) )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_APPSTREAM_VERSION
|
||||||
|
if ( !pool )
|
||||||
|
{
|
||||||
|
pool = std::make_unique< AppStream::Pool >();
|
||||||
|
pool->setLocale( QStringLiteral( "ALL" ) );
|
||||||
|
poolOk = pool->load();
|
||||||
|
}
|
||||||
|
if ( pool && poolOk )
|
||||||
|
{
|
||||||
|
model->addPackage( fromAppStream( *pool, item_map ) );
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
cWarning() << "Loading AppStream data is not supported.";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
model->addPackage( PackageItem( item_map ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cDebug() << Logger::SubEntry << "Loaded PackageChooser with" << model->packageCount() << "entries.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Config::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
|
{
|
||||||
|
m_mode = packageChooserModeNames().find( Calamares::getString( configurationMap, "mode" ),
|
||||||
|
PackageChooserMode::Required );
|
||||||
|
m_method = PackageChooserMethodNames().find( Calamares::getString( configurationMap, "method" ),
|
||||||
|
PackageChooserMethod::Legacy );
|
||||||
|
|
||||||
|
if ( m_method == PackageChooserMethod::Legacy )
|
||||||
|
{
|
||||||
|
cDebug() << "Using module ID" << m_defaultId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( configurationMap.contains( "items" ) )
|
||||||
|
{
|
||||||
|
fillModel( m_model, configurationMap.value( "items" ).toList() );
|
||||||
|
|
||||||
|
QString default_item_id = Calamares::getString( configurationMap, "default" );
|
||||||
|
if ( !default_item_id.isEmpty() )
|
||||||
|
{
|
||||||
|
for ( int item_n = 0; item_n < m_model->packageCount(); ++item_n )
|
||||||
|
{
|
||||||
|
QModelIndex item_idx = m_model->index( item_n, 0 );
|
||||||
|
QVariant item_id = m_model->data( item_idx, PackageListModel::IdRole );
|
||||||
|
|
||||||
|
if ( item_id.toString() == default_item_id )
|
||||||
|
{
|
||||||
|
m_defaultModelIndex = item_idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setPackageChoice( Calamares::getString( configurationMap, "packageChoice" ) );
|
||||||
|
if ( m_method != PackageChooserMethod::Legacy )
|
||||||
|
{
|
||||||
|
cWarning() << "Single-selection QML module must use 'Legacy' method.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool labels_ok = false;
|
||||||
|
auto labels = Calamares::getSubMap( configurationMap, "labels", labels_ok );
|
||||||
|
if ( labels_ok )
|
||||||
|
{
|
||||||
|
if ( labels.contains( "step" ) )
|
||||||
|
{
|
||||||
|
m_stepName = new Calamares::Locale::TranslatedString( labels, "step" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
128
modules/packagechooser/Config.h
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-FileCopyrightText: 2021 Anke Boersma <demm@kaosx.us>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PACKAGECHOOSER_CONFIG_H
|
||||||
|
#define PACKAGECHOOSER_CONFIG_H
|
||||||
|
|
||||||
|
#include "PackageModel.h"
|
||||||
|
|
||||||
|
#include "modulesystem/Config.h"
|
||||||
|
#include "modulesystem/InstanceKey.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
enum class PackageChooserMode
|
||||||
|
{
|
||||||
|
Optional, // zero or one
|
||||||
|
Required, // exactly one
|
||||||
|
OptionalMultiple, // zero or more
|
||||||
|
RequiredMultiple // one or more
|
||||||
|
};
|
||||||
|
|
||||||
|
const NamedEnumTable< PackageChooserMode >& packageChooserModeNames();
|
||||||
|
|
||||||
|
enum class PackageChooserMethod
|
||||||
|
{
|
||||||
|
Legacy, // use contextualprocess or other custom
|
||||||
|
Packages, // use the packages module
|
||||||
|
NetAdd, // adds packages to the netinstall module
|
||||||
|
NetSelect, // makes selections in the netinstall module
|
||||||
|
};
|
||||||
|
|
||||||
|
const NamedEnumTable< PackageChooserMethod >& PackageChooserMethodNames();
|
||||||
|
|
||||||
|
class Config : public Calamares::ModuleSystem::Config
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
/** @brief This is the single-select package-choice
|
||||||
|
*
|
||||||
|
* For (QML) modules that support only a single selection and
|
||||||
|
* just want to do things in a straightforward pick-this-one
|
||||||
|
* way, the packageChoice property is a (the) way to go.
|
||||||
|
*
|
||||||
|
* Writing to this property means that any other form of package-
|
||||||
|
* choice or selection is ignored.
|
||||||
|
*/
|
||||||
|
Q_PROPERTY( QString packageChoice READ packageChoice WRITE setPackageChoice NOTIFY packageChoiceChanged )
|
||||||
|
Q_PROPERTY( QString prettyStatus READ prettyStatus NOTIFY prettyStatusChanged FINAL )
|
||||||
|
|
||||||
|
public:
|
||||||
|
Config( QObject* parent = nullptr );
|
||||||
|
~Config() override;
|
||||||
|
|
||||||
|
/** @brief Sets the default Id for this Config
|
||||||
|
*
|
||||||
|
* The default Id is the (owning) module identifier for the config,
|
||||||
|
* and it is used when the Id read from the config file is empty.
|
||||||
|
* The **usual** configuration when using method *packages* is
|
||||||
|
* to rely on the default Id.
|
||||||
|
*/
|
||||||
|
void setDefaultId( const Calamares::ModuleSystem::InstanceKey& defaultId ) { m_defaultId = defaultId; }
|
||||||
|
void setConfigurationMap( const QVariantMap& ) override;
|
||||||
|
|
||||||
|
PackageChooserMode mode() const { return m_mode; }
|
||||||
|
PackageListModel* model() const { return m_model; }
|
||||||
|
QModelIndex defaultSelectionIndex() const { return m_defaultModelIndex; }
|
||||||
|
|
||||||
|
/** @brief Returns an "introductory package" which describes packagechooser
|
||||||
|
*
|
||||||
|
* If the model contains a "none" package, returns that one on
|
||||||
|
* the assumption that it is one to describe the whole; otherwise
|
||||||
|
* returns a totally generic description.
|
||||||
|
*/
|
||||||
|
const PackageItem& introductionPackage() const;
|
||||||
|
|
||||||
|
/** @brief Write selection to global storage
|
||||||
|
*
|
||||||
|
* Updates the GS keys for this packagechooser, marking all
|
||||||
|
* (and only) the packages in @p selected as selected.
|
||||||
|
*/
|
||||||
|
void updateGlobalStorage( const QStringList& selected ) const;
|
||||||
|
/** @brief Write selection to global storage
|
||||||
|
*
|
||||||
|
* Updates the GS keys for this packagechooser, marking **only**
|
||||||
|
* the package choice as selected. This assumes that the single-
|
||||||
|
* selection QML code is in use.
|
||||||
|
*/
|
||||||
|
void updateGlobalStorage() const;
|
||||||
|
|
||||||
|
QString packageChoice() const { return m_packageChoice.value_or( QString() ); }
|
||||||
|
void setPackageChoice( const QString& packageChoice );
|
||||||
|
|
||||||
|
QString prettyName() const;
|
||||||
|
QString prettyStatus() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void packageChoiceChanged( QString packageChoice );
|
||||||
|
void prettyStatusChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
PackageListModel* m_model = nullptr;
|
||||||
|
QModelIndex m_defaultModelIndex;
|
||||||
|
|
||||||
|
/// Selection mode for this module
|
||||||
|
PackageChooserMode m_mode = PackageChooserMode::Optional;
|
||||||
|
/// How this module stores to GS
|
||||||
|
PackageChooserMethod m_method = PackageChooserMethod::Legacy;
|
||||||
|
/// Value to use for id if none is set in the config file
|
||||||
|
Calamares::ModuleSystem::InstanceKey m_defaultId;
|
||||||
|
/** @brief QML selection (for single-selection approaches)
|
||||||
|
*
|
||||||
|
* If there is no value, then there has been no selection.
|
||||||
|
* Reading the property will return an empty QString.
|
||||||
|
*/
|
||||||
|
std::optional< QString > m_packageChoice;
|
||||||
|
Calamares::Locale::TranslatedString* m_stepName; // As it appears in the sidebar
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
225
modules/packagechooser/ItemAppData.cpp
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief Loading items from AppData XML files.
|
||||||
|
*
|
||||||
|
* Only used if QtXML is found, implements PackageItem::fromAppData().
|
||||||
|
*/
|
||||||
|
#include "PackageModel.h"
|
||||||
|
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
#include <QDomDocument>
|
||||||
|
#include <QDomNodeList>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
/** @brief try to load the given @p fileName XML document
|
||||||
|
*
|
||||||
|
* Returns a QDomDocument, which will be valid iff the file can
|
||||||
|
* be read and contains valid XML data.
|
||||||
|
*/
|
||||||
|
static inline QDomDocument
|
||||||
|
loadAppData( const QString& fileName )
|
||||||
|
{
|
||||||
|
QFile file( fileName );
|
||||||
|
if ( !file.open( QIODevice::ReadOnly ) )
|
||||||
|
{
|
||||||
|
return QDomDocument();
|
||||||
|
}
|
||||||
|
QDomDocument doc( "AppData" );
|
||||||
|
if ( !doc.setContent( &file ) )
|
||||||
|
{
|
||||||
|
file.close();
|
||||||
|
return QDomDocument();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief gets the text of child element @p tagName
|
||||||
|
*/
|
||||||
|
static inline QString
|
||||||
|
getChildText( const QDomNode& n, const QString& tagName )
|
||||||
|
{
|
||||||
|
QDomElement e = n.firstChildElement( tagName );
|
||||||
|
return e.isNull() ? QString() : e.text();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Gets a suitable screenshot path
|
||||||
|
*
|
||||||
|
* The <screenshots> element contains zero or more <screenshot>
|
||||||
|
* elements, which can have a *type* associated with them.
|
||||||
|
* Scan the screenshot elements, return the <image> path
|
||||||
|
* for the one labeled with type=default or, if there is no
|
||||||
|
* default, the first element.
|
||||||
|
*/
|
||||||
|
static inline QString
|
||||||
|
getScreenshotPath( const QDomNode& n )
|
||||||
|
{
|
||||||
|
QDomElement shotsNode = n.firstChildElement( "screenshots" );
|
||||||
|
if ( shotsNode.isNull() )
|
||||||
|
{
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QDomNodeList shotList = shotsNode.childNodes();
|
||||||
|
int firstScreenshot = -1; // Use which screenshot node?
|
||||||
|
for ( int i = 0; i < shotList.count(); ++i )
|
||||||
|
{
|
||||||
|
if ( !shotList.at( i ).isElement() )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
QDomElement e = shotList.at( i ).toElement();
|
||||||
|
if ( e.tagName() != "screenshot" )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// If none has the "type=default" attribute, use the first one
|
||||||
|
if ( firstScreenshot < 0 )
|
||||||
|
{
|
||||||
|
firstScreenshot = i;
|
||||||
|
}
|
||||||
|
// But type=default takes precedence.
|
||||||
|
if ( e.hasAttribute( "type" ) && e.attribute( "type" ) == "default" )
|
||||||
|
{
|
||||||
|
firstScreenshot = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( firstScreenshot >= 0 )
|
||||||
|
{
|
||||||
|
return shotList.at( firstScreenshot ).firstChildElement( "image" ).text();
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Returns language of the given element @p e
|
||||||
|
*
|
||||||
|
* Transforms the attribute value for xml:lang to something
|
||||||
|
* suitable for TranslatedString (e.g. [lang]).
|
||||||
|
*/
|
||||||
|
static inline QString
|
||||||
|
getLanguage( const QDomElement& e )
|
||||||
|
{
|
||||||
|
QString language = e.attribute( "xml:lang" );
|
||||||
|
if ( !language.isEmpty() )
|
||||||
|
{
|
||||||
|
language.replace( '-', '_' );
|
||||||
|
language.prepend( '[' );
|
||||||
|
language.append( ']' );
|
||||||
|
}
|
||||||
|
return language;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Scan the list of @p children for @p tagname elements and add them to the map
|
||||||
|
*
|
||||||
|
* Uses @p mapname instead of @p tagname for the entries in map @p m
|
||||||
|
* to allow renaming from XML to map keys (in particular for
|
||||||
|
* TranslatedString). Also transforms xml:lang attributes to suitable
|
||||||
|
* key-decorations on @p mapname.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
fillMap( QVariantMap& m, const QDomNodeList& children, const QString& tagname, const QString& mapname )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < children.count(); ++i )
|
||||||
|
{
|
||||||
|
if ( !children.at( i ).isElement() )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDomElement e = children.at( i ).toElement();
|
||||||
|
if ( e.tagName() != tagname )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m[ mapname + getLanguage( e ) ] = e.text();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief gets the <name> and <description> elements
|
||||||
|
*
|
||||||
|
* Builds up a map of the <name> elements (which may have a *lang*
|
||||||
|
* attribute to indicate translations and paragraphs of the
|
||||||
|
* <description> element (also with lang). Uses the <summary>
|
||||||
|
* elements to supplement the description if no description
|
||||||
|
* is available for a given language.
|
||||||
|
*
|
||||||
|
* Returns a map with keys suitable for use by TranslatedString.
|
||||||
|
*/
|
||||||
|
static inline QVariantMap
|
||||||
|
getNameAndSummary( const QDomNode& n )
|
||||||
|
{
|
||||||
|
QVariantMap m;
|
||||||
|
|
||||||
|
const QDomNodeList children = n.childNodes();
|
||||||
|
fillMap( m, children, "name", "name" );
|
||||||
|
fillMap( m, children, "summary", "description" );
|
||||||
|
|
||||||
|
const QDomElement description = n.firstChildElement( "description" );
|
||||||
|
if ( !description.isNull() )
|
||||||
|
{
|
||||||
|
fillMap( m, description.childNodes(), "p", "description" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageItem
|
||||||
|
fromAppData( const QVariantMap& item_map )
|
||||||
|
{
|
||||||
|
QString fileName = Calamares::getString( item_map, "appdata" );
|
||||||
|
if ( fileName.isEmpty() )
|
||||||
|
{
|
||||||
|
cWarning() << "Can't load AppData without a suitable key.";
|
||||||
|
return PackageItem();
|
||||||
|
}
|
||||||
|
cDebug() << "Loading AppData XML from" << fileName;
|
||||||
|
|
||||||
|
QDomDocument doc = loadAppData( fileName );
|
||||||
|
if ( doc.isNull() )
|
||||||
|
{
|
||||||
|
return PackageItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
QDomElement componentNode = doc.documentElement();
|
||||||
|
if ( !componentNode.isNull() && componentNode.tagName() == "component" )
|
||||||
|
{
|
||||||
|
// An "id" entry in the Calamares config overrides ID in the AppData
|
||||||
|
QString id = Calamares::getString( item_map, "id" );
|
||||||
|
if ( id.isEmpty() )
|
||||||
|
{
|
||||||
|
id = getChildText( componentNode, "id" );
|
||||||
|
}
|
||||||
|
if ( id.isEmpty() )
|
||||||
|
{
|
||||||
|
return PackageItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
// A "screenshot" entry in the Calamares config overrides AppData
|
||||||
|
QString screenshotPath = Calamares::getString( item_map, "screenshot" );
|
||||||
|
if ( screenshotPath.isEmpty() )
|
||||||
|
{
|
||||||
|
screenshotPath = getScreenshotPath( componentNode );
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap map = getNameAndSummary( componentNode );
|
||||||
|
map.insert( "id", id );
|
||||||
|
map.insert( "screenshot", screenshotPath );
|
||||||
|
|
||||||
|
return PackageItem( map );
|
||||||
|
}
|
||||||
|
|
||||||
|
return PackageItem();
|
||||||
|
}
|
||||||
28
modules/packagechooser/ItemAppData.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ITEMAPPDATA_H
|
||||||
|
#define ITEMAPPDATA_H
|
||||||
|
|
||||||
|
#include "PackageModel.h"
|
||||||
|
|
||||||
|
/** @brief Loads an AppData XML file and returns a PackageItem
|
||||||
|
*
|
||||||
|
* The @p map must have a key *appdata*. That is used as the
|
||||||
|
* primary source of information, but keys *id* and *screenshotPath*
|
||||||
|
* may be used to override parts of the AppData -- so that the
|
||||||
|
* ID is under the control of Calamares, and the screenshot can be
|
||||||
|
* forced to a local path available on the installation medium.
|
||||||
|
*
|
||||||
|
* Requires XML support in libcalamares, if not present will
|
||||||
|
* return invalid PackageItems.
|
||||||
|
*/
|
||||||
|
PackageItem fromAppData( const QVariantMap& map );
|
||||||
|
|
||||||
|
#endif
|
||||||
169
modules/packagechooser/ItemAppStream.cpp
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief Loading items from AppData XML files.
|
||||||
|
*
|
||||||
|
* Only used if QtXML is found, implements PackageItem::fromAppData().
|
||||||
|
*/
|
||||||
|
#include "PackageModel.h"
|
||||||
|
|
||||||
|
#include "locale/TranslationsModel.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
#include <AppStreamQt/image.h>
|
||||||
|
#include <AppStreamQt/pool.h>
|
||||||
|
#include <AppStreamQt/screenshot.h>
|
||||||
|
|
||||||
|
/// @brief Return number of pixels in a size, for < ordering purposes
|
||||||
|
static inline quint64
|
||||||
|
sizeOrder( const QSize& size )
|
||||||
|
{
|
||||||
|
return static_cast<quint64>(size.width()) * static_cast<quint64>(size.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Sets a screenshot in @p map from @p screenshot, if a usable one is found
|
||||||
|
static void
|
||||||
|
setScreenshot( QVariantMap& map, const AppStream::Screenshot& screenshot )
|
||||||
|
{
|
||||||
|
if ( screenshot.images().count() < 1 )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pick the smallest
|
||||||
|
QUrl url;
|
||||||
|
quint64 size = sizeOrder( screenshot.images().first().size() );
|
||||||
|
for ( const auto& img : screenshot.images() )
|
||||||
|
{
|
||||||
|
if ( sizeOrder( img.size() ) <= size )
|
||||||
|
{
|
||||||
|
url = img.url();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( url.isValid() )
|
||||||
|
{
|
||||||
|
map.insert( "screenshot", url.toString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Interpret an AppStream Component
|
||||||
|
static PackageItem
|
||||||
|
fromComponent( AppStream::Pool& pool, AppStream::Component& component )
|
||||||
|
{
|
||||||
|
#if HAVE_APPSTREAM_VERSION == 0
|
||||||
|
auto setActiveLocale = [&component](const QString & locale)
|
||||||
|
{
|
||||||
|
component.setActiveLocale( locale );
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
auto setActiveLocale = [&pool](const QString & locale)
|
||||||
|
{
|
||||||
|
pool.setLocale( locale );
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QVariantMap map;
|
||||||
|
map.insert( "id", component.id() );
|
||||||
|
map.insert( "package", component.packageNames().join( "," ) );
|
||||||
|
|
||||||
|
// Assume that the pool has loaded "ALL" locales, but it might be set
|
||||||
|
// to any of them; get the en_US locale as "untranslated" and then
|
||||||
|
// loop over Calamares locales (since there is no way to query for
|
||||||
|
// available locales in the Component) to see if there's anything else.
|
||||||
|
setActiveLocale( QStringLiteral( "en_US" ) );
|
||||||
|
QString en_name = component.name();
|
||||||
|
QString en_description = component.description();
|
||||||
|
map.insert( "name", en_name );
|
||||||
|
map.insert( "description", en_description );
|
||||||
|
|
||||||
|
for ( const QString& locale : Calamares::Locale::availableTranslations()->localeIds() )
|
||||||
|
{
|
||||||
|
setActiveLocale( locale );
|
||||||
|
QString name = component.name();
|
||||||
|
if ( name != en_name )
|
||||||
|
{
|
||||||
|
map.insert( QStringLiteral( "name[%1]" ).arg( locale ), name );
|
||||||
|
}
|
||||||
|
QString description = component.description();
|
||||||
|
if ( description != en_description )
|
||||||
|
{
|
||||||
|
map.insert( QStringLiteral( "description[%1]" ).arg( locale ), description );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_APPSTREAM_VERSION == 0
|
||||||
|
auto screenshots = component.screenshots();
|
||||||
|
#else
|
||||||
|
auto screenshots = component.screenshotsAll();
|
||||||
|
#endif
|
||||||
|
if ( screenshots.count() > 0 )
|
||||||
|
{
|
||||||
|
bool done = false;
|
||||||
|
for ( const auto& s : screenshots )
|
||||||
|
{
|
||||||
|
if ( s.isDefault() )
|
||||||
|
{
|
||||||
|
setScreenshot( map, s );
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( !done )
|
||||||
|
{
|
||||||
|
setScreenshot( map, screenshots.first() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PackageItem( map );
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageItem
|
||||||
|
fromAppStream( AppStream::Pool& pool, const QVariantMap& item_map )
|
||||||
|
{
|
||||||
|
QString appstreamId = Calamares::getString( item_map, "appstream" );
|
||||||
|
if ( appstreamId.isEmpty() )
|
||||||
|
{
|
||||||
|
cWarning() << "Can't load AppStream without a suitable appstreamId.";
|
||||||
|
return PackageItem();
|
||||||
|
}
|
||||||
|
cDebug() << "Loading AppStream data for" << appstreamId;
|
||||||
|
|
||||||
|
#if HAVE_APPSTREAM_VERSION == 0
|
||||||
|
auto itemList = pool.componentsById( appstreamId );
|
||||||
|
#else
|
||||||
|
auto itemList = pool.componentsById( appstreamId ).toList();
|
||||||
|
#endif
|
||||||
|
if ( itemList.count() < 1 )
|
||||||
|
{
|
||||||
|
cWarning() << "No AppStream data for" << appstreamId;
|
||||||
|
return PackageItem();
|
||||||
|
}
|
||||||
|
if ( itemList.count() > 1 )
|
||||||
|
{
|
||||||
|
cDebug() << "Multiple AppStream data for" << appstreamId << "using first.";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto r = fromComponent( pool, itemList.first() );
|
||||||
|
if ( r.isValid() )
|
||||||
|
{
|
||||||
|
QString id = Calamares::getString( item_map, "id" );
|
||||||
|
QString screenshotPath = Calamares::getString( item_map, "screenshot" );
|
||||||
|
if ( !id.isEmpty() )
|
||||||
|
{
|
||||||
|
r.id = id;
|
||||||
|
}
|
||||||
|
if ( !screenshotPath.isEmpty() )
|
||||||
|
{
|
||||||
|
r.screenshot = screenshotPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
34
modules/packagechooser/ItemAppStream.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ITEMAPPSTREAM_H
|
||||||
|
#define ITEMAPPSTREAM_H
|
||||||
|
|
||||||
|
#include "PackageModel.h"
|
||||||
|
|
||||||
|
namespace AppStream
|
||||||
|
{
|
||||||
|
class Pool;
|
||||||
|
} // namespace AppStream
|
||||||
|
|
||||||
|
/** @brief Loads an item from AppStream data.
|
||||||
|
*
|
||||||
|
* The @p map must have a key *appstream*. That is used as the
|
||||||
|
* primary source of information from the AppStream cache, but
|
||||||
|
* keys *id* and *screenshotPath* may be used to override parts
|
||||||
|
* of the AppStream data -- so that the ID is under the control
|
||||||
|
* of Calamares, and the screenshot can be forced to a local path
|
||||||
|
* available on the installation medium.
|
||||||
|
*
|
||||||
|
* Requires AppStreamQt, if not present will return invalid
|
||||||
|
* PackageItems.
|
||||||
|
*/
|
||||||
|
PackageItem fromAppStream( AppStream::Pool& pool, const QVariantMap& map );
|
||||||
|
|
||||||
|
#endif
|
||||||
145
modules/packagechooser/PackageChooserPage.cpp
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PackageChooserPage.h"
|
||||||
|
|
||||||
|
#include "ui_page_package.h"
|
||||||
|
|
||||||
|
#include "utils/Gui.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Retranslator.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
PackageChooserPage::PackageChooserPage( PackageChooserMode mode, QWidget* parent )
|
||||||
|
: QWidget( parent )
|
||||||
|
, ui( new Ui::PackageChooserPage )
|
||||||
|
, m_introduction( QString(),
|
||||||
|
QString(),
|
||||||
|
tr( "Package Selection" ),
|
||||||
|
tr( "Please pick a product from the list. The selected product will be installed." ) )
|
||||||
|
{
|
||||||
|
m_introduction.screenshot = QPixmap( QStringLiteral( ":/images/no-selection.png" ) );
|
||||||
|
|
||||||
|
ui->setupUi( this );
|
||||||
|
CALAMARES_RETRANSLATE( updateLabels(); );
|
||||||
|
|
||||||
|
switch ( mode )
|
||||||
|
{
|
||||||
|
case PackageChooserMode::Optional:
|
||||||
|
[[fallthrough]];
|
||||||
|
case PackageChooserMode::Required:
|
||||||
|
ui->products->setSelectionMode( QAbstractItemView::SingleSelection );
|
||||||
|
break;
|
||||||
|
case PackageChooserMode::OptionalMultiple:
|
||||||
|
[[fallthrough]];
|
||||||
|
case PackageChooserMode::RequiredMultiple:
|
||||||
|
ui->products->setSelectionMode( QAbstractItemView::ExtendedSelection );
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->products->setMinimumWidth( 10 * Calamares::defaultFontHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageChooserPage::currentChanged( const QModelIndex& index )
|
||||||
|
{
|
||||||
|
if ( !index.isValid() || !ui->products->selectionModel()->hasSelection() )
|
||||||
|
{
|
||||||
|
ui->productName->setText( m_introduction.name.get() );
|
||||||
|
ui->productScreenshot->setPixmap( m_introduction.screenshot );
|
||||||
|
ui->productDescription->setText( m_introduction.description.get() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto* model = ui->products->model();
|
||||||
|
|
||||||
|
ui->productName->setText( model->data( index, PackageListModel::NameRole ).toString() );
|
||||||
|
ui->productDescription->setText( model->data( index, PackageListModel::DescriptionRole ).toString() );
|
||||||
|
|
||||||
|
QPixmap currentScreenshot = model->data( index, PackageListModel::ScreenshotRole ).value< QPixmap >();
|
||||||
|
if ( currentScreenshot.isNull() )
|
||||||
|
{
|
||||||
|
ui->productScreenshot->setPixmap( m_introduction.screenshot );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->productScreenshot->setPixmap( currentScreenshot );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageChooserPage::updateLabels()
|
||||||
|
{
|
||||||
|
if ( ui && ui->products && ui->products->selectionModel() )
|
||||||
|
{
|
||||||
|
currentChanged( ui->products->selectionModel()->currentIndex() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentChanged( QModelIndex() );
|
||||||
|
}
|
||||||
|
emit selectionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageChooserPage::setModel( QAbstractItemModel* model )
|
||||||
|
{
|
||||||
|
ui->products->setModel( model );
|
||||||
|
currentChanged( QModelIndex() );
|
||||||
|
connect( ui->products->selectionModel(),
|
||||||
|
&QItemSelectionModel::selectionChanged,
|
||||||
|
this,
|
||||||
|
&PackageChooserPage::updateLabels );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageChooserPage::setSelection( const QModelIndex& index )
|
||||||
|
{
|
||||||
|
if ( index.isValid() )
|
||||||
|
{
|
||||||
|
ui->products->selectionModel()->select( index, QItemSelectionModel::Select );
|
||||||
|
}
|
||||||
|
currentChanged( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PackageChooserPage::hasSelection() const
|
||||||
|
{
|
||||||
|
return ui && ui->products && ui->products->selectionModel() && ui->products->selectionModel()->hasSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList
|
||||||
|
PackageChooserPage::selectedPackageIds() const
|
||||||
|
{
|
||||||
|
if ( !( ui && ui->products && ui->products->selectionModel() ) )
|
||||||
|
{
|
||||||
|
return QStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* model = ui->products->model();
|
||||||
|
QStringList ids;
|
||||||
|
for ( const auto& index : ui->products->selectionModel()->selectedIndexes() )
|
||||||
|
{
|
||||||
|
QString pid = model->data( index, PackageListModel::IdRole ).toString();
|
||||||
|
if ( !pid.isEmpty() )
|
||||||
|
{
|
||||||
|
ids.append( pid );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageChooserPage::setIntroduction( const PackageItem& item )
|
||||||
|
{
|
||||||
|
m_introduction.name = item.name;
|
||||||
|
m_introduction.description = item.description;
|
||||||
|
m_introduction.screenshot = item.screenshot;
|
||||||
|
}
|
||||||
57
modules/packagechooser/PackageChooserPage.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PACKAGECHOOSERPAGE_H
|
||||||
|
#define PACKAGECHOOSERPAGE_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "PackageModel.h"
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class PackageChooserPage;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
|
class PackageChooserPage : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit PackageChooserPage( PackageChooserMode mode, QWidget* parent = nullptr );
|
||||||
|
|
||||||
|
/// @brief Sets the data model for the listview
|
||||||
|
void setModel( QAbstractItemModel* model );
|
||||||
|
|
||||||
|
/// @brief Sets the introductory (no-package-selected) texts
|
||||||
|
void setIntroduction( const PackageItem& item );
|
||||||
|
/// @brief Selects a listview item
|
||||||
|
void setSelection( const QModelIndex& index );
|
||||||
|
/// @brief Is anything selected?
|
||||||
|
bool hasSelection() const;
|
||||||
|
/** @brief Get the list of selected ids
|
||||||
|
*
|
||||||
|
* This list may be empty (if none is selected).
|
||||||
|
*/
|
||||||
|
QStringList selectedPackageIds() const;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void currentChanged( const QModelIndex& index );
|
||||||
|
void updateLabels();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void selectionChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::PackageChooserPage* ui;
|
||||||
|
PackageItem m_introduction;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PACKAGECHOOSERPAGE_H
|
||||||
158
modules/packagechooser/PackageChooserViewStep.cpp
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PackageChooserViewStep.h"
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "PackageChooserPage.h"
|
||||||
|
#include "PackageModel.h"
|
||||||
|
|
||||||
|
#include "GlobalStorage.h"
|
||||||
|
#include "JobQueue.h"
|
||||||
|
#include "locale/TranslatableConfiguration.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/System.h"
|
||||||
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
CALAMARES_PLUGIN_FACTORY_DEFINITION( PackageChooserViewStepFactory, registerPlugin< PackageChooserViewStep >(); )
|
||||||
|
|
||||||
|
PackageChooserViewStep::PackageChooserViewStep( QObject* parent )
|
||||||
|
: Calamares::ViewStep( parent )
|
||||||
|
, m_config( new Config( this ) )
|
||||||
|
, m_widget( nullptr )
|
||||||
|
{
|
||||||
|
emit nextStatusChanged( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PackageChooserViewStep::~PackageChooserViewStep()
|
||||||
|
{
|
||||||
|
if ( m_widget && m_widget->parent() == nullptr )
|
||||||
|
{
|
||||||
|
m_widget->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString
|
||||||
|
PackageChooserViewStep::prettyName() const
|
||||||
|
{
|
||||||
|
return m_config->prettyName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QWidget*
|
||||||
|
PackageChooserViewStep::widget()
|
||||||
|
{
|
||||||
|
if ( !m_widget )
|
||||||
|
{
|
||||||
|
m_widget = new PackageChooserPage( m_config->mode(), nullptr );
|
||||||
|
connect( m_widget,
|
||||||
|
&PackageChooserPage::selectionChanged,
|
||||||
|
[ = ]() { emit nextStatusChanged( this->isNextEnabled() ); } );
|
||||||
|
hookupModel();
|
||||||
|
}
|
||||||
|
return m_widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
PackageChooserViewStep::isNextEnabled() const
|
||||||
|
{
|
||||||
|
if ( !m_widget )
|
||||||
|
{
|
||||||
|
// No way to have changed anything
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( m_config->mode() )
|
||||||
|
{
|
||||||
|
case PackageChooserMode::Optional:
|
||||||
|
case PackageChooserMode::OptionalMultiple:
|
||||||
|
// zero or one OR zero or more
|
||||||
|
return true;
|
||||||
|
case PackageChooserMode::Required:
|
||||||
|
case PackageChooserMode::RequiredMultiple:
|
||||||
|
// exactly one OR one or more
|
||||||
|
return m_widget->hasSelection();
|
||||||
|
}
|
||||||
|
__builtin_unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
PackageChooserViewStep::isBackEnabled() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
PackageChooserViewStep::isAtBeginning() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
PackageChooserViewStep::isAtEnd() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageChooserViewStep::onActivate()
|
||||||
|
{
|
||||||
|
if ( !m_widget->hasSelection() )
|
||||||
|
{
|
||||||
|
m_widget->setSelection( m_config->defaultSelectionIndex() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageChooserViewStep::onLeave()
|
||||||
|
{
|
||||||
|
m_config->updateGlobalStorage( m_widget->selectedPackageIds() );
|
||||||
|
}
|
||||||
|
|
||||||
|
Calamares::JobList
|
||||||
|
PackageChooserViewStep::jobs() const
|
||||||
|
{
|
||||||
|
Calamares::JobList l;
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap )
|
||||||
|
{
|
||||||
|
m_config->setDefaultId( moduleInstanceKey() );
|
||||||
|
m_config->setConfigurationMap( configurationMap );
|
||||||
|
|
||||||
|
if ( m_widget )
|
||||||
|
{
|
||||||
|
hookupModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageChooserViewStep::hookupModel()
|
||||||
|
{
|
||||||
|
if ( !m_config->model() || !m_widget )
|
||||||
|
{
|
||||||
|
cError() << "Can't hook up model until widget and model both exist.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_widget->setModel( m_config->model() );
|
||||||
|
m_widget->setIntroduction( m_config->introductionPackage() );
|
||||||
|
}
|
||||||
57
modules/packagechooser/PackageChooserViewStep.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PACKAGECHOOSERVIEWSTEP_H
|
||||||
|
#define PACKAGECHOOSERVIEWSTEP_H
|
||||||
|
|
||||||
|
#include "DllMacro.h"
|
||||||
|
#include "locale/TranslatableConfiguration.h"
|
||||||
|
#include "utils/PluginFactory.h"
|
||||||
|
#include "viewpages/ViewStep.h"
|
||||||
|
|
||||||
|
#include <QVariantMap>
|
||||||
|
|
||||||
|
class Config;
|
||||||
|
class PackageChooserPage;
|
||||||
|
|
||||||
|
class PLUGINDLLEXPORT PackageChooserViewStep : public Calamares::ViewStep
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit PackageChooserViewStep( QObject* parent = nullptr );
|
||||||
|
~PackageChooserViewStep() override;
|
||||||
|
|
||||||
|
QString prettyName() const override;
|
||||||
|
|
||||||
|
QWidget* widget() override;
|
||||||
|
|
||||||
|
bool isNextEnabled() const override;
|
||||||
|
bool isBackEnabled() const override;
|
||||||
|
|
||||||
|
bool isAtBeginning() const override;
|
||||||
|
bool isAtEnd() const override;
|
||||||
|
|
||||||
|
void onActivate() override;
|
||||||
|
void onLeave() override;
|
||||||
|
|
||||||
|
Calamares::JobList jobs() const override;
|
||||||
|
|
||||||
|
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void hookupModel();
|
||||||
|
|
||||||
|
Config* m_config;
|
||||||
|
PackageChooserPage* m_widget;
|
||||||
|
};
|
||||||
|
|
||||||
|
CALAMARES_PLUGIN_FACTORY_DECLARATION( PackageChooserViewStepFactory )
|
||||||
|
|
||||||
|
#endif // PACKAGECHOOSERVIEWSTEP_H
|
||||||
196
modules/packagechooser/PackageModel.cpp
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PackageModel.h"
|
||||||
|
|
||||||
|
#include "Branding.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Variant.h"
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
/** @brief A wrapper for Calamares::getSubMap that excludes the success param
|
||||||
|
*/
|
||||||
|
static QVariantMap
|
||||||
|
getSubMap( const QVariantMap& map, const QString& key )
|
||||||
|
{
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
return Calamares::getSubMap( map, key, success );
|
||||||
|
}
|
||||||
|
|
||||||
|
static QPixmap
|
||||||
|
loadScreenshot( const QString& path )
|
||||||
|
{
|
||||||
|
if ( QFileInfo::exists( path ) )
|
||||||
|
{
|
||||||
|
return QPixmap( path );
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* branding = Calamares::Branding::instance();
|
||||||
|
if ( !branding )
|
||||||
|
{
|
||||||
|
return QPixmap();
|
||||||
|
}
|
||||||
|
return QPixmap( branding->componentDirectory() + QStringLiteral( "/" ) + path );
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageItem::PackageItem() {}
|
||||||
|
|
||||||
|
PackageItem::PackageItem( const QString& a_id, const QString& a_name, const QString& a_description )
|
||||||
|
: id( a_id )
|
||||||
|
, name( a_name )
|
||||||
|
, description( a_description )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageItem::PackageItem( const QString& a_id,
|
||||||
|
const QString& a_name,
|
||||||
|
const QString& a_description,
|
||||||
|
const QString& screenshotPath )
|
||||||
|
: id( a_id )
|
||||||
|
, name( a_name )
|
||||||
|
, description( a_description )
|
||||||
|
, screenshot( screenshotPath )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageItem::PackageItem( const QVariantMap& item_map )
|
||||||
|
: id( Calamares::getString( item_map, "id" ) )
|
||||||
|
, name( Calamares::Locale::TranslatedString( item_map, "name" ) )
|
||||||
|
, description( Calamares::Locale::TranslatedString( item_map, "description" ) )
|
||||||
|
, screenshot( loadScreenshot( Calamares::getString( item_map, "screenshot" ) ) )
|
||||||
|
, packageNames( Calamares::getStringList( item_map, "packages" ) )
|
||||||
|
, netinstallData( getSubMap( item_map, "netinstall" ) )
|
||||||
|
{
|
||||||
|
if ( name.isEmpty() && id.isEmpty() )
|
||||||
|
{
|
||||||
|
name = QObject::tr( "No product" );
|
||||||
|
}
|
||||||
|
else if ( name.isEmpty() )
|
||||||
|
{
|
||||||
|
cWarning() << "PackageChooser item" << id << "has an empty name.";
|
||||||
|
}
|
||||||
|
if ( description.isEmpty() )
|
||||||
|
{
|
||||||
|
description = QObject::tr( "No description provided." );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageListModel::PackageListModel( QObject* parent )
|
||||||
|
: QAbstractListModel( parent )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageListModel::PackageListModel( PackageList&& items, QObject* parent )
|
||||||
|
: QAbstractListModel( parent )
|
||||||
|
, m_packages( std::move( items ) )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageListModel::~PackageListModel() {}
|
||||||
|
|
||||||
|
void
|
||||||
|
PackageListModel::addPackage( PackageItem&& p )
|
||||||
|
{
|
||||||
|
// Only add valid packages
|
||||||
|
if ( p.isValid() )
|
||||||
|
{
|
||||||
|
int c = m_packages.count();
|
||||||
|
beginInsertRows( QModelIndex(), c, c );
|
||||||
|
m_packages.append( p );
|
||||||
|
endInsertRows();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList
|
||||||
|
PackageListModel::getInstallPackagesForName( const QString& id ) const
|
||||||
|
{
|
||||||
|
for ( const auto& p : qAsConst( m_packages ) )
|
||||||
|
{
|
||||||
|
if ( p.id == id )
|
||||||
|
{
|
||||||
|
return p.packageNames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList
|
||||||
|
PackageListModel::getInstallPackagesForNames( const QStringList& ids ) const
|
||||||
|
{
|
||||||
|
QStringList l;
|
||||||
|
for ( const auto& p : qAsConst( m_packages ) )
|
||||||
|
{
|
||||||
|
if ( ids.contains( p.id ) )
|
||||||
|
{
|
||||||
|
l.append( p.packageNames );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList
|
||||||
|
PackageListModel::getNetinstallDataForNames( const QStringList& ids ) const
|
||||||
|
{
|
||||||
|
QVariantList l;
|
||||||
|
for ( auto& p : m_packages )
|
||||||
|
{
|
||||||
|
if ( ids.contains( p.id ) )
|
||||||
|
{
|
||||||
|
if ( !p.netinstallData.isEmpty() )
|
||||||
|
{
|
||||||
|
QVariantMap newData = p.netinstallData;
|
||||||
|
newData[ "source" ] = QStringLiteral( "packageChooser" );
|
||||||
|
l.append( newData );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PackageListModel::rowCount( const QModelIndex& index ) const
|
||||||
|
{
|
||||||
|
// For lists, valid indexes have zero children; only the root index has them
|
||||||
|
return index.isValid() ? 0 : m_packages.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant
|
||||||
|
PackageListModel::data( const QModelIndex& index, int role ) const
|
||||||
|
{
|
||||||
|
if ( !index.isValid() )
|
||||||
|
{
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
int row = index.row();
|
||||||
|
if ( row >= m_packages.count() || row < 0 )
|
||||||
|
{
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( role == Qt::DisplayRole /* Also PackageNameRole */ )
|
||||||
|
{
|
||||||
|
return m_packages[ row ].name.get();
|
||||||
|
}
|
||||||
|
else if ( role == DescriptionRole )
|
||||||
|
{
|
||||||
|
return m_packages[ row ].description.get();
|
||||||
|
}
|
||||||
|
else if ( role == ScreenshotRole )
|
||||||
|
{
|
||||||
|
return m_packages[ row ].screenshot;
|
||||||
|
}
|
||||||
|
else if ( role == IdRole )
|
||||||
|
{
|
||||||
|
return m_packages[ row ].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
135
modules/packagechooser/PackageModel.h
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PACKAGEMODEL_H
|
||||||
|
#define PACKAGEMODEL_H
|
||||||
|
|
||||||
|
#include "locale/TranslatableConfiguration.h"
|
||||||
|
#include "utils/NamedEnum.h"
|
||||||
|
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QObject>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QVector>
|
||||||
|
|
||||||
|
|
||||||
|
struct PackageItem
|
||||||
|
{
|
||||||
|
QString id;
|
||||||
|
Calamares::Locale::TranslatedString name;
|
||||||
|
Calamares::Locale::TranslatedString description;
|
||||||
|
QPixmap screenshot;
|
||||||
|
QStringList packageNames;
|
||||||
|
QVariantMap netinstallData;
|
||||||
|
|
||||||
|
/// @brief Create blank PackageItem
|
||||||
|
PackageItem();
|
||||||
|
/** @brief Creates a PackageItem from given strings
|
||||||
|
*
|
||||||
|
* This constructor sets all the text members,
|
||||||
|
* but leaves the screenshot blank. Set that separately.
|
||||||
|
*/
|
||||||
|
PackageItem( const QString& id, const QString& name, const QString& description );
|
||||||
|
|
||||||
|
/** @brief Creates a PackageItem from given strings.
|
||||||
|
*
|
||||||
|
* Set all the text members and load the screenshot from the given
|
||||||
|
* @p screenshotPath, which may be a QRC path (:/path/in/qrc) or
|
||||||
|
* a filesystem path, whatever QPixmap understands.
|
||||||
|
*/
|
||||||
|
PackageItem( const QString& id, const QString& name, const QString& description, const QString& screenshotPath );
|
||||||
|
|
||||||
|
/** @brief Creates a PackageItem from a QVariantMap
|
||||||
|
*
|
||||||
|
* This is intended for use when loading PackageItems from a
|
||||||
|
* configuration map. It will look up the various keys in the map
|
||||||
|
* and handle translation strings as well.
|
||||||
|
*
|
||||||
|
* The following keys are used:
|
||||||
|
* - *id*: the identifier for this item; if it is the empty string
|
||||||
|
* then this is the special "no-package".
|
||||||
|
* - *name* (and *name[lang]*): for the name and its translations
|
||||||
|
* - *description* (and *description[lang]*)
|
||||||
|
* - *screenshot*: a path to a screenshot for this package
|
||||||
|
* - *packages*: a list of package names
|
||||||
|
*/
|
||||||
|
PackageItem( const QVariantMap& map );
|
||||||
|
|
||||||
|
/** @brief Is this item valid?
|
||||||
|
*
|
||||||
|
* A valid item has an untranslated name available.
|
||||||
|
*/
|
||||||
|
bool isValid() const { return !name.isEmpty(); }
|
||||||
|
|
||||||
|
/** @brief Is this a (the) No-Package package?
|
||||||
|
*
|
||||||
|
* There should be at most one No-Package item in a collection
|
||||||
|
* of PackageItems. That one will be used to describe a
|
||||||
|
* "no package" situation.
|
||||||
|
*/
|
||||||
|
bool isNonePackage() const { return id.isEmpty(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
using PackageList = QVector< PackageItem >;
|
||||||
|
|
||||||
|
class PackageListModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PackageListModel( PackageList&& items, QObject* parent );
|
||||||
|
PackageListModel( QObject* parent );
|
||||||
|
~PackageListModel() override;
|
||||||
|
|
||||||
|
/** @brief Add a package @p to the model
|
||||||
|
*
|
||||||
|
* Only valid packages are added -- that is, they must have a name.
|
||||||
|
*/
|
||||||
|
void addPackage( PackageItem&& p );
|
||||||
|
|
||||||
|
int rowCount( const QModelIndex& index ) const override;
|
||||||
|
QVariant data( const QModelIndex& index, int role ) const override;
|
||||||
|
|
||||||
|
/// @brief Direct (non-abstract) access to package data
|
||||||
|
const PackageItem& packageData( int r ) const { return m_packages[ r ]; }
|
||||||
|
/// @brief Direct (non-abstract) count of package data
|
||||||
|
int packageCount() const { return m_packages.count(); }
|
||||||
|
|
||||||
|
/** @brief Does a name lookup (based on id) and returns the packages member
|
||||||
|
*
|
||||||
|
* If there is a package with the given @p id, returns its packages
|
||||||
|
* (e.g. the names of underlying packages to install for it); returns
|
||||||
|
* an empty list if the id is not found.
|
||||||
|
*/
|
||||||
|
QStringList getInstallPackagesForName( const QString& id ) const;
|
||||||
|
/** @brief Name-lookup all the @p ids and returns the packages members
|
||||||
|
*
|
||||||
|
* Concatenates installPackagesForName() for each id in @p ids.
|
||||||
|
*/
|
||||||
|
QStringList getInstallPackagesForNames( const QStringList& ids ) const;
|
||||||
|
|
||||||
|
/** @brief Does a name lookup (based on id) and returns the netinstall data
|
||||||
|
*
|
||||||
|
* If there is a package with an id in @p ids, returns their netinstall data
|
||||||
|
*
|
||||||
|
* returns a list of netinstall data or an emply list if none is found
|
||||||
|
*/
|
||||||
|
QVariantList getNetinstallDataForNames( const QStringList& ids ) const;
|
||||||
|
|
||||||
|
enum Roles : int
|
||||||
|
{
|
||||||
|
NameRole = Qt::DisplayRole,
|
||||||
|
DescriptionRole = Qt::UserRole,
|
||||||
|
ScreenshotRole,
|
||||||
|
IdRole
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
PackageList m_packages;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||