forked from artix/calamares-extensions
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f01b4ed2f8 | ||
|
|
ea762b0945 | ||
|
|
cae8acb4a4 | ||
|
|
ae204d0108 | ||
|
|
a2fae600c4 | ||
|
|
349acad491 | ||
|
|
9b4c4876bc | ||
|
|
cc02baed9a | ||
|
|
dfab089938 | ||
|
|
2dd9a7ba8a | ||
|
|
82f31f3cd9 | ||
|
|
c5b01a574d | ||
|
|
bc4789d57f | ||
|
|
0962b98494 | ||
|
|
108476c025 | ||
|
|
04a1bc9e2c | ||
|
|
bff5e485f4 | ||
|
|
3c838436c2 | ||
|
|
644c9cf4f3 | ||
|
|
dcaa378ddd | ||
|
|
14fd23dcef | ||
|
|
f4bc7052e0 | ||
|
|
4f0f48d99d | ||
|
|
1344880f2e |
@@ -29,15 +29,12 @@ rules of decent behavior in both communities are pretty much the same).
|
||||
|
||||
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`. The conversation is bridged with IRC
|
||||
on [Libera.Chat](https://libera.chat/).
|
||||
Responsiveness is best during the day
|
||||
in Europe, but feel free to idle. If you use IRC, **DO NOT** ask-and-leave. Keep
|
||||
that chat window open because it can easily take a few hours for
|
||||
someone to notice a message.
|
||||
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)
|
||||
* [](https://kiwiirc.com/client/irc.libera.chat/#calamares)
|
||||
|
||||
16
README.md
16
README.md
@@ -40,7 +40,10 @@ and documentation for the framework that Calamares ships with.
|
||||
(probably moreso than the default slideshow).
|
||||
- [`kaos_branding/`](branding/kaos_branding/branding.desc)
|
||||
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)
|
||||
is a copy of the Qt Company "Same Game" QML demo. It
|
||||
shows that **any** QML can be used for branding purposes.
|
||||
@@ -217,15 +220,12 @@ The API is loosely documented in the
|
||||
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`. The conversation is bridged with IRC
|
||||
on [Libera.Chat](https://libera.chat/).
|
||||
Responsiveness is best during the day
|
||||
in Europe, but feel free to idle. If you use IRC, **DO NOT** ask-and-leave. Keep
|
||||
that chat window open because it can easily take a few hours for
|
||||
someone to notice a message.
|
||||
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)
|
||||
* [](https://kiwiirc.com/client/irc.libera.chat/#calamares)
|
||||
|
||||
101
branding/kaos_branding/about.qml
Normal file
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
|
||||
|
||||
welcomeStyleCalamares: false
|
||||
|
||||
# Should the welcome image (productWelcome, below) be scaled
|
||||
# up beyond its natural size?
|
||||
welcomeExpandingLogo: true
|
||||
|
||||
windowExpanding: normal
|
||||
windowSize: 920px,630px
|
||||
windowPlacement: center
|
||||
|
||||
sidebar: qml,bottom
|
||||
navigation: qml,right
|
||||
|
||||
strings:
|
||||
productName: KaOS
|
||||
shortProductName: KaOS
|
||||
version: 2018.03
|
||||
version: 2022.08
|
||||
shortVersion: KaOS
|
||||
versionedName: KaOS 2018.03
|
||||
versionedName: KaOS 2022.08
|
||||
shortVersionedName: KaOS 2018.03
|
||||
bootloaderEntryName: KaOS
|
||||
productUrl: https://kaosx.us/
|
||||
supportUrl: https://kaosx.us/docs/
|
||||
knownIssuesUrl: https://kaosx.us/pages/download/#known-issues
|
||||
releaseNotesUrl: https://kaosx.us/pages/release_notes
|
||||
donateUrl: https://kaosx.us/about/donors
|
||||
|
||||
images:
|
||||
productLogo: "kaos.png"
|
||||
@@ -27,6 +37,7 @@ slideshow: "show.qml"
|
||||
slideshowAPI: 1
|
||||
|
||||
style:
|
||||
sidebarBackground: "#bdc3c7"
|
||||
sidebarText: "#1F1F1F"
|
||||
sidebarTextSelect: "#3498DB"
|
||||
SidebarBackground: "#bdc3c7"
|
||||
SidebarText: "#1F1F1F"
|
||||
SidebarTextCurrent: "#3498DB"
|
||||
SidebarBackgroundCurrent: "#eff0f1"
|
||||
|
||||
224
branding/kaos_branding/calamares-navigation.qml
Normal file
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
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
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 |
Binary file not shown.
|
Before Width: | Height: | Size: 292 KiB After Width: | Height: | Size: 106 KiB |
15
branding/kaos_branding/pan-end-symbolic.svg
Normal file
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
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
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> ===
|
||||
*
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,13 +25,12 @@ Presentation
|
||||
id: presentation
|
||||
|
||||
Timer {
|
||||
id: advanceTimer
|
||||
interval: 5000
|
||||
running: false
|
||||
repeat: true
|
||||
onTriggered: presentation.goToNextSlide()
|
||||
}
|
||||
|
||||
|
||||
Slide {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -38,7 +38,7 @@ Presentation
|
||||
id: background
|
||||
source: "1.svg"
|
||||
anchors.fill: parent
|
||||
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: 0
|
||||
@@ -96,15 +96,15 @@ Presentation
|
||||
anchors.horizontalCenterOffset: -100
|
||||
font.pixelSize: parent.width *.015
|
||||
color: 'white'
|
||||
text: qsTr("The default Office Suite is Calligra.<br/>"+
|
||||
"LibreOffice is available in the repositories. <br/>")
|
||||
text: qsTr("The default Office Suite is LibreOffice.<br/>"+
|
||||
"Calligra is available in the repositories. <br/>")
|
||||
wrapMode: Text.WordWrap
|
||||
width: 450
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Slide {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -120,7 +120,7 @@ Presentation
|
||||
font.pixelSize: parent.width *.015
|
||||
color: 'white'
|
||||
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/>")
|
||||
wrapMode: Text.WordWrap
|
||||
width: 450
|
||||
@@ -128,7 +128,7 @@ Presentation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Slide {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -150,7 +150,7 @@ Presentation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Slide {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -172,6 +172,4 @@ Presentation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: advanceTimer.running = true
|
||||
}
|
||||
|
||||
@@ -30,6 +30,13 @@ Config::setConfigurationMap( const QVariantMap& cfgMap )
|
||||
m_device = getString( cfgMap, "device", "(unknown)" );
|
||||
m_userInterface = getString( cfgMap, "userInterface", "(unknown)" );
|
||||
m_version = getString( cfgMap, "version", "(unknown)" );
|
||||
|
||||
m_reservedUsernames = getStringList( cfgMap, "reservedUsernames", QStringList { "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" } );
|
||||
|
||||
// ensure m_cmdUsermod matches m_username
|
||||
m_username = getString( cfgMap, "username", "user" );
|
||||
m_userPasswordNumeric = getBool( cfgMap, "userPasswordNumeric", true );
|
||||
|
||||
@@ -54,6 +61,8 @@ Config::setConfigurationMap( const QVariantMap& cfgMap )
|
||||
|
||||
m_cmdInternalStoragePrepare = getString( cfgMap, "cmdInternalStoragePrepare", "ondev-internal-storage-prepare" );
|
||||
m_cmdPasswd = getString( cfgMap, "cmdPasswd", "passwd" );
|
||||
m_cmdUsermod = getString( cfgMap, "cmdUsermod", "xargs -I{} -n1 usermod -m -d /home/{} -l {} -c {} user");
|
||||
|
||||
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" );
|
||||
@@ -68,6 +77,7 @@ Config::createJobs()
|
||||
/* Put users job in queue (should run after unpackfs) */
|
||||
Calamares::Job* j = new UsersJob( m_featureSshd,
|
||||
m_cmdPasswd,
|
||||
m_cmdUsermod,
|
||||
cmdSshd,
|
||||
m_cmdSshdUseradd,
|
||||
m_isSshEnabled,
|
||||
@@ -132,6 +142,13 @@ Config::runPartitionJobThenLeave( bool b )
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Config::setUsername( const QString& username )
|
||||
{
|
||||
m_username = username;
|
||||
emit usernameChanged( m_username );
|
||||
}
|
||||
|
||||
void
|
||||
Config::setUserPassword( const QString& userPassword )
|
||||
{
|
||||
|
||||
@@ -20,8 +20,11 @@ class Config : public QObject
|
||||
Q_PROPERTY( QString userInterface READ userInterface CONSTANT FINAL )
|
||||
Q_PROPERTY( QString version READ version CONSTANT FINAL )
|
||||
|
||||
/* reserved usernames (user_pass, ssh_credentials )*/
|
||||
Q_PROPERTY( QStringList reservedUsernames READ reservedUsernames CONSTANT FINAL )
|
||||
|
||||
/* default user */
|
||||
Q_PROPERTY( QString username READ username CONSTANT FINAL )
|
||||
Q_PROPERTY( QString username READ username WRITE setUsername NOTIFY usernameChanged )
|
||||
Q_PROPERTY( QString userPassword READ userPassword WRITE setUserPassword NOTIFY userPasswordChanged )
|
||||
Q_PROPERTY( bool userPasswordNumeric READ userPasswordNumeric CONSTANT FINAL )
|
||||
|
||||
@@ -72,13 +75,17 @@ public:
|
||||
QString userInterface() const { return m_userInterface; }
|
||||
QString version() const { return m_version; }
|
||||
|
||||
/* default user */
|
||||
/* reserved usernames (user_pass, ssh_credentials) */
|
||||
QStringList reservedUsernames() const { return m_reservedUsernames; };
|
||||
|
||||
/* user */
|
||||
QString username() const { return m_username; }
|
||||
QString userPassword() const { return m_userPassword; }
|
||||
void setUsername( const QString& username );
|
||||
void setUserPassword( const QString& userPassword );
|
||||
bool userPasswordNumeric() const { return m_userPasswordNumeric; }
|
||||
|
||||
/* ssh server + credetials */
|
||||
/* ssh server + credentials */
|
||||
bool featureSshd() { return m_featureSshd; }
|
||||
QString sshdUsername() const { return m_sshdUsername; }
|
||||
QString sshdPassword() const { return m_sshdPassword; }
|
||||
@@ -120,6 +127,7 @@ public:
|
||||
|
||||
/* users job */
|
||||
QString cmdPasswd() const { return m_cmdPasswd; }
|
||||
QString cmdUsermod() const { return m_cmdUsermod; }
|
||||
QString cmdSshdEnable() const { return m_cmdSshdEnable; }
|
||||
QString cmdSshdDisable() const { return m_cmdSshdDisable; }
|
||||
QString cmdSshdUseradd() const { return m_cmdSshdUseradd; }
|
||||
@@ -135,6 +143,9 @@ private:
|
||||
QString m_userInterface;
|
||||
QString m_version;
|
||||
|
||||
/* reserved usernames (user_pass, ssh_credentials) */
|
||||
QStringList m_reservedUsernames;
|
||||
|
||||
/* default user */
|
||||
QString m_username;
|
||||
QString m_userPassword;
|
||||
@@ -172,6 +183,7 @@ private:
|
||||
|
||||
/* users job */
|
||||
QString m_cmdPasswd;
|
||||
QString m_cmdUsermod;
|
||||
QString m_cmdSshdEnable;
|
||||
QString m_cmdSshdDisable;
|
||||
QString m_cmdSshdUseradd;
|
||||
@@ -181,6 +193,7 @@ signals:
|
||||
|
||||
/* default user */
|
||||
void userPasswordChanged( QString userPassword );
|
||||
void usernameChanged( QString username );
|
||||
|
||||
/* ssh server + credentials */
|
||||
void sshdUsernameChanged( QString sshdUsername );
|
||||
|
||||
@@ -118,7 +118,7 @@ PartitionJob::exec()
|
||||
const QString pathRoot = "/";
|
||||
|
||||
ProcessResult res
|
||||
= System::runCommand( System::RunLocation::RunInHost, args, pathRoot, stdInput, chrono::seconds( 120 ) );
|
||||
= System::runCommand( System::RunLocation::RunInHost, args, pathRoot, stdInput, chrono::seconds( 600 ) );
|
||||
if ( res.getExitCode() )
|
||||
{
|
||||
return JobResult::error( "Command failed:<br><br>"
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
UsersJob::UsersJob( bool featureSshd,
|
||||
const QString& cmdPasswd,
|
||||
const QString& cmdUsermod,
|
||||
const QString& cmdSshd,
|
||||
const QString& cmdSshdUseradd,
|
||||
bool isSshEnabled,
|
||||
@@ -24,6 +25,7 @@ UsersJob::UsersJob( bool featureSshd,
|
||||
: Calamares::Job()
|
||||
, m_featureSshd( featureSshd )
|
||||
, m_cmdPasswd( cmdPasswd )
|
||||
, m_cmdUsermod( cmdUsermod )
|
||||
, m_cmdSshd( cmdSshd )
|
||||
, m_cmdSshdUseradd( cmdSshdUseradd )
|
||||
, m_isSshEnabled( isSshEnabled )
|
||||
@@ -49,9 +51,11 @@ UsersJob::exec()
|
||||
using namespace std;
|
||||
|
||||
QList< QPair< QStringList, QString > > commands = {
|
||||
{ { "sh", "-c", m_cmdPasswd + " " + m_username }, m_password + "\n" + m_password + "\n" },
|
||||
{ { "sh", "-c", m_cmdUsermod }, m_username + "\n" }
|
||||
};
|
||||
|
||||
commands.append( { { "sh", "-c", m_cmdPasswd + " " + m_username }, m_password + "\n" + m_password + "\n" } );
|
||||
|
||||
if ( m_featureSshd )
|
||||
{
|
||||
commands.append( { { "sh", "-c", m_cmdSshd }, QString() } );
|
||||
|
||||
@@ -10,6 +10,7 @@ class UsersJob : public Calamares::Job
|
||||
public:
|
||||
UsersJob( bool featureSshd,
|
||||
const QString& cmdPasswd,
|
||||
const QString& cmdUsermod,
|
||||
const QString& cmdSshd,
|
||||
const QString& cmdSshdUseradd,
|
||||
bool isSshEnabled,
|
||||
@@ -26,6 +27,7 @@ public:
|
||||
private:
|
||||
bool m_featureSshd;
|
||||
QString m_cmdPasswd;
|
||||
QString m_cmdUsermod;
|
||||
QString m_cmdSshd;
|
||||
QString m_cmdSshdUseradd;
|
||||
bool m_isSshEnabled;
|
||||
|
||||
@@ -22,13 +22,13 @@ Item {
|
||||
id: mainText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
anchors.topMargin: 25
|
||||
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>";
|
||||
" device until it is done.<br>";
|
||||
|
||||
if (config.installFromExternalToInternal) {
|
||||
ret += "<b>After the installation, your device will shutdown" +
|
||||
@@ -44,14 +44,14 @@ Item {
|
||||
return ret;
|
||||
}())
|
||||
|
||||
width: 500
|
||||
width: 550
|
||||
}
|
||||
|
||||
Button {
|
||||
id: firstButton
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: mainText.bottom
|
||||
anchors.topMargin: 40
|
||||
anchors.topMargin: 20
|
||||
width: 500
|
||||
|
||||
text: qsTr("Install")
|
||||
|
||||
@@ -26,8 +26,45 @@ bogus: true
|
||||
# version: "(unknown)"
|
||||
|
||||
## Default username (for which the password will be set)
|
||||
## Ensure also cmdUsermod command matches the default user, so it can be changed if desired.
|
||||
# username: "user"
|
||||
|
||||
## reserved usernames (for user_pass username prompt and ssh_credentials)
|
||||
# reservedUsernames:
|
||||
# - 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
|
||||
|
||||
#######
|
||||
### Target device information
|
||||
#######
|
||||
@@ -118,6 +155,10 @@ bogus: true
|
||||
### Commands running in the target OS (chroot)
|
||||
#######
|
||||
|
||||
## Change the username for the default user
|
||||
## Stdin: username with \n
|
||||
# cmdUsermod: "xargs -I{} -n1 usermod -m -d /home/{} -l {} -c {} user"
|
||||
|
||||
## Set the password for default user and sshd user
|
||||
## Arguments: <username>
|
||||
## Stdin: password twice, each time with \n
|
||||
|
||||
@@ -253,7 +253,7 @@ Page
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Input validation: user-screens (user_pass, ssh_credentials) */
|
||||
/* Input validation: user-screens (fde_pass, user_pass, ssh_credentials) */
|
||||
function validatePin(userPin, userPinRepeat, errorText) {
|
||||
var pin = userPin.text;
|
||||
var repeat = userPinRepeat.text;
|
||||
@@ -278,47 +278,12 @@ Page
|
||||
|
||||
return validationFailureClear(errorText);
|
||||
}
|
||||
function validateSshdUsername(username, errorText) {
|
||||
function validateUsername(username, errorText, extraReservedUsernames = []) {
|
||||
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",
|
||||
]
|
||||
var reserved = config.reservedUsernames.concat(extraReservedUsernames);
|
||||
|
||||
/* Validate characters */
|
||||
for (var i=0; i<name.length; i++) {
|
||||
for (var i = 0; i < name.length; i++) {
|
||||
if (i) {
|
||||
if (!name[i].match(/^[a-z0-9_-]$/))
|
||||
return validationFailure(errorText,
|
||||
@@ -335,16 +300,20 @@ Page
|
||||
}
|
||||
|
||||
/* Validate against reserved usernames */
|
||||
for (var i=0;i<reserved.length;i++) {
|
||||
for (var i = 0; i < reserved.length; i++) {
|
||||
if (name == reserved[i])
|
||||
return validationFailure(errorText, "Username '" +
|
||||
reserved[i] +
|
||||
"' is reserved.")
|
||||
"' is reserved.");
|
||||
}
|
||||
|
||||
/* Passed */
|
||||
return validationFailureClear(errorText);
|
||||
}
|
||||
|
||||
function validateSshdUsername(username, errorText) {
|
||||
return validateUsername(username, errorText, [config.username]);
|
||||
}
|
||||
function validateSshdPassword(password, passwordRepeat, errorText) {
|
||||
var pass = password.text;
|
||||
var repeat = passwordRepeat.text;
|
||||
@@ -352,10 +321,10 @@ Page
|
||||
if (pass == "")
|
||||
return validationFailure(errorText);
|
||||
|
||||
if (pass.length < 8)
|
||||
if (pass.length < 6)
|
||||
return validationFailure(errorText,
|
||||
"Too short: needs at least 8" +
|
||||
" characters.");
|
||||
"Too short: needs at least 6" +
|
||||
" digits/characters.");
|
||||
|
||||
if (repeat == "")
|
||||
return validationFailure(errorText);
|
||||
@@ -365,8 +334,6 @@ Page
|
||||
|
||||
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)
|
||||
@@ -407,10 +374,10 @@ Page
|
||||
"\n" +
|
||||
allowed_chars_multiline());
|
||||
|
||||
if (pass.length < 8)
|
||||
if (pass.length < 6)
|
||||
return validationFailure(errorText,
|
||||
"Too short: needs at least 8" +
|
||||
" characters.");
|
||||
"Too short: needs at least 6" +
|
||||
" digits/characters.");
|
||||
|
||||
if (repeat == "")
|
||||
return validationFailure(errorText);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<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>user_pass.qml</file> <!-- default user: username, 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 -->
|
||||
|
||||
@@ -12,16 +12,18 @@ import QtQuick.Window 2.3
|
||||
import QtQuick.VirtualKeyboard 2.1
|
||||
|
||||
Item {
|
||||
property var placeholder: (config.userPasswordNumeric
|
||||
property var passPlaceholder: (config.userPasswordNumeric
|
||||
? "PIN"
|
||||
: "Password")
|
||||
property var hints: (config.userPasswordNumeric
|
||||
? Qt.ImhDigitsOnly
|
||||
: Qt.ImhPreferLowercase)
|
||||
property var validateFunc: (config.userPasswordNumeric
|
||||
property var validatePassFunc: (config.userPasswordNumeric
|
||||
? validatePin
|
||||
: validatePassword);
|
||||
|
||||
property var validateNameFunc: validateUsername;
|
||||
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
@@ -30,12 +32,38 @@ Item {
|
||||
height: parent.height
|
||||
|
||||
Text {
|
||||
id: description
|
||||
id: usernameDescription
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 30
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
text: (function() {
|
||||
return "Set the username of your user. The default" +
|
||||
" username is \"" + config.username + "\".";
|
||||
}())
|
||||
|
||||
width: 500
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: username
|
||||
anchors.top: usernameDescription.bottom
|
||||
placeholderText: qsTr("Username")
|
||||
onTextChanged: validateNameFunc(username, errorText)
|
||||
text: config.username
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: 50
|
||||
width: 500
|
||||
}
|
||||
|
||||
Text {
|
||||
id: userPassDescription
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: username.bottom
|
||||
anchors.topMargin: 30
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
text: (function() {
|
||||
if (config.userPasswordNumeric) {
|
||||
return "Set the numeric password of your user. The" +
|
||||
@@ -53,10 +81,10 @@ Item {
|
||||
|
||||
TextField {
|
||||
id: userPass
|
||||
anchors.top: description.bottom
|
||||
placeholderText: qsTr(placeholder)
|
||||
anchors.top: userPassDescription.bottom
|
||||
placeholderText: qsTr(passPlaceholder)
|
||||
echoMode: TextInput.Password
|
||||
onTextChanged: validateFunc(userPass, userPassRepeat, errorText)
|
||||
onTextChanged: validatePassFunc(userPass, userPassRepeat, errorText)
|
||||
text: config.userPassword
|
||||
|
||||
/* Let the virtual keyboard change to digits only */
|
||||
@@ -75,10 +103,10 @@ Item {
|
||||
TextField {
|
||||
id: userPassRepeat
|
||||
anchors.top: userPass.bottom
|
||||
placeholderText: qsTr(placeholder + " (repeat)")
|
||||
placeholderText: qsTr(passPlaceholder + " (repeat)")
|
||||
inputMethodHints: hints
|
||||
echoMode: TextInput.Password
|
||||
onTextChanged: validateFunc(userPass, userPassRepeat, errorText)
|
||||
onTextChanged: validatePassFunc(userPass, userPassRepeat, errorText)
|
||||
text: config.userPassword
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -105,8 +133,9 @@ Item {
|
||||
|
||||
text: qsTr("Continue")
|
||||
onClicked: {
|
||||
if (validateFunc(userPass, userPassRepeat, errorText)) {
|
||||
if (validatePassFunc(userPass, userPassRepeat, errorText) && validateNameFunc(username, errorText)) {
|
||||
config.userPassword = userPass.text;
|
||||
config.username = username.text;
|
||||
navNext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ Page
|
||||
anchors.topMargin: 150
|
||||
wrapMode: Text.WordWrap
|
||||
text: "Formatting and mounting target partition. This may" +
|
||||
" take up to two minutes, please be patient."
|
||||
" take up to ten minutes, please be patient."
|
||||
width: 500
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ calamares_add_plugin( unpackfsc
|
||||
# The workers for differently-packed filesystems
|
||||
Runners.cpp
|
||||
FSArchiverRunner.cpp
|
||||
TarballRunner.cpp
|
||||
UnsquashRunner.cpp
|
||||
SHARED_LIB
|
||||
)
|
||||
|
||||
@@ -15,46 +15,11 @@
|
||||
#include <QProcess>
|
||||
|
||||
static constexpr const int chunk_size = 137;
|
||||
|
||||
Calamares::JobResult
|
||||
FSArchiverRunner::run()
|
||||
static const QString&
|
||||
toolName()
|
||||
{
|
||||
const QString toolName = QStringLiteral( "fsarchiver" );
|
||||
|
||||
if ( !checkSourceExists() )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
tr( "Invalid fsarchiver configuration" ),
|
||||
tr( "The source archive <i>%1</i> does not exist." ).arg( m_source ),
|
||||
Calamares::JobResult::InvalidConfiguration );
|
||||
}
|
||||
|
||||
QString fsarchiverExecutable;
|
||||
if ( !checkToolExists( toolName, fsarchiverExecutable ) )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
tr( "Missing tools" ),
|
||||
tr( "The <i>%1</i> tool is not installed on the system." ).arg( toolName ),
|
||||
Calamares::JobResult::MissingRequirements );
|
||||
}
|
||||
|
||||
const QString destinationPath = CalamaresUtils::System::instance()->targetPath( m_destination );
|
||||
if ( destinationPath.isEmpty() )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
tr( "Invalid fsarchiver configuration" ),
|
||||
tr( "No destination could be found for <i>%1</i>." ).arg( m_destination ),
|
||||
Calamares::JobResult::InvalidConfiguration );
|
||||
}
|
||||
|
||||
Calamares::Utils::Runner r( { fsarchiverExecutable,
|
||||
QStringLiteral( "-v" ),
|
||||
QStringLiteral( "restdir" ),
|
||||
m_source,
|
||||
destinationPath } );
|
||||
r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing();
|
||||
connect( &r, &decltype( r )::output, this, &FSArchiverRunner::fsarchiverProgress );
|
||||
return r.run().explainProcess( toolName, std::chrono::seconds( 0 ) );
|
||||
static const QString name = QStringLiteral( "fsarchiver" );
|
||||
return name;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -64,11 +29,89 @@ FSArchiverRunner::fsarchiverProgress( QString line )
|
||||
// Typical line of output is this:
|
||||
// -[00][ 99%][REGFILEM] /boot/thing
|
||||
// 5 9 ^21
|
||||
if (m_since >= chunk_size && line.length() > 21 && line[5] == '[' && line[9] == '%')
|
||||
if ( m_since >= chunk_size && line.length() > 21 && line[ 5 ] == '[' && line[ 9 ] == '%' )
|
||||
{
|
||||
m_since = 0;
|
||||
double p = double(line.mid(6,3).toInt()) / 100.0;
|
||||
const QString filename = line.mid(22);
|
||||
Q_EMIT progress(p, filename);
|
||||
double p = double( line.mid( 6, 3 ).toInt() ) / 100.0;
|
||||
const QString filename = line.mid( 22 );
|
||||
Q_EMIT progress( p, filename );
|
||||
}
|
||||
}
|
||||
|
||||
Calamares::JobResult
|
||||
FSArchiverRunner::checkPrerequisites( QString& fsarchiverExecutable ) const
|
||||
{
|
||||
if ( !checkToolExists( toolName(), fsarchiverExecutable ) )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
tr( "Missing tools" ),
|
||||
tr( "The <i>%1</i> tool is not installed on the system." ).arg( toolName() ),
|
||||
Calamares::JobResult::MissingRequirements );
|
||||
}
|
||||
|
||||
if ( !checkSourceExists() )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
tr( "Invalid fsarchiver configuration" ),
|
||||
tr( "The source archive <i>%1</i> does not exist." ).arg( m_source ),
|
||||
Calamares::JobResult::InvalidConfiguration );
|
||||
}
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
Calamares::JobResult
|
||||
FSArchiverRunner::checkDestination( QString& destinationPath ) const
|
||||
{
|
||||
destinationPath = CalamaresUtils::System::instance()->targetPath( m_destination );
|
||||
if ( destinationPath.isEmpty() )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
tr( "Invalid fsarchiver configuration" ),
|
||||
tr( "No destination could be found for <i>%1</i>." ).arg( m_destination ),
|
||||
Calamares::JobResult::InvalidConfiguration );
|
||||
}
|
||||
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
Calamares::JobResult
|
||||
FSArchiverDirRunner::run()
|
||||
{
|
||||
QString fsarchiverExecutable;
|
||||
if ( auto res = checkPrerequisites( fsarchiverExecutable ); !res )
|
||||
{
|
||||
return res;
|
||||
}
|
||||
QString destinationPath;
|
||||
if ( auto res = checkDestination( destinationPath ); !res )
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
Calamares::Utils::Runner r(
|
||||
{ fsarchiverExecutable, QStringLiteral( "-v" ), QStringLiteral( "restdir" ), m_source, destinationPath } );
|
||||
r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing();
|
||||
connect( &r, &decltype( r )::output, this, &FSArchiverDirRunner::fsarchiverProgress );
|
||||
return r.run().explainProcess( toolName(), std::chrono::seconds( 0 ) );
|
||||
}
|
||||
|
||||
Calamares::JobResult
|
||||
FSArchiverFSRunner::run()
|
||||
{
|
||||
QString fsarchiverExecutable;
|
||||
if ( auto res = checkPrerequisites( fsarchiverExecutable ); !res )
|
||||
{
|
||||
return res;
|
||||
}
|
||||
QString destinationPath;
|
||||
if ( auto res = checkDestination( destinationPath ); !res )
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
Calamares::Utils::Runner r(
|
||||
{ fsarchiverExecutable, QStringLiteral( "-v" ), QStringLiteral( "restfs" ), m_source, destinationPath } );
|
||||
r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing();
|
||||
connect( &r, &decltype( r )::output, this, &FSArchiverFSRunner::fsarchiverProgress );
|
||||
return r.run().explainProcess( toolName(), std::chrono::seconds( 0 ) );
|
||||
}
|
||||
|
||||
@@ -12,19 +12,48 @@
|
||||
|
||||
#include "Runners.h"
|
||||
|
||||
/** @brief Base class for runners of FSArchiver
|
||||
*
|
||||
*/
|
||||
class FSArchiverRunner : public Runner
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using Runner::Runner;
|
||||
|
||||
Calamares::JobResult run() override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void fsarchiverProgress( QString line );
|
||||
|
||||
private:
|
||||
protected:
|
||||
/** @brief Checks prerequisites, sets full path of fsarchiver in @p executable
|
||||
*/
|
||||
Calamares::JobResult checkPrerequisites( QString& executable ) const;
|
||||
Calamares::JobResult checkDestination( QString& destinationPath ) const;
|
||||
|
||||
int m_since = 0;
|
||||
};
|
||||
|
||||
/** @brief Running FSArchiver in **dir** mode
|
||||
*
|
||||
*/
|
||||
class FSArchiverDirRunner : public FSArchiverRunner
|
||||
{
|
||||
public:
|
||||
using FSArchiverRunner::FSArchiverRunner;
|
||||
|
||||
Calamares::JobResult run() override;
|
||||
};
|
||||
|
||||
/** @brief Running FSArchiver in **dir** mode
|
||||
*
|
||||
*/
|
||||
class FSArchiverFSRunner : public FSArchiverRunner
|
||||
{
|
||||
public:
|
||||
using FSArchiverRunner::FSArchiverRunner;
|
||||
|
||||
Calamares::JobResult run() override;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,7 @@ Runner::Runner( const QString& source, const QString& destination )
|
||||
{
|
||||
}
|
||||
|
||||
Runner::~Runner() {}
|
||||
Runner::~Runner() { }
|
||||
|
||||
bool
|
||||
Runner::checkSourceExists() const
|
||||
|
||||
86
modules/unpackfsc/TarballRunner.cpp
Normal file
86
modules/unpackfsc/TarballRunner.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "TarballRunner.h"
|
||||
|
||||
#include <utils/Logger.h>
|
||||
#include <utils/Runner.h>
|
||||
#include <utils/String.h>
|
||||
|
||||
#include <QString>
|
||||
|
||||
static constexpr const int chunk_size = 107;
|
||||
|
||||
Calamares::JobResult
|
||||
TarballRunner::run()
|
||||
{
|
||||
if ( !checkSourceExists() )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
tr( "Invalid tarball configuration" ),
|
||||
tr( "The source archive <i>%1</i> does not exist." ).arg( m_source ),
|
||||
Calamares::JobResult::InvalidConfiguration );
|
||||
}
|
||||
|
||||
const QString toolName = QStringLiteral( "tar" );
|
||||
QString tarExecutable;
|
||||
if ( !checkToolExists( toolName, tarExecutable ) )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
tr( "Missing tools" ),
|
||||
tr( "The <i>%1</i> tool is not installed on the system." ).arg( toolName ),
|
||||
Calamares::JobResult::MissingRequirements );
|
||||
}
|
||||
|
||||
const QString destinationPath = CalamaresUtils::System::instance()->targetPath( m_destination );
|
||||
if ( destinationPath.isEmpty() )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
tr( "Invalid tarball configuration" ),
|
||||
tr( "No destination could be found for <i>%1</i>." ).arg( m_destination ),
|
||||
Calamares::JobResult::InvalidConfiguration );
|
||||
}
|
||||
|
||||
// Get the stats (number of inodes) from the FS
|
||||
{
|
||||
m_total = 0;
|
||||
Calamares::Utils::Runner r( { tarExecutable, QStringLiteral( "-tf" ), m_source } );
|
||||
r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing();
|
||||
QObject::connect( &r, &decltype( r )::output, [ & ]( QString line ) { m_total++; } );
|
||||
/* ignored */ r.run();
|
||||
}
|
||||
if ( m_total <= 0 )
|
||||
{
|
||||
cWarning() << "No stats could be obtained from" << tarExecutable << "-tf" << m_source;
|
||||
}
|
||||
|
||||
// Now do the actual unpack
|
||||
{
|
||||
m_processed = 0;
|
||||
m_since = 0;
|
||||
Calamares::Utils::Runner r(
|
||||
{ tarExecutable, QStringLiteral( "-xpvf" ), m_source, QStringLiteral( "-C" ), destinationPath } );
|
||||
r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing();
|
||||
connect( &r, &decltype( r )::output, this, &TarballRunner::tarballProgress );
|
||||
return r.run().explainProcess( toolName, std::chrono::seconds( 0 ) );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TarballRunner::tarballProgress( QString line )
|
||||
{
|
||||
m_processed++;
|
||||
m_since++;
|
||||
if ( m_since > chunk_size )
|
||||
{
|
||||
m_since = 0;
|
||||
double p = m_total > 0 ? ( double( m_processed ) / double( m_total ) ) : 0.5;
|
||||
Q_EMIT progress( p, tr( "Tarball extract file %1" ).arg( line ) );
|
||||
}
|
||||
}
|
||||
35
modules/unpackfsc/TarballRunner.h
Normal file
35
modules/unpackfsc/TarballRunner.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2022 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UNPACKFSC_TARBALLRUNNER_H
|
||||
#define UNPACKFSC_TARBALLRUNNER_H
|
||||
|
||||
#include "Runners.h"
|
||||
|
||||
/** @brief Use (GNU) tar for extracting a filesystem
|
||||
*
|
||||
*/
|
||||
class TarballRunner : public Runner
|
||||
{
|
||||
public:
|
||||
using Runner::Runner;
|
||||
|
||||
Calamares::JobResult run() override;
|
||||
|
||||
protected Q_SLOTS:
|
||||
void tarballProgress( QString line );
|
||||
|
||||
private:
|
||||
// Progress reporting
|
||||
int m_total = 0;
|
||||
int m_processed = 0;
|
||||
int m_since = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "UnpackFSCJob.h"
|
||||
|
||||
#include "FSArchiverRunner.h"
|
||||
#include "TarballRunner.h"
|
||||
#include "UnsquashRunner.h"
|
||||
|
||||
#include <utils/Logger.h>
|
||||
@@ -31,10 +32,14 @@ typeNames()
|
||||
{ "fsarchive", T::FSArchive },
|
||||
{ "fsa", T::FSArchive },
|
||||
{ "fsa-dir", T::FSArchive },
|
||||
// TODO: support fsa-block, savefs/restfs format
|
||||
{ "fsa-block", T::FSArchiveFS },
|
||||
{ "fsa-fs", T::FSArchiveFS },
|
||||
{ "squashfs", T::Squashfs },
|
||||
{ "squash", T::Squashfs },
|
||||
{ "unsquash", T::Squashfs },
|
||||
{ "tar", T::Tarball },
|
||||
{ "tarball", T::Tarball },
|
||||
{ "tgz", T::Tarball },
|
||||
};
|
||||
// clang-format on
|
||||
return names;
|
||||
@@ -45,7 +50,7 @@ UnpackFSCJob::UnpackFSCJob( QObject* parent )
|
||||
{
|
||||
}
|
||||
|
||||
UnpackFSCJob::~UnpackFSCJob() {}
|
||||
UnpackFSCJob::~UnpackFSCJob() { }
|
||||
|
||||
QString
|
||||
UnpackFSCJob::prettyName() const
|
||||
@@ -66,21 +71,30 @@ UnpackFSCJob::exec()
|
||||
switch ( m_type )
|
||||
{
|
||||
case Type::FSArchive:
|
||||
r = std::make_unique< FSArchiverRunner >( m_source, m_destination );
|
||||
r = std::make_unique< FSArchiverDirRunner >( m_source, m_destination );
|
||||
break;
|
||||
case Type::FSArchiveFS:
|
||||
r = std::make_unique< FSArchiverFSRunner >( m_source, m_destination );
|
||||
break;
|
||||
case Type::Squashfs:
|
||||
r = std::make_unique< UnsquashRunner >( m_source, m_destination );
|
||||
break;
|
||||
case Type::Tarball:
|
||||
r = std::make_unique< TarballRunner >( m_source, m_destination );
|
||||
break;
|
||||
case Type::None:
|
||||
default:
|
||||
cDebug() << "Nothing to do.";
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
connect( r.get(), &Runner::progress, [=]( qreal percent, const QString& message ) {
|
||||
m_progressMessage = message;
|
||||
Q_EMIT progress( percent );
|
||||
} );
|
||||
connect( r.get(),
|
||||
&Runner::progress,
|
||||
[ = ]( qreal percent, const QString& message )
|
||||
{
|
||||
m_progressMessage = message;
|
||||
Q_EMIT progress( percent );
|
||||
} );
|
||||
return r->run();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ public:
|
||||
{
|
||||
None, /// << Invalid
|
||||
FSArchive,
|
||||
FSArchiveFS,
|
||||
Squashfs,
|
||||
Tarball,
|
||||
};
|
||||
|
||||
explicit UnpackFSCJob( QObject* parent = nullptr );
|
||||
|
||||
@@ -52,12 +52,15 @@ UnsquashRunner::run()
|
||||
m_inodes = -1;
|
||||
Calamares::Utils::Runner r( { unsquashExecutable, QStringLiteral( "-s" ), m_source } );
|
||||
r.setLocation( Calamares::Utils::RunLocation::RunInHost ).enableOutputProcessing();
|
||||
QObject::connect( &r, &decltype( r )::output, [&]( QString line ) {
|
||||
if ( line.startsWith( "Number of inodes " ) )
|
||||
{
|
||||
m_inodes = line.split( ' ', SplitSkipEmptyParts ).last().toInt();
|
||||
}
|
||||
} );
|
||||
QObject::connect( &r,
|
||||
&decltype( r )::output,
|
||||
[ & ]( QString line )
|
||||
{
|
||||
if ( line.startsWith( "Number of inodes " ) )
|
||||
{
|
||||
m_inodes = line.split( ' ', SplitSkipEmptyParts ).last().toInt();
|
||||
}
|
||||
} );
|
||||
/* ignored */ r.run();
|
||||
}
|
||||
if ( m_inodes <= 0 )
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
/** @brief Use Unsquash for extracting a filesystem
|
||||
*
|
||||
* NOTE: not implemented
|
||||
*/
|
||||
class UnsquashRunner : public Runner
|
||||
{
|
||||
|
||||
@@ -21,15 +21,19 @@
|
||||
# - *sourcefs* the type of the source files; valid entries are
|
||||
# - `none` (this entry is ignored; kind of useless)
|
||||
# - `fsarchiver`
|
||||
# Aliases of this are `fsarchive`, `fsa` and `fsa-dir`.
|
||||
# Aliases of this are `fsarchive`, `fsa` and `fsa-dir`. Uses
|
||||
# fsarchiver in "restdir" mode.
|
||||
# - `fsarchiver-block`
|
||||
# Aliases of this are `fsa-block` and `fsa-fs`. Uses fsarchiver
|
||||
# in "restfs" mode.
|
||||
# - `squashfs`
|
||||
# Aliases of this are `squash` and `unsquash`.
|
||||
# - `tar`
|
||||
# - *destination* path relative to rootMountPoint (so in the target
|
||||
# system) where this filesystem is unpacked. It may be an
|
||||
# empty string, which effectively is / (the root) of the target
|
||||
# system.
|
||||
#
|
||||
# TODO: add `fsa-block` and support for *savefs/restfs* mode.
|
||||
source: /data/rootfs.fsa
|
||||
sourcefs: fsarchiver
|
||||
destination: "/"
|
||||
|
||||
Reference in New Issue
Block a user