Compare commits

...

96 Commits

Author SHA1 Message Date
Adriaan de Groot
5ea2e1c2fe [locale] Fix QString-vs-char* confusion 2018-05-17 23:19:00 +02:00
Adriaan de Groot
c9ced8c387 ci: switch to less volatile KDE Neon version 2018-04-26 10:10:05 -04:00
Adriaan de Groot
4f16d65a8b CMake: bump version 2018-04-13 09:59:16 -04:00
Adriaan de Groot
17fd10cdb1 [locale] Un-idiomize back to 3.1 2018-04-13 09:44:17 -04:00
Adriaan de Groot
faf21ce438 [locale] Log GeoIP attempt URL, use possibly-modified form 2018-04-13 09:43:46 -04:00
Adriaan de Groot
be5ad6944e [locale] On GeoIP failure, log URL 2018-04-13 09:43:46 -04:00
Adriaan de Groot
c9928c99c8 Merge remote-tracking branch 'origin/3.1.x-stable' into 3.1.x-stable 2018-04-12 17:13:34 -04:00
Adriaan de Groot
1340613ef5 [locale] Additional test application for GeoIP processing 2018-04-12 16:55:24 -04:00
Adriaan de Groot
76e37402b3 [locale] Extend tests with negative results 2018-04-12 16:23:54 -04:00
Adriaan de Groot
0c1453ff18 [locale] Fix string value handled by XML parser 2018-04-12 16:23:54 -04:00
Adriaan de Groot
eea421f499 [locale] Add tests for GeoIP handlers
- One sample JSON result
 - Two sample XML results
2018-04-12 16:23:54 -04:00
Adriaan de Groot
6b7c8a694a [locale] Make the style of GeoIP retrieval selectable
- Unchanged config files will continue to use the weird addition
   of /json, and interpret JSON data.
 - Allow to specify full URL with data format through one of
     geoipStyle: json
     geoipStyle: xml
 - XML support is optional
2018-04-12 14:37:38 -04:00
Adriaan de Groot
5b98e58ae7 [locale] Refactor GeoIP handlers
- Read the data in the caller of the handler, instead of in the callers
2018-04-12 12:22:43 -04:00
Adriaan de Groot
939cdff93b [locale] Add alternate GeoIP data format 2018-04-12 12:18:43 -04:00
Adriaan de Groot
aaae1507cd [locale] Convenience function for TZ splitting 2018-04-12 11:51:50 -04:00
Adriaan de Groot
3636226425 [locale] Document change to the way GeoIPURL is handled. 2018-04-12 10:18:15 -04:00
Adriaan de Groot
fe98b789f0 [locale] Document the settings in locale.conf
- The geoipUrl is weird, because it is not a complete URL.
   Document that, and what kind of data is expected.

FIXES #920
2018-04-12 10:15:19 -04:00
Adriaan de Groot
d5623af8ef [locale] Refactor geoip handling
- Configuration **must** be a complete URL. The implementation no
   longer appends /json to the URL.
2018-04-12 10:11:48 -04:00
Adriaan de Groot
c0d5a153d4 [locale] Refactor GeoIP handler
- Move GeoIP to its own cpp file
 - Provide a default implementation of the URL mangler
2018-04-12 09:54:22 -04:00
Adriaan de Groot
445f181cc3 [locale] Start refactoring geoip handling
- Introduce a handler interface for GeoIP providers
 - Move the implementation of FreeGeoIP into a struct of its own
2018-04-12 09:45:48 -04:00
Adriaan de Groot
06e43a7312 CI: Switch to stable Neon, to avoid all-builds-failing.
The dev-unstable Neon branch now has a too-new KPMCore for
this branch of Calamares.
2018-04-09 11:20:40 -04:00
Adriaan de Groot
b8e6144553 [locale] Document how the locale entry in Global Storage works.
- Make the BCP47 value explicitly lower-case.
 - Add some constness and encapsulation.
 - Fix up documentation in the packages module explaining the
   format of the ${LOCALE} replacement (now forced to lower-case,
   but it is also only the language part, not e.g. en-UK).

FIXES #922
2018-04-03 13:07:36 -04:00
Adriaan de Groot
4c04260b97 [packages] Don't change the global package list.
- Count only the packages that will be changed, given the current
   locale settings.
 - Preserve global storage unchanged (don't remove any locale-packages).
2018-04-03 08:28:29 -04:00
Adriaan de Groot
36aede52ef [packages] Example configuration installs a localization package 2018-04-03 08:20:01 -04:00
Adriaan de Groot
fd1279dbe3 [welcome] Make the example configuration less strict 2018-04-03 08:19:45 -04:00
Adriaan de Groot
9cdb6734bf [packages] If locale is empty, pretend it is 'en'.
- Otherwise packages like vi-$LOCALE will be retained in the
   package list, which will cause install problems.
2018-04-03 08:02:16 -04:00
Adriaan de Groot
32a1c84935 [locale] Document the settings in locale.conf
- The geoipUrl is weird, because it is not a complete URL.
   Document that, and what kind of data is expected.

FIXES #920
2018-03-29 16:50:02 -04:00
Adriaan de Groot
fb93a8288e [plasmalnf] Simplify showAll handling
- Only need the showAll parameter once, when passing in the list
   of themes to show.
2018-03-29 10:09:45 -04:00
Adriaan de Groot
b0828faadb [plasmalnf] New setting to show all installed LnF themes
- This enables working in three modes:
   - No themes listed; all are shown without screenshots,
   - Themes listed, showAll false; only those are shown,
   - Themes listed, showAll true; the installed-but-not-listed
     themes are shown after the listed ones, and have limited info.
2018-03-29 09:57:19 -04:00
Adriaan de Groot
c2efae765d [plasmalnf] Add auto-detection of Plasma theme.
- Although it's not necessarily accurate for an extensively-modified
   Plasma configuration, we can read the Look-and-Feel from the
   configuration files. Allows auto-detection.
2018-03-29 08:49:22 -04:00
Adriaan de Groot
11652c5856 [plasmalnf] Add pre-selected theme
- For OEM modes where there is already a theme, add a preselect:
   key to pick a specific theme and have that one come up as already-
   selected in the list.
 - Don't re-run the lnftool if an already-selected theme is clicked
   again. Use toggled() instead of clicked().
2018-03-29 07:59:16 -04:00
Adriaan de Groot
94000b6847 [plasmalnf] Improve wording of LnF explanation. 2018-03-29 04:33:55 -04:00
Adriaan de Groot
b3f0932ff9 CMake: bump version number 2018-01-02 15:37:36 +01:00
Adriaan de Groot
41e6f0e06c [calamares] Allow WM close button
- remove hide-close-button hack
 - refactor code in viewmanager for confirming quit
 - hook up confirm-and-quit to WM close button
 - also works for alt-F4 and other quit methods
 - while here, update copyright year

FIXES #870
2018-01-02 14:58:08 +01:00
Adriaan de Groot
5593be125f [calamares] Reduce font-related debug output on startup. 2018-01-02 14:43:48 +01:00
Adriaan de Groot
661789825a [plasmalnf] Make the module optional
- Check for presence of KDE Frameworks for Plasma & Package
 - Explain when module is skipped
2017-12-24 16:15:04 -05:00
Adriaan de Groot
2e1f389997 CMake: explain which modules are skipped
Modules may be skipped for different reasons: SKIP_MODULES
is the traditional approach to suppress some, but other modules
may have unmet build requirements (e.g. Plasma Look-and-Feel,
or the Partitioning module) and should be able to opt-out
of being built. For all those skipped, log it explicitly after
all the modules have been examined.

Only CMake-based (e.g. C++) modules support opting-out in this way.
2017-12-24 16:14:58 -05:00
Adriaan de Groot
c2ee0c6ed4 CMake: bump version number 2017-12-20 04:22:06 -05:00
Adriaan de Groot
d42210eb93 Merge branch '3.1-pinebook' into 3.1.x-stable 2017-12-19 11:13:21 -05:00
Adriaan de Groot
d5b46dfb86 [plasmalnf] Improve theme-listing handling
- if key is missing or badly typed, enable all (explicitly)
 - document settings and code
2017-12-19 12:51:56 +01:00
Adriaan de Groot
f2aeecf546 [plasmalnf] Improve screenshot view
- make screenies smaller
 - use view-preview to indicate no-screenshot-specified
2017-12-19 12:28:42 +01:00
Adriaan de Groot
10e71bab30 [plasmalnf] Add Breeze 'view-preview' icon for missing screenshots 2017-12-19 12:21:05 +01:00
Adriaan de Groot
e73d54767d [plasmalnf] Expand explanation, drop CSS 2017-12-18 07:57:19 -05:00
Adriaan de Groot
cf39dddbf3 [plasmalnf] Prevent duplicate widgets
- Only create widgets for themes once
 - Update visible texts as needed
2017-12-18 07:25:59 -05:00
Adriaan de Groot
3f258d4bd9 [plasmalnf] Fallback for image-not-found
- calculate a hash of the filename, and use that
 - makes it possible to distinguish different screenshots
   even when the image file is missing / badly configured
 - most colors will be dreadful
2017-12-18 07:07:47 -05:00
Adriaan de Groot
2db485bb33 [plasmalnf] Improve layout of theme widget 2017-12-14 17:04:16 -05:00
Adriaan de Groot
244919d6fe [plasmalnf] Add description to theme widget 2017-12-14 17:01:59 -05:00
Adriaan de Groot
8b3f71af40 [plasmalnf] Widget for showing theme info
- Radio button + group for button action
 - Use a (still very primitive) widget for displaying theme information
2017-12-13 11:04:34 -05:00
Adriaan de Groot
755c0cba18 [plasmalnf] Prep-work for UI changes 2017-12-13 09:55:54 -05:00
Adriaan de Groot
11fc3e0507 [plasmalnf] minor documentation
- Code documentation
 - Add another broken example theme, as test for winnowing
2017-12-13 09:53:41 -05:00
Adriaan de Groot
afbdcc3782 [hwclock] Be more lenient.
Patch by Gabriel C. (@abucodonosor).

 - use libcalamares functions
 - no need to copy /etc/adjtime over we can run hwclock in chroot
   since we have /proc , /sys , /dev , /run/* already bind mounted.
 - added RTC and ISA probing methode ( see issue #873)
    - we probe default from /dev/rtc* ,
    - fall back to ISA
    - still doesn't work we just print a BIOS/Kernel BUG message and continue
- NOTE: issue #873 is about broken ArchLinux kernel config but there
  are HP boxes with real RTC problems no matter what kernel config
  is used so let us be nice and don't error out..

FIXES #873
2017-12-13 06:27:04 -05:00
Adriaan de Groot
748ccf94e9 [plasmalnf] Enrich config file
- Extend the config file format to allow theme, image pairs
   as well as just naming the themes.
 - Reduce verbosity when querying Plasma themes.
2017-12-12 06:59:25 -05:00
Adriaan de Groot
0116465303 CMake: bump version 2017-12-07 08:42:49 -05:00
Adriaan de Groot
6bd8c67ca9 [plasmalnf] Allow filtering the selectable lnf themes
- empty list allows all of them
 - always suppress hidden, invalid themes, and those named
2017-12-04 12:27:30 -05:00
Adriaan de Groot
ad69eda337 [plasmalnf] Complain again if poorly configured 2017-12-04 11:54:33 -05:00
Adriaan de Groot
98b9f67e39 [plasmalnf] Complain more loudly (and more often) when badly configured 2017-12-04 11:51:16 -05:00
Adriaan de Groot
02dfe51d55 [welcome] Improve error reporting from requirements checker 2017-12-04 10:47:26 -05:00
Adriaan de Groot
e628ddfdbf [plasmalnf] Try to get back to the live user before changing themes 2017-12-04 09:37:34 -05:00
Adriaan de Groot
b10b19e9ee [plasmalnf] C++ style and reduce includes 2017-12-04 09:11:10 -05:00
Adriaan de Groot
eb92755b0a [plasmalnf] Enable translations
- Move tool-running to the view-step
 - Enable translations by showing name instead of theme-id
 - More verbose logging
2017-12-04 06:40:13 -05:00
Adriaan de Groot
71966b5330 [plasmalnf] Wait longer for the tool to finish 2017-12-03 16:09:34 -05:00
Adriaan de Groot
1de2e94fd0 [plasmalnf] Simplify code, reduce copies of lnftool setting 2017-12-03 15:41:52 -05:00
Adriaan de Groot
fe8ff3ab05 [plasmalnf] Simplify code, remove redundant implementations 2017-12-03 15:34:06 -05:00
Adriaan de Groot
4e2e55a935 [plasmalnf] Needs to run as target user in all cases 2017-12-03 15:24:39 -05:00
Adriaan de Groot
ac92d4911d Compatibility: revert conveniences from master 2017-12-03 12:58:54 -05:00
Adriaan de Groot
3a94f02547 CMake: look for ECM at top-level, add to search path if found. 2017-12-03 12:48:23 -05:00
Adriaan de Groot
cddc4699aa [plasmalnf] Import Plasma Look-and-Feel module independently 2017-12-03 12:47:41 -05:00
Adriaan de Groot
1f49f764a6 [libcalamares] Allow retrieving chroot mode from system (as well as settings) 2017-12-03 12:46:33 -05:00
Adriaan de Groot
65a236cd60 [packages] Fix previous.
This, kids, is why you don't switch writing C++ and Python too often.
The C++ code isn't a syntax error in Python, although this would fail
at runtime.
2017-12-02 06:14:17 -05:00
Adriaan de Groot
3e3cd08ff3 [packages] Fix previous (false vs False) 2017-12-02 05:20:13 -05:00
Adriaan de Groot
150007c138 [packages] Feature: skip if no internet.
Update documentation, add a new key *skip_if_no_internet* to support
systems that **recommend** having an internet connection (but don't
require it), and which also use the packages module. This prevents
a long delay while the package manager tries to access the internet
and times out (repeatedly).

Existing configurations are unchanged.
2017-12-02 05:17:15 -05:00
Adriaan de Groot
7b145c2a36 [packages] Improve message when no packages are processed at all. 2017-12-01 16:48:02 -05:00
Adriaan de Groot
517dbfab06 [libcalamares] The script namespace is actually a dict
Use dict methods, in particular d.get(k, v), to retrieve
the pretty_name() function (or None if it isn't there).
Using getattr() on a dict will not return values in the
dict.
2017-12-01 16:42:56 -05:00
Adriaan de Groot
fe61925f31 [packages] Update module documentation 2017-12-01 13:46:59 -05:00
Adriaan de Groot
63af8c1b92 Drop -rc status 2017-11-29 08:50:22 -05:00
Adriaan de Groot
12369abaa4 [libcalamares] Refactor to reduce compiler warnings 2017-11-29 08:49:44 -05:00
Adriaan de Groot
93ab6432c4 [netinstall] Special-case the root node.
Root is always selected, can't be unselected, and has its own explicit
constructor and name. This resolves issue reported where unchecking
all *visible* groups caused the root to be unchecked, after which
hidden-but-still-selected subgroups were not installed.

Reported by crazy@
2017-11-24 07:52:52 -05:00
bill-auger
452cefd482 use orphaned Branding::ProductLogo as sidebar image 2017-11-21 07:25:39 -05:00
Adriaan de Groot
aa0fa37492 [netinstall] Hidden groups follow selectedness of parents.
If a subgroup is hidden, then it should be considered
selected if its parent is selected or partially-selected.
If the parent group is totally unselected, then the hidden
subgroup shouldn't be installed either. This allows putting
required-packages into a group, without cluttering the
interface.

FIXES #864
2017-11-21 06:16:30 -05:00
Adriaan de Groot
71e80f680e [netinstall] Only update selectedness of parents with children.
While walking up the tree, only switch the selectedness states
of parents with children. This avoids the case where a parent
has a first subgroup that is hidden -- in which case the
parent ends up with no children, and is unselected even though
it is marked as selected in the config file.

FIXES #864
2017-11-21 05:36:38 -05:00
Adriaan de Groot
7e2e2cabfe CMake: bump version to 3.1.9rc1 (no functional changes yet) 2017-11-21 04:25:32 -05:00
Adriaan de Groot
848d532a58 CMake: drop -rc status 2017-11-14 10:18:58 -05:00
Adriaan de Groot
51c74c6abb [netinstall] Convenience typedefs 2017-11-06 05:42:13 -05:00
Adriaan de Groot
91e949f8fc [netinstall] Apply Calamares C++ style 2017-11-06 05:34:57 -05:00
Adriaan de Groot
f424af36d3 [netinstall] Avoid crash when do groups are available
- m_groups is only set to a non-nullptr value when data is received
   and fully processed,
 - avoid nullptr dereference when paging *back* from a netinstall
   page that hasn't loaded groups data.

FIXES #859
2017-11-06 05:33:01 -05:00
Adriaan de Groot
ee0b3b85dc [netinstall] Improve 'next' button handling
- Document netinstall.conf a little,
 - Add setting *required* which influences whether next is enabled or not
   in case of missing or corrupt data,
 - Enable *next* button only once some (any!) data is received.

This can be used to disallow stepping past the netinstall step when
there is no data (e.g. internet has failed between the welcome page
and the netinstall page).
2017-11-06 05:33:01 -05:00
Adriaan de Groot
35f5612ec1 [locale] Fix GeoIP (reported by demm, crazy)
- data has already been read, don't try to read more from the QNM reply
 - regression introduced in 7e25909e
2017-11-01 11:07:18 +01:00
Adriaan de Groot
4ea8b2e6ef CMake: report on the example-distro feature correctly 2017-10-30 11:43:37 -04:00
Adriaan de Groot
5474dc6d2b [partition] allow KPMcore 3.0.2 (with warning) 2017-10-30 11:43:37 -04:00
Adriaan de Groot
a179c6c765 Merge pull request #846 from stikonas/3.1.x-stable
Use KPMcore Resize Operation.
2017-10-30 11:22:53 -04:00
Adriaan de Groot
12f4104fe1 Merge pull request #850 from abucodonosor/3.1.x-stable
NetInstallPage.cpp: fix displaying for Name and Description
2017-10-30 11:18:52 -04:00
Gabriel Craciunescu
d2ea83a0b2 NetInstallPage.cpp: fix displaying for Name and Description
- fixes 1d7ad9e045 which sets
  both header's labels to 0 so 'Name' was always overridden
  by Description and Description never displayed
2017-10-28 02:18:36 +02:00
Andrius Štikonas
fb1522f6ca Use KPMcore Resize Operation. 2017-10-27 14:00:32 +01:00
Adriaan de Groot
951e5ad7f4 Merge pull request #845 from stikonas/3.1.x-stable
Fix reported partition size.
2017-10-27 04:43:11 -04:00
Andrius Štikonas
274025d04e Fix reported partition size. 2017-10-27 02:51:44 +01:00
Adriaan de Groot
3b30bbde67 Bump version number, pretending 3.1.8-rc1 is pending 2017-10-25 08:55:59 -04:00
68 changed files with 2192 additions and 872 deletions

View File

@@ -114,6 +114,16 @@ find_package( Qt5 ${QT_VERSION} CONFIG REQUIRED Core Gui Widgets LinguistTools S
find_package( YAMLCPP 0.5.1 REQUIRED )
find_package( PolkitQt5-1 REQUIRED )
# Find ECM once, and add it to the module search path; Calamares
# modules that need ECM can do
# find_package(ECM ${ECM_VERSION} REQUIRED NO_MODULE),
# no need to mess with the module path after.
set( ECM_VERSION 5.10.0 )
find_package(ECM ${ECM_VERSION} NO_MODULE)
if( ECM_FOUND )
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH})
endif()
option( INSTALL_CONFIG "Install configuration files" ON )
option( WITH_PYTHON "Enable Python modules API (requires Boost.Python)." ON )
option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." OFF )
@@ -166,7 +176,7 @@ set( CALAMARES_TRANSLATION_LANGUAGES ar ast bg ca cs_CZ da de el en en_GB es_MX
### Bump version here
set( CALAMARES_VERSION_MAJOR 3 )
set( CALAMARES_VERSION_MINOR 1 )
set( CALAMARES_VERSION_PATCH 7 )
set( CALAMARES_VERSION_PATCH 13 )
set( CALAMARES_VERSION_RC 0 )
set( CALAMARES_VERSION ${CALAMARES_VERSION_MAJOR}.${CALAMARES_VERSION_MINOR}.${CALAMARES_VERSION_PATCH} )
@@ -267,12 +277,9 @@ else()
endif()
# Doesn't list mksquashfs as an optional dep, though, because it
# hasn't been sent through the find_package() scheme.
set_package_properties( mksquashfs PROPERTIES
DESCRIPTION "Create squashed filesystems"
URL "http://tldp.org/HOWTO/SquashFS-HOWTO/creatingandusing.html"
PURPOSE "Create example distro"
TYPE OPTIONAL
)
#
# "http://tldp.org/HOWTO/SquashFS-HOWTO/creatingandusing.html"
add_feature_info( ExampleDistro ${mksquashfs_FOUND} "Create example-distro target.")
# add_subdirectory( thirdparty )
add_subdirectory( src )

View File

@@ -3,15 +3,27 @@ include( CalamaresAddTranslations )
set( MODULE_DATA_DESTINATION share/calamares/modules )
# Convenience function to indicate that a module has been skipped
# (optionally also why). Call this in the module's CMakeLists.txt
macro( calamares_skip_module )
set( SKIPPED_MODULES ${SKIPPED_MODULES} ${ARGV} PARENT_SCOPE )
endmacro()
function( calamares_add_module_subdirectory )
set( SUBDIRECTORY ${ARGV0} )
set( SKIPPED_MODULES )
set( MODULE_CONFIG_FILES "" )
# If this subdirectory has a CMakeLists.txt, we add_subdirectory it...
if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/CMakeLists.txt" )
add_subdirectory( ${SUBDIRECTORY} )
file( GLOB MODULE_CONFIG_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY} "${SUBDIRECTORY}/*.conf" )
# Module has indicated it should be skipped, show that in
# the calling CMakeLists (which is src/modules/CMakeLists.txt normally).
if ( SKIPPED_MODULES )
set( SKIPPED_MODULES ${SKIPPED_MODULES} PARENT_SCOPE )
endif()
# ...otherwise, we look for a module.desc.
elseif( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/module.desc" )
set( MODULES_DIR ${CMAKE_INSTALL_LIBDIR}/calamares/modules )

View File

@@ -1,2 +1,2 @@
FROM kdeneon/all
FROM kdeneon/all:user
RUN sudo apt-get update && 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

View File

@@ -55,14 +55,7 @@ CalamaresApplication::CalamaresApplication( int& argc, char* argv[] )
QFont f = font();
cDebug() << "Default font ====="
<< "\nPixel size: " << f.pixelSize()
<< "\nPoint size: " << f.pointSize()
<< "\nPoint sizeF: " << f.pointSizeF()
<< "\nFont family: " << f.family()
<< "\nMetric height:" << QFontMetrics( f ).height();
// The following line blocks for 15s on Qt 5.1.0
cDebug() << "Font height:" << QFontMetrics( f ).height();
cDebug() << "Default font size" << f.pointSize() << ';' << f.pixelSize() << "px";
CalamaresUtils::setDefaultFontSize( f.pointSize() );
cDebug() << "Available languages:" << QString( CALAMARES_TRANSLATION_LANGUAGES ).split( ';' );

View File

@@ -1,7 +1,7 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017-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
@@ -30,6 +30,7 @@
#include <QApplication>
#include <QBoxLayout>
#include <QCloseEvent>
#include <QDesktopWidget>
#include <QLabel>
#include <QTreeView>
@@ -37,10 +38,8 @@
CalamaresWindow::CalamaresWindow( QWidget* parent )
: QWidget( parent )
, m_debugWindow( nullptr )
, m_viewManager( nullptr )
{
// Hide close button
setWindowFlags( Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint );
CALAMARES_RETRANSLATE(
setWindowTitle( tr( "%1 Installer" )
.arg( *Calamares::Branding::ProductName ) );
@@ -96,7 +95,7 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
logoLabel->setAlignment( Qt::AlignCenter );
logoLabel->setFixedSize( 80, 80 );
logoLabel->setPixmap( Calamares::Branding::instance()->
image( Calamares::Branding::ProductIcon,
image( Calamares::Branding::ProductLogo,
logoLabel->size() ) );
logoLayout->addWidget( logoLabel );
logoLayout->addStretch();
@@ -139,10 +138,10 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
CalamaresUtils::unmarginLayout( sideLayout );
CalamaresUtils::unmarginLayout( mainLayout );
Calamares::ViewManager* vm = Calamares::ViewManager::instance( this );
connect( vm, &Calamares::ViewManager::enlarge, this, &CalamaresWindow::enlarge );
m_viewManager = Calamares::ViewManager::instance( this );
connect( m_viewManager, &Calamares::ViewManager::enlarge, this, &CalamaresWindow::enlarge );
mainLayout->addWidget( vm->centralWidget() );
mainLayout->addWidget( m_viewManager->centralWidget() );
}
void
@@ -156,3 +155,15 @@ CalamaresWindow::enlarge( QSize enlarge )
resize( w, h );
}
void
CalamaresWindow::closeEvent( QCloseEvent* event )
{
if ( ( !m_viewManager ) || m_viewManager->confirmCancelInstallation() )
{
event->accept();
qApp->quit();
}
else
event->ignore();
}

View File

@@ -1,7 +1,7 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017-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
@@ -26,6 +26,7 @@
namespace Calamares
{
class DebugWindow;
class ViewManager;
}
/**
@@ -46,8 +47,12 @@ public slots:
*/
void enlarge( QSize enlarge );
protected:
virtual void closeEvent( QCloseEvent* e ) override;
private:
QPointer< Calamares::DebugWindow > m_debugWindow;
QPointer< Calamares::DebugWindow > m_debugWindow; // Managed by self
Calamares::ViewManager* m_viewManager;
};
#endif //CALAMARESWINDOW_H

View File

@@ -183,6 +183,16 @@ variantHashFromPyDict( const boost::python::dict& pyDict )
Helper* Helper::s_instance = nullptr;
static inline void add_if_lib_exists( const QDir& dir, const char* name, QStringList& list )
{
if ( ! ( dir.exists() && dir.isReadable() ) )
return;
QFileInfo fi( dir.absoluteFilePath( name ) );
if ( fi.exists() && fi.isReadable() )
list.append( fi.dir().absolutePath() );
}
Helper::Helper( QObject* parent )
: QObject( parent )
{
@@ -196,20 +206,11 @@ Helper::Helper( QObject* parent )
m_mainNamespace = m_mainModule.attr( "__dict__" );
// If we're running from the build dir
QFileInfo fi( QDir::current().absoluteFilePath( "libcalamares.so" ) );
if ( fi.exists() && fi.isReadable() )
m_pythonPaths.append( fi.dir().absolutePath() );
add_if_lib_exists( QDir::current(), "libcalamares.so", m_pythonPaths );
QDir calaPythonPath( CalamaresUtils::systemLibDir().absolutePath() +
QDir::separator() + "calamares" );
if ( calaPythonPath.exists() &&
calaPythonPath.isReadable() )
{
QFileInfo fi( calaPythonPath.absoluteFilePath( "libcalamares.so" ) );
if ( fi.exists() && fi.isReadable() )
m_pythonPaths.append( fi.dir().absolutePath() );
}
add_if_lib_exists( calaPythonPath, "libcalamares.so", m_pythonPaths );
bp::object sys = bp::import( "sys" );
@@ -232,7 +233,7 @@ Helper::~Helper()
{}
boost::python::object
boost::python::dict
Helper::createCleanNamespace()
{
// To make sure we run each script with a clean namespace, we only fetch the

View File

@@ -51,7 +51,7 @@ public:
explicit Helper( QObject* parent = nullptr );
virtual ~Helper();
boost::python::object createCleanNamespace();
boost::python::dict createCleanNamespace();
QString handleLastError();

View File

@@ -216,10 +216,10 @@ BOOST_PYTHON_MODULE( libcalamares )
"in the original string."
);
bp::def(
"gettext_languages",
&CalamaresPython::gettext_languages,
bp::def(
"gettext_languages",
&CalamaresPython::gettext_languages,
"Returns list of languages (most to least-specific) for gettext."
);
@@ -296,7 +296,7 @@ PythonJob::exec()
try
{
bp::object scriptNamespace = helper()->createCleanNamespace();
bp::dict scriptNamespace = helper()->createCleanNamespace();
bp::object calamaresModule = bp::import( "libcalamares" );
bp::dict calamaresNamespace = bp::extract< bp::dict >( calamaresModule.attr( "__dict__" ) );
@@ -310,7 +310,7 @@ PythonJob::exec()
scriptNamespace );
bp::object entryPoint = scriptNamespace[ "run" ];
bp::object prettyNameFunc = bp::getattr(scriptNamespace, "pretty_name", bp::object());
bp::object prettyNameFunc = scriptNamespace.get("pretty_name", bp::object());
cDebug() << "Job file" << scriptFI.absoluteFilePath();
if ( !prettyNameFunc.is_none() )

View File

@@ -256,5 +256,10 @@ System::getTotalMemoryB()
#endif
}
bool
System::doChroot() const
{
return m_doChroot;
}
} // namespace

View File

@@ -114,6 +114,8 @@ public:
*/
DLLEXPORT QPair<quint64, float> getTotalMemoryB();
DLLEXPORT bool doChroot() const;
private:
static System* s_instance;

View File

@@ -1,7 +1,7 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017-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
@@ -88,30 +88,8 @@ ViewManager::ViewManager( QObject* parent )
connect( m_back, &QPushButton::clicked, this, &ViewManager::back );
m_back->setEnabled( false );
connect( m_quit, &QPushButton::clicked,
this, [this]()
{
// If it's NOT the last page of the last step, we ask for confirmation
if ( !( m_currentStep == m_steps.count() -1 &&
m_steps.last()->isAtEnd() ) )
{
QMessageBox mb( QMessageBox::Question,
tr( "Cancel installation?" ),
tr( "Do you really want to cancel the current install process?\n"
"The installer will quit and all changes will be lost." ),
QMessageBox::Yes | QMessageBox::No,
m_widget );
mb.setDefaultButton( QMessageBox::No );
mb.button( QMessageBox::Yes )->setText( tr( "&Yes" ) );
mb.button( QMessageBox::No )->setText( tr( "&No" ) );
int response = mb.exec();
if ( response == QMessageBox::Yes )
qApp->quit();
}
else // Means we're at the end, no need to confirm.
qApp->quit();
} );
connect( m_quit, &QPushButton::clicked, this,
[this]() { if ( this->confirmCancelInstallation() ) qApp->quit(); } );
connect( JobQueue::instance(), &JobQueue::failed,
this, &ViewManager::onInstallationFailed );
connect( JobQueue::instance(), &JobQueue::finished,
@@ -302,4 +280,26 @@ ViewManager::back()
}
}
bool ViewManager::confirmCancelInstallation()
{
// If it's NOT the last page of the last step, we ask for confirmation
if ( !( m_currentStep == m_steps.count() -1 &&
m_steps.last()->isAtEnd() ) )
{
QMessageBox mb( QMessageBox::Question,
tr( "Cancel installation?" ),
tr( "Do you really want to cancel the current install process?\n"
"The installer will quit and all changes will be lost." ),
QMessageBox::Yes | QMessageBox::No,
m_widget );
mb.setDefaultButton( QMessageBox::No );
mb.button( QMessageBox::Yes )->setText( tr( "&Yes" ) );
mb.button( QMessageBox::No )->setText( tr( "&No" ) );
int response = mb.exec();
return response == QMessageBox::Yes;
}
else // Means we're at the end, no need to confirm.
return true;
}
} // namespace

View File

@@ -1,7 +1,7 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017-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
@@ -86,6 +86,13 @@ public:
*/
int currentStepIndex() const;
/**
* @ brief Called when "Cancel" is clicked; asks for confirmation.
* Other means of closing Calamares also call this method, e.g. alt-F4.
* At the end of installation, no confirmation is asked. Returns true
* if the user confirms closing the window.
*/
bool confirmCancelInstallation();
public slots:
/**

View File

@@ -1,5 +1,11 @@
include( CMakeColors )
# The variable SKIP_MODULES can be set to skip particular modules;
# individual modules can also decide they must be skipped (e.g. OS-specific
# modules, or ones with unmet dependencies). Collect the skipped modules
# in this list.
set( LIST_SKIPPED_MODULES "" )
if( BUILD_TESTING )
add_executable( test_conf test_conf.cpp )
target_link_libraries( test_conf ${YAMLCPP_LIBRARY} )
@@ -13,11 +19,24 @@ foreach( SUBDIRECTORY ${SUBDIRECTORIES} )
if( NOT DO_SKIP EQUAL -1 )
message( "${ColorReset}-- Skipping module ${BoldRed}${SUBDIRECTORY}${ColorReset}." )
message( "" )
list( APPEND LIST_SKIPPED_MODULES "${SUBDIRECTORY} (user request)" )
elseif( ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}" ) AND
( DO_SKIP EQUAL -1 ) )
set( SKIPPED_MODULES )
calamares_add_module_subdirectory( ${SUBDIRECTORY} )
if ( SKIPPED_MODULES )
list( APPEND LIST_SKIPPED_MODULES "${SKIPPED_MODULES}" )
endif()
endif()
endforeach()
if ( LIST_SKIPPED_MODULES )
message( "${ColorReset}-- Skipped modules:" )
foreach( SUBDIRECTORY ${LIST_SKIPPED_MODULES} )
message( "${ColorReset}-- Skipped ${BoldRed}${SUBDIRECTORY}${ColorReset}." )
endforeach()
message( "" )
endif()
include( CalamaresAddTranslations )
add_calamares_python_translations( ${CALAMARES_TRANSLATION_LANGUAGES} )

View File

@@ -5,7 +5,8 @@
#
# Copyright 2014 - 2015, Philip Müller <philm@manjaro.org>
# Copyright 2014, Teo Mrnjavac <teo@kde.org>
# Copyright 2017. Alf Gaida <agaida@siduction.org>
# Copyright 2017, Alf Gaida <agaida@siduction.org>
# Copyright 2017, Gabriel Craciunescu <crazy@frugalware.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
@@ -20,26 +21,33 @@
# You should have received a copy of the GNU General Public License
# along with Calamares. If not, see <http://www.gnu.org/licenses/>.
import subprocess
import shutil
import libcalamares
def run():
"""
Set hardware clock.
"""
hwclock_rtc = ["hwclock", "--systohc", "--utc"]
hwclock_isa = ["hwclock", "--systohc", "--utc", "--directisa"]
is_broken_rtc = False
is_broken_isa = False
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
try:
subprocess.check_call(["hwclock", "--systohc", "--utc"])
except subprocess.CalledProcessError as e:
return (
"Cannot set hardware clock.",
"hwclock terminated with exit code {}.".format(e.returncode)
)
shutil.copy2("/etc/adjtime", "{!s}/etc/".format(root_mount_point))
ret = libcalamares.utils.target_env_call(hwclock_rtc)
if ret != 0:
is_broken_rtc = True
libcalamares.utils.debug("Hwclock returned error code {}".format(ret))
libcalamares.utils.debug(" .. RTC method failed, trying ISA bus method.")
else:
libcalamares.utils.debug("Hwclock set using RTC method.")
if is_broken_rtc:
ret = libcalamares.utils.target_env_call(hwclock_isa)
if ret != 0:
is_broken_isa = True
libcalamares.utils.debug("Hwclock returned error code {}".format(ret))
libcalamares.utils.debug(" .. ISA bus method failed.")
else:
libcalamares.utils.debug("Hwclock set using ISA bus methode.")
if is_broken_rtc and is_broken_isa:
libcalamares.utils.debug("BIOS or Kernel BUG: Setting hwclock failed.")
return None

View File

@@ -1,5 +1,4 @@
find_package(ECM 5.10.0 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH})
find_package(ECM ${ECM_VERSION} REQUIRED NO_MODULE)
include(KDEInstallDirs)
include(GenerateExportHeader)

View File

@@ -1,9 +1,26 @@
find_package(ECM ${ECM_VERSION} NO_MODULE)
if( ECM_FOUND AND BUILD_TESTING )
include( ECMAddTests )
find_package( Qt5 COMPONENTS Core Test REQUIRED )
endif()
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
set( geoip_src GeoIP.cpp GeoIPFreeGeoIP.cpp )
set( geoip_libs )
find_package(Qt5 COMPONENTS Xml)
if( Qt5Xml_FOUND )
list( APPEND geoip_src GeoIPXML.cpp )
list( APPEND geoip_libs Qt5::Xml )
add_definitions( -DHAVE_XML )
endif()
calamares_add_plugin( locale
TYPE viewmodule
EXPORT_MACRO PLUGINDLLEXPORT_PRO
SOURCES
${geoip_src}
LCLocaleDialog.cpp
LocaleConfiguration.cpp
LocalePage.cpp
@@ -17,6 +34,28 @@ calamares_add_plugin( locale
LINK_PRIVATE_LIBRARIES
calamaresui
Qt5::Network
${geoip_libs}
${YAMLCPP_LIBRARY}
SHARED_LIB
)
if( ECM_FOUND AND BUILD_TESTING )
ecm_add_test(
GeoIPTests.cpp
${geoip_src}
TEST_NAME
geoiptest
LINK_LIBRARIES
calamaresui
Qt5::Network
Qt5::Test
${geoip_libs}
${YAMLCPP_LIBRARY}
)
set_target_properties( geoiptest PROPERTIES AUTOMOC TRUE )
endif()
if( BUILD_TESTING )
add_executable( test_geoip test_geoip.cpp ${geoip_src} )
target_link_libraries( test_geoip calamaresui Qt5::Network ${geoip_libs} ${YAMLCPP_LIBRARY} )
endif()

View File

@@ -0,0 +1,40 @@
/* === This file is part of Calamares - <http://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 "GeoIP.h"
#include "utils/Logger.h"
GeoIP::~GeoIP()
{
}
GeoIP::RegionZonePair
GeoIP::splitTZString( const QString& timezoneString )
{
QStringList tzParts = timezoneString.split( '/', QString::SkipEmptyParts );
if ( tzParts.size() >= 2 )
{
cDebug() << "GeoIP reporting" << timezoneString;
QString region = tzParts.takeFirst();
QString zone = tzParts.join( '/' );
return qMakePair( region, zone );
}
return qMakePair( QString(), QString() );
}

View File

@@ -0,0 +1,56 @@
/* === This file is part of Calamares - <http://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 GEOIP_H
#define GEOIP_H
#include <QPair>
#include <QString>
#include <QUrl>
class QByteArray;
/**
* @brief Interface for GeoIP retrievers.
*
* A GeoIP retriever takes a configured URL (from the config file)
* and can handle the data returned from its interpretation of that
* configured URL, returning a region and zone.
*/
struct GeoIP
{
using RegionZonePair = QPair<QString, QString>;
virtual ~GeoIP();
/** @brief Handle a (successful) request by interpreting the data.
*
* Should return a ( <zone>, <region> ) pair, e.g.
* ( "Europe", "Amsterdam" ). This is called **only** if the
* request to the fullUrl was successful; the handler
* is free to read as much, or as little, data as it
* likes. On error, returns a RegionZonePair with empty
* strings (e.g. ( "", "" ) ).
*/
virtual RegionZonePair processReply( const QByteArray& ) = 0;
/** @brief Splits a region/zone string into a pair. */
static RegionZonePair splitTZString( const QString& s );
} ;
#endif

View File

@@ -0,0 +1,55 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014-2016, Teo Mrnjavac <teo@kde.org>
* 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 "GeoIPFreeGeoIP.h"
#include "utils/Logger.h"
#include "utils/YamlUtils.h"
#include <QByteArray>
#include <yaml-cpp/yaml.h>
GeoIP::RegionZonePair
FreeGeoIP::processReply( const QByteArray& data )
{
try
{
YAML::Node doc = YAML::Load( data );
QVariant var = CalamaresUtils::yamlToVariant( doc );
if ( !var.isNull() &&
var.isValid() &&
var.type() == QVariant::Map )
{
QVariantMap map = var.toMap();
if ( map.contains( "time_zone" ) &&
!map.value( "time_zone" ).toString().isEmpty() )
{
return splitTZString( map.value( "time_zone" ).toString() );
}
}
}
catch ( YAML::Exception& e )
{
CalamaresUtils::explainYamlException( e, data, "GeoIP data");
}
return qMakePair( QString(), QString() );
}

View File

@@ -0,0 +1,37 @@
/* === This file is part of Calamares - <http://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 GEOIPFREEGEOIP_H
#define GEOIPFREEGEOIP_H
#include "GeoIP.h"
/** @brief GeoIP lookup via freegeoip.com
*
* This is the original implementation of GeoIP lookup,
* using the FreeGeoIP service, or similar which returns
* data in the same format.
*
* The data is assumed to be in JSON format with a time_zone attribute.
*/
struct FreeGeoIP : public GeoIP
{
virtual RegionZonePair processReply( const QByteArray& );
} ;
#endif

View File

@@ -0,0 +1,140 @@
/* === This file is part of Calamares - <http://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 "GeoIPTests.h"
#include "GeoIPFreeGeoIP.h"
#ifdef HAVE_XML
#include "GeoIPXML.h"
#endif
#include <QtTest/QtTest>
QTEST_GUILESS_MAIN( GeoIPTests )
GeoIPTests::GeoIPTests()
{
}
GeoIPTests::~GeoIPTests()
{
}
void
GeoIPTests::initTestCase()
{
}
void
GeoIPTests::testJSON()
{
static const char data[] =
"{\"time_zone\":\"Europe/Amsterdam\"}";
FreeGeoIP handler;
auto tz = handler.processReply( data );
QCOMPARE( tz.first, QLatin1String( "Europe" ) );
QCOMPARE( tz.second, QLatin1String( "Amsterdam" ) );
// JSON is quite tolerant
tz = handler.processReply( "time_zone: \"Europe/Brussels\"" );
QCOMPARE( tz.second, QLatin1String( "Brussels" ) );
tz = handler.processReply( "time_zone: America/New_York\n" );
QCOMPARE( tz.first, QLatin1String( "America" ) );
}
void
GeoIPTests::testJSONbad()
{
static const char data[] = "time_zone: 1";
FreeGeoIP handler;
auto tz = handler.processReply( data );
tz = handler.processReply( data );
QCOMPARE( tz.first, QString() );
tz = handler.processReply( "" );
QCOMPARE( tz.first, QString() );
tz = handler.processReply( "<html><body>404 Forbidden</body></html>" );
QCOMPARE( tz.first, QString() );
}
void
GeoIPTests::testXML()
{
static const char data[] =
R"(<Response>
<Ip>85.150.1.1</Ip>
<Status>OK</Status>
<CountryCode>NL</CountryCode>
<CountryCode3>NLD</CountryCode3>
<CountryName>Netherlands</CountryName>
<RegionCode>None</RegionCode>
<RegionName>None</RegionName>
<City>None</City>
<ZipPostalCode/>
<Latitude>50.0</Latitude>
<Longitude>4.0</Longitude>
<AreaCode>0</AreaCode>
<TimeZone>Europe/Amsterdam</TimeZone>
</Response>)";
#ifdef HAVE_XML
XMLGeoIP handler;
auto tz = handler.processReply( data );
QCOMPARE( tz.first, QLatin1String( "Europe" ) );
QCOMPARE( tz.second, QLatin1String( "Amsterdam" ) );
#endif
}
void
GeoIPTests::testXML2()
{
static const char data[] =
"<Response><TimeZone>America/North Dakota/Beulah</TimeZone></Response>";
#ifdef HAVE_XML
XMLGeoIP handler;
auto tz = handler.processReply( data );
QCOMPARE( tz.first, QLatin1String( "America" ) );
QCOMPARE( tz.second, QLatin1String( "North Dakota/Beulah" ) );
#endif
}
void
GeoIPTests::testXMLbad()
{
#ifdef HAVE_XML
XMLGeoIP handler;
auto tz = handler.processReply( "{time_zone: \"Europe/Paris\"}" );
QCOMPARE( tz.first, QString() );
tz = handler.processReply( "<Response></Response>" );
QCOMPARE( tz.first, QString() );
tz = handler.processReply( "fnord<html/>" );
QCOMPARE( tz.first, QString() );
#endif
}

View File

@@ -0,0 +1,40 @@
/* === This file is part of Calamares - <http://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 GEOIPTESTS_H
#define GEOIPTESTS_H
#include <QObject>
class GeoIPTests : public QObject
{
Q_OBJECT
public:
GeoIPTests();
~GeoIPTests() override;
private Q_SLOTS:
void initTestCase();
void testJSON();
void testJSONbad();
void testXML();
void testXML2();
void testXMLbad();
};
#endif

View File

@@ -0,0 +1,50 @@
/* === This file is part of Calamares - <http://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 "GeoIPXML.h"
#include "utils/Logger.h"
#include <QNetworkReply>
#include <QtXml/QDomDocument>
GeoIP::RegionZonePair
XMLGeoIP::processReply( const QByteArray& data )
{
QString domError;
int errorLine, errorColumn;
QDomDocument doc;
if ( doc.setContent( data, false, &domError, &errorLine, &errorColumn ) )
{
const auto tzElements = doc.elementsByTagName( "TimeZone" );
cDebug() << "GeoIP found" << tzElements.length() << "elements";
for ( int it = 0; it < tzElements.length(); ++it )
{
auto e = tzElements.at(it).toElement();
return splitTZString( e.text() );
}
}
else
{
cDebug() << "GeoIP XML data error:" << domError << "(line" << errorLine << errorColumn << ')';
}
return qMakePair( QString(), QString() );
}

View File

@@ -0,0 +1,36 @@
/* === This file is part of Calamares - <http://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 GEOIPXML_H
#define GEOIPXML_H
#include "GeoIP.h"
/** @brief GeoIP lookup with XML data
*
* The data is assumed to be in XML format with a
* <Response><TimeZone></TimeZone></Response>
* element, which contains the text (string) for the region/zone. This
* format is expected by, e.g. the Ubiquity installer.
*/
struct XMLGeoIP : public GeoIP
{
virtual RegionZonePair processReply( const QByteArray& );
} ;
#endif

View File

@@ -43,9 +43,11 @@ LocaleConfiguration::fromLanguageAndLocation( const QString& languageLocale,
const QStringList& availableLocales,
const QString& countryCode )
{
LocaleConfiguration lc = LocaleConfiguration();
LocaleConfiguration lc;
// Note that the documentation how this works is in packages.conf
QString language = languageLocale.split( '_' ).first();
lc.myLanguageLocaleBcp47 = QLocale(language).bcp47Name();
lc.myLanguageLocaleBcp47 = QLocale(language).bcp47Name().toLower();
QStringList linesForLanguage;
for ( const QString &line : availableLocales )
@@ -288,7 +290,7 @@ LocaleConfiguration::isEmpty() const
QMap< QString, QString >
LocaleConfiguration::toMap()
LocaleConfiguration::toMap() const
{
QMap< QString, QString > map;
@@ -324,3 +326,9 @@ LocaleConfiguration::toMap()
return map;
}
QString
LocaleConfiguration::toBcp47() const
{
return myLanguageLocaleBcp47;
}

View File

@@ -35,16 +35,21 @@ public:
bool isEmpty() const;
QMap< QString, QString > toMap() const;
// Note that the documentation how this works is in packages.conf
QString toBcp47() const;
// These become all uppercase in locale.conf, but we keep them lowercase here to
// avoid confusion with locale.h.
QString lang, lc_numeric, lc_time, lc_monetary, lc_paper, lc_name, lc_address,
lc_telephone, lc_measurement, lc_identification;
QString myLanguageLocaleBcp47;
QMap< QString, QString > toMap();
// If the user has explicitly selected language (from the dialog)
// or numbers format, set these to avoid implicit changes to them.
bool explicit_lang, explicit_lc;
private:
QString myLanguageLocaleBcp47;
};
#endif // LOCALECONFIGURATION_H

View File

@@ -489,8 +489,10 @@ LocalePage::updateGlobalStorage()
->insert( "locationRegion", location.region );
Calamares::JobQueue::instance()->globalStorage()
->insert( "locationZone", location.zone );
Calamares::JobQueue::instance()->globalStorage()
->insert( "locale", m_selectedLocaleConfiguration.myLanguageLocaleBcp47);
const QString bcp47 = m_selectedLocaleConfiguration.toBcp47();
Calamares::JobQueue::instance()->globalStorage()->insert( "locale", bcp47 );
cDebug() << "Updated locale globals, BCP47=" << bcp47;
// If we're in chroot mode (normal install mode), then we immediately set the
// timezone on the live system.

View File

@@ -1,6 +1,7 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014-2016, Teo Mrnjavac <teo@kde.org>
* Copyright 2018, Adriaan de Groot <groot.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
@@ -18,11 +19,17 @@
#include "LocaleViewStep.h"
#include "GeoIP.h"
#include "GeoIPFreeGeoIP.h"
#ifdef HAVE_XML
#include "GeoIPXML.h"
#endif
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "LocalePage.h"
#include "timezonewidget/localeglobal.h"
#include "widgets/WaitingWidget.h"
#include "JobQueue.h"
#include "GlobalStorage.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h"
@@ -110,54 +117,52 @@ LocaleViewStep::setUpPage()
void
LocaleViewStep::fetchGeoIpTimezone()
{
QString actualUrl( m_geoipUrl );
GeoIP *handler = nullptr;
if ( m_geoipStyle.isEmpty() || m_geoipStyle == "legacy" )
{
actualUrl.append( "/json/" );
handler = new FreeGeoIP;
}
else if ( m_geoipStyle == "json" )
{
handler = new FreeGeoIP;
}
#if defined(HAVE_XML)
else if ( m_geoipStyle == "xml" )
{
handler = new XMLGeoIP;
}
#endif
else
{
cDebug() << "WARNING: GeoIP Style" << m_geoipStyle << "is not recognized.";
setUpPage();
return;
}
cDebug() << "Fetching GeoIP data from" << actualUrl;
QNetworkAccessManager *manager = new QNetworkAccessManager( this );
connect( manager, &QNetworkAccessManager::finished,
[=]( QNetworkReply* reply )
{
if ( reply->error() == QNetworkReply::NoError )
{
QByteArray data = reply->readAll();
try
{
YAML::Node doc = YAML::Load( reply->readAll() );
QVariant var = CalamaresUtils::yamlToVariant( doc );
if ( !var.isNull() &&
var.isValid() &&
var.type() == QVariant::Map )
{
QVariantMap map = var.toMap();
if ( map.contains( "time_zone" ) &&
!map.value( "time_zone" ).toString().isEmpty() )
{
QString timezoneString = map.value( "time_zone" ).toString();
QStringList tzParts = timezoneString.split( '/', QString::SkipEmptyParts );
if ( tzParts.size() >= 2 )
{
cDebug() << "GeoIP reporting" << timezoneString;
QString region = tzParts.takeFirst();
QString zone = tzParts.join( '/' );
m_startingTimezone = qMakePair( region, zone );
}
}
}
}
catch ( YAML::Exception& e )
{
CalamaresUtils::explainYamlException( e, data, "GeoIP data");
}
auto tz = handler->processReply( reply->readAll() );
if ( !tz.first.isEmpty() )
m_startingTimezone = tz;
else
cDebug() << "WARNING: GeoIP lookup at" << reply->url() << "failed.";
}
delete handler;
reply->deleteLater();
manager->deleteLater();
setUpPage();
} );
QNetworkRequest request;
QString requestUrl = QString( "%1/json" )
.arg( QUrl::fromUserInput( m_geoipUrl ).toString() );
request.setUrl( QUrl( requestUrl ) );
request.setUrl( QUrl::fromUserInput( actualUrl ) );
request.setAttribute( QNetworkRequest::FollowRedirectsAttribute, true );
manager->get( request );
}
@@ -293,4 +298,10 @@ LocaleViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{
m_geoipUrl = configurationMap.value( "geoipUrl" ).toString();
}
if ( configurationMap.contains( "geoipStyle" ) &&
configurationMap.value( "geoipStyle" ).type() == QVariant::String &&
!configurationMap.value( "geoipStyle" ).toString().isEmpty() )
{
m_geoipStyle = configurationMap.value( "geoipStyle" ).toString();
}
}

View File

@@ -76,6 +76,7 @@ private:
QPair< QString, QString > m_startingTimezone;
QString m_localeGenPath;
QString m_geoipUrl;
QString m_geoipStyle;
QList< Calamares::job_ptr > m_jobs;
};

View File

@@ -1,7 +1,56 @@
---
# The starting timezone (e.g. the pin-on-the-map) when entering
# the locale page can be set through keys *region* and *zone*.
# If either is not set, defaults to America/New_York.
#
region: "America"
zone: "New_York"
# GeoIP settings. Leave commented out to disable GeoIP.
# Some distros come with a meaningfully commented and easy to parse
# `/etc/locale.gen`, and others ship a separate file
# `/usr/share/i18n/SUPPORTED` with a clean list of supported locales.
# We first try SUPPORTED, and if it doesn't exist, we fall back
# to parsing the lines from `locale.gen`. For distro's that ship
# the `locale.gen` file installed elsewhere, the key *localeGenPath*
# can be used to specify where it is. If not set, the default
# `/etc/locale.gen` is used.
#
#localeGenPath: "/etc/locale.gen"
# GeoIP settings. Leave commented out to disable GeoIP.
#
# An HTTP request is made to *geoipUrl* -- depending on the geoipStyle,
# the URL may be modified before use. The request should return
# valid data in a suitable format, depending on geoipStyle;
# generally this includes a string value with the timezone
# in <region>/<zone> format.
#
# Note that this example URL works, but the service is shutting
# down in June 2018.
#
# Suitable JSON data looks like
# ```
# {"time_zone":"America/New_York"}
# ```
# Suitable XML data looks like
# ```
# <Response><TimeZone>Europe/Brussels</TimeZone></Response>
# ```
#
#geoipUrl: "freegeoip.net"
# GeoIP style. Leave commented out for the "legacy" interpretation.
# This setting only makes sense if geoipUrl is set, enabliing geoIP.
#
# Possible values are:
# unset same as "legacy"
# blank same as "legacy"
# "legacy" appends "/json" to geoipUrl, above, and uses JSON format
# (which is what freegeoip.net provides there).
# "json" URL is not modified, uses JSON format.
# "xml" URL is not modified, uses XML format.
#
# The JSON format is provided by freegeoip.net, but that service is
# shutting down in June 2018. There are other providers with the same
# format. XML format is provided for Ubiquity.
#geoipStyle: "legacy"

View File

@@ -0,0 +1,73 @@
/* === This file is part of Calamares - <http://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/>.
*/
/**
* This is a test-application that does one GeoIP parse.
*/
#include <iostream>
#include "GeoIPFreeGeoIP.h"
#ifdef HAVE_XML
#include "GeoIPXML.h"
#endif
using std::cerr;
int main(int argc, char** argv)
{
if (argc != 2)
{
cerr << "Usage: curl url | test_geoip <format>\n";
return 1;
}
GeoIP* handler = nullptr;
if ( QLatin1String( "json" ) == argv[1] )
handler = new FreeGeoIP;
#ifdef HAVE_XML
else if ( QLatin1String( "xml" ) == argv[1] )
handler = new XMLGeoIP;
#endif
if ( !handler )
{
cerr << "Unknown format '" << argv[1] << "'\n";
return 1;
}
QByteArray ba;
while( !std::cin.eof() ) {
char arr[1024];
std::cin.read(arr,sizeof(arr));
int s = std::cin.gcount();
ba.append(arr, s);
}
auto tz = handler->processReply( ba );
if ( tz.first.isEmpty() )
{
std::cout << "No TimeZone determined from input.\n";
}
else
{
std::cout << "TimeZone Region=" << tz.first.toLatin1().constData() << "\nTimeZone Zone=" << tz.second.toLatin1().constData() << '\n';
}
return 0;
}

View File

@@ -3,6 +3,7 @@
* Copyright 2016, Lisa Vitolo <shainer@chakraos.org>
* Copyright 2017, Kyle Robbertze <krobbertze@gmail.com>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017, Gabriel Craciunescu <crazy@frugalware.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
@@ -56,14 +57,6 @@ NetInstallPage::NetInstallPage( QWidget* parent )
ui->setupUi( this );
}
bool
NetInstallPage::isReady()
{
// nothing to wait for, the data are immediately ready
// if the user does not select any group nothing is installed
return true;
}
bool
NetInstallPage::readGroups( const QByteArray& yamlData )
{
@@ -77,7 +70,7 @@ NetInstallPage::readGroups( const QByteArray& yamlData )
m_groups = new PackageModel( groups );
CALAMARES_RETRANSLATE(
m_groups->setHeaderData( 0, Qt::Horizontal, tr( "Name" ) );
m_groups->setHeaderData( 0, Qt::Horizontal, tr( "Description" ) ); )
m_groups->setHeaderData( 1, Qt::Horizontal, tr( "Description" ) ); )
return true;
}
@@ -91,10 +84,13 @@ NetInstallPage::readGroups( const QByteArray& yamlData )
void
NetInstallPage::dataIsHere( QNetworkReply* reply )
{
// If m_required is *false* then we still say we're ready
// even if the reply is corrupt or missing.
if ( reply->error() != QNetworkReply::NoError )
{
cDebug() << reply->errorString();
ui->netinst_status->setText( tr( "Network Installation. (Disabled: Unable to fetch package lists, check your network connection)" ) );
emit checkReady( !m_required );
return;
}
@@ -103,6 +99,7 @@ NetInstallPage::dataIsHere( QNetworkReply* reply )
cDebug() << "Netinstall groups data was received, but invalid.";
ui->netinst_status->setText( tr( "Network Installation. (Disabled: Unable to fetch package lists, check your network connection)" ) );
reply->deleteLater();
emit checkReady( !m_required );
return;
}
@@ -111,15 +108,23 @@ NetInstallPage::dataIsHere( QNetworkReply* reply )
ui->groupswidget->header()->setSectionResizeMode( 1, QHeaderView::Stretch );
reply->deleteLater();
emit checkReady( isReady() );
emit checkReady( true );
}
QList<PackageTreeItem::ItemData> NetInstallPage::selectedPackages() const
PackageModel::PackageItemDataList
NetInstallPage::selectedPackages() const
{
return m_groups->getPackages();
if ( m_groups )
return m_groups->getPackages();
else
{
cDebug() << "WARNING: no netinstall groups are available.";
return PackageModel::PackageItemDataList();
}
}
void NetInstallPage::loadGroupList()
void
NetInstallPage::loadGroupList()
{
QString confUrl(
Calamares::JobQueue::instance()->globalStorage()->value(
@@ -138,7 +143,15 @@ void NetInstallPage::loadGroupList()
m_networkManager.get( request );
}
void NetInstallPage::onActivate()
void
NetInstallPage::setRequired( bool b )
{
m_required = b;
}
void
NetInstallPage::onActivate()
{
ui->groupswidget->setFocus();
}

View File

@@ -46,17 +46,24 @@ public:
void onActivate();
bool isReady();
// Retrieves the groups, with name, description and packages, from
// the remote URL configured in the settings. Assumes the URL is already
// in the global storage. This should be called before displaying the page.
void loadGroupList();
// Sets the "required" state of netinstall data. Influences whether
// corrupt or unavailable data causes checkReady() to be emitted
// true (not-required) or false.
void setRequired( bool );
bool getRequired() const
{
return m_required;
}
// Returns the list of packages belonging to groups that are
// selected in the view in this given moment. No data is cached here, so
// this function does not have constant time.
QList<PackageTreeItem::ItemData> selectedPackages() const;
PackageModel::PackageItemDataList selectedPackages() const;
public slots:
void dataIsHere( QNetworkReply* );
@@ -76,6 +83,7 @@ private:
QNetworkAccessManager m_networkManager;
PackageModel* m_groups;
bool m_required;
};
#endif // NETINSTALLPAGE_H

View File

@@ -2,6 +2,7 @@
* Copyright 2016, Luca Giambonini <almack@chakraos.org>
* Copyright 2016, Lisa Vitolo <shainer@chakraos.org>
* Copyright 2017, Kyle Robbertze <krobbertze@gmail.com>
* Copyright 2017, 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
@@ -30,11 +31,11 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( NetInstallViewStepFactory, registerPlugin<N
NetInstallViewStep::NetInstallViewStep( QObject* parent )
: Calamares::ViewStep( parent )
, m_widget( new NetInstallPage() )
, m_nextEnabled( true )
, m_nextEnabled( false )
{
emit nextStatusChanged( true );
connect( m_widget, &NetInstallPage::checkReady,
this, &NetInstallViewStep::nextStatusChanged );
this, &NetInstallViewStep::nextIsReady );
}
@@ -126,7 +127,7 @@ NetInstallViewStep::onLeave()
cDebug() << "Leaving netinstall, adding packages to be installed"
<< "to global storage";
QList<PackageTreeItem::ItemData> packages = m_widget->selectedPackages();
PackageModel::PackageItemDataList packages = m_widget->selectedPackages();
QVariantList installPackages;
QVariantList tryInstallPackages;
QVariantList packageOperations;
@@ -138,7 +139,7 @@ NetInstallViewStep::onLeave()
QVariant details( package.packageName );
// If it's a package with a pre- or post-script, replace
// with the more complicated datastructure.
if (!package.preScript.isEmpty() || !package.postScript.isEmpty())
if ( !package.preScript.isEmpty() || !package.postScript.isEmpty() )
{
QMap<QString, QVariant> sdetails;
sdetails.insert( "pre-script", package.preScript );
@@ -156,14 +157,14 @@ NetInstallViewStep::onLeave()
{
QMap<QString, QVariant> op;
op.insert( "install", QVariant( installPackages ) );
packageOperations.append(op);
packageOperations.append( op );
cDebug() << " .." << installPackages.length() << "critical packages.";
}
if ( !tryInstallPackages.empty() )
{
QMap<QString, QVariant> op;
op.insert( "try_install", QVariant( tryInstallPackages ) );
packageOperations.append(op);
packageOperations.append( op );
cDebug() << " .." << tryInstallPackages.length() << "non-critical packages.";
}
@@ -178,6 +179,11 @@ NetInstallViewStep::onLeave()
void
NetInstallViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{
m_widget->setRequired(
configurationMap.contains( "required" ) &&
configurationMap.value( "required" ).type() == QVariant::Bool &&
configurationMap.value( "required" ).toBool() );
if ( configurationMap.contains( "groupsUrl" ) &&
configurationMap.value( "groupsUrl" ).type() == QVariant::String )
{
@@ -186,3 +192,10 @@ NetInstallViewStep::setConfigurationMap( const QVariantMap& configurationMap )
m_widget->loadGroupList();
}
}
void
NetInstallViewStep::nextIsReady( bool b )
{
m_nextEnabled = b;
emit nextStatusChanged( b );
}

View File

@@ -60,6 +60,9 @@ public:
void setConfigurationMap( const QVariantMap& configurationMap ) override;
public slots:
void nextIsReady( bool );
private:
NetInstallPage* m_widget;
bool m_nextEnabled;

View File

@@ -163,7 +163,8 @@ PackageModel::getPackages() const
{
QList<PackageTreeItem*> items = getItemPackages( m_rootItem );
for ( auto package : m_hiddenItems )
items.append( getItemPackages( package ) );
if ( package->hiddenSelected() )
items.append( getItemPackages( package ) );
QList<PackageTreeItem::ItemData> packages;
for ( auto item : items )
{

View File

@@ -1,3 +1,4 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright (c) 2017, Kyle Robbertze <kyle@aims.ac.za>
@@ -28,14 +29,13 @@
#include <yaml-cpp/yaml.h>
// Required forward declarations
class PackageTreeItem;
class PackageModel : public QAbstractItemModel
{
Q_OBJECT
public:
using PackageItemDataList = QList< PackageTreeItem::ItemData >;
explicit PackageModel( const YAML::Node& data, QObject* parent = nullptr );
~PackageModel() override;
@@ -52,7 +52,7 @@ public:
QModelIndex parent( const QModelIndex& index ) const override;
int rowCount( const QModelIndex& parent = QModelIndex() ) const override;
int columnCount( const QModelIndex& parent = QModelIndex() ) const override;
QList<PackageTreeItem::ItemData> getPackages() const;
PackageItemDataList getPackages() const;
QList<PackageTreeItem*> getItemPackages( PackageTreeItem* item ) const;
private:

View File

@@ -19,6 +19,8 @@
#include "PackageTreeItem.h"
#include "utils/Logger.h"
PackageTreeItem::PackageTreeItem( const ItemData& data, PackageTreeItem* parent )
: m_parentItem( parent )
, m_data( data )
@@ -36,7 +38,15 @@ PackageTreeItem::PackageTreeItem( const QString packageName, PackageTreeItem* pa
PackageTreeItem::PackageTreeItem( PackageTreeItem* parent ) :
m_parentItem( parent )
{ }
{
}
PackageTreeItem::PackageTreeItem::PackageTreeItem() :
PackageTreeItem( QString(), nullptr )
{
m_data.selected = Qt::Checked;
m_data.name = QLatin1Literal( "<root>" );
}
PackageTreeItem::~PackageTreeItem()
{
@@ -101,6 +111,13 @@ PackageTreeItem::parentItem()
return m_parentItem;
}
const PackageTreeItem*
PackageTreeItem::parentItem() const
{
return m_parentItem;
}
QString
PackageTreeItem::prettyName() const
{
@@ -143,6 +160,26 @@ PackageTreeItem::setHidden( bool isHidden )
m_data.isHidden = isHidden;
}
bool
PackageTreeItem::hiddenSelected() const
{
Q_ASSERT( m_data.isHidden );
if (! m_data.selected )
return false;
const PackageTreeItem* currentItem = parentItem();
while ( currentItem != nullptr )
{
if ( !currentItem->isHidden() )
return currentItem->isSelected() != Qt::Unchecked;
currentItem = currentItem->parentItem();
}
/* Has no non-hiddent parents */
return m_data.selected;
}
bool
PackageTreeItem::isCritical() const
{
@@ -164,34 +201,47 @@ PackageTreeItem::isSelected() const
void
PackageTreeItem::setSelected( Qt::CheckState isSelected )
{
if ( parentItem() == nullptr )
// This is the root, it is always checked so don't change state
return;
m_data.selected = isSelected;
setChildrenSelected( isSelected );
// Look for suitable parent item which may change checked-state
// when one of its children changes.
PackageTreeItem* currentItem = parentItem();
while ( currentItem != nullptr )
while ( ( currentItem != nullptr ) && ( currentItem->childCount() == 0 ) )
{
int childrenSelected = 0;
bool isChildPartiallySelected = false;
for ( int i = 0; i < currentItem->childCount(); i++ )
{
if ( currentItem->child( i )->isSelected() == Qt::Checked )
childrenSelected++;
if ( currentItem->child( i )->isSelected() == Qt::PartiallyChecked )
isChildPartiallySelected = true;
}
if ( !childrenSelected && !isChildPartiallySelected )
currentItem->m_data.selected = Qt::Unchecked;
else if ( childrenSelected == currentItem->childCount() )
currentItem->m_data.selected = Qt::Checked;
else
currentItem->m_data.selected = Qt::PartiallyChecked;
currentItem = currentItem->parentItem();
}
if ( currentItem == nullptr )
// Reached the root .. don't bother
return;
// Figure out checked-state based on the children
int childrenSelected = 0;
int childrenPartiallySelected = 0;
for ( int i = 0; i < currentItem->childCount(); i++ )
{
if ( currentItem->child( i )->isSelected() == Qt::Checked )
childrenSelected++;
if ( currentItem->child( i )->isSelected() == Qt::PartiallyChecked )
childrenPartiallySelected++;
}
if ( !childrenSelected && !childrenPartiallySelected)
currentItem->setSelected( Qt::Unchecked );
else if ( childrenSelected == currentItem->childCount() )
currentItem->setSelected( Qt::Checked );
else
currentItem->setSelected( Qt::PartiallyChecked );
}
void
PackageTreeItem::setChildrenSelected( Qt::CheckState isSelected )
{
if ( isSelected != Qt::PartiallyChecked )
// Children are never root; don't need to use setSelected on them.
for ( auto child : m_childItems )
{
child->m_data.selected = isSelected;

View File

@@ -40,7 +40,8 @@ public:
};
explicit PackageTreeItem( const ItemData& data, PackageTreeItem* parent = nullptr );
explicit PackageTreeItem( const QString packageName, PackageTreeItem* parent = nullptr );
explicit PackageTreeItem( PackageTreeItem* parent = nullptr );
explicit PackageTreeItem( PackageTreeItem* parent );
explicit PackageTreeItem(); // The root of the tree; always selected, named <root>
~PackageTreeItem() override;
void appendChild( PackageTreeItem* child );
@@ -49,16 +50,30 @@ public:
int columnCount() const;
QVariant data( int column ) const override;
int row() const;
PackageTreeItem* parentItem();
const PackageTreeItem* parentItem() const;
QString prettyName() const;
QString description() const;
QString preScript() const;
QString packageName() const;
QString postScript() const;
bool isHidden() const;
void setHidden( bool isHidden );
/**
* @brief Is this hidden item, considered "selected"?
*
* This asserts when called on a non-hidden item.
* A hidden item has its own selected state, but really
* falls under the selectedness of the parent item.
*/
bool hiddenSelected() const;
bool isCritical() const;
void setCritical( bool isCritical );
Qt::CheckState isSelected() const;
void setSelected( Qt::CheckState isSelected );
void setChildrenSelected( Qt::CheckState isSelected );

View File

@@ -1,2 +1,13 @@
---
# This is the URL that is retrieved to get the netinstall groups-and-packages
# data (which should be in the format described in netinstall.yaml).
groupsUrl: http://chakraos.org/netinstall.php
# If the installation can proceed without netinstall (e.g. the Live CD
# can create a working installed system, but netinstall is preferred
# to bring it up-to-date or extend functionality) leave this set to
# false (the default). If set to true, the netinstall data is required.
#
# This only has an effect if the netinstall data cannot be retrieved,
# or is corrupt: having "required" set, means the install cannot proceed.
required: false

View File

@@ -55,8 +55,12 @@ def _change_mode(mode):
def pretty_name():
if not group_packages:
# Outside the context of an operation
s = _("Processing packages (%(count)d / %(total)d)")
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)
@@ -314,7 +318,10 @@ def subst_locale(plist):
"""
locale = libcalamares.globalstorage.value("locale")
if not locale:
return plist
# 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:
@@ -360,20 +367,20 @@ def run_operations(pkgman, entry):
global group_packages, completed_packages, mode_packages
for key in entry.keys():
entry[key] = subst_locale(entry[key])
group_packages = len(entry[key])
package_list = subst_locale(entry[key])
group_packages = len(package_list)
if key == "install":
_change_mode(INSTALL)
if all([isinstance(x, str) for x in entry[key]]):
pkgman.install(entry[key])
if all([isinstance(x, str) for x in package_list]):
pkgman.install(package_list)
else:
for package in entry[key]:
for package in package_list:
pkgman.install_package(package)
elif key == "try_install":
_change_mode(INSTALL)
# we make a separate package manager call for each package so a
# single failing package won't stop all of them
for package in entry[key]:
for package in package_list:
try:
pkgman.install_package(package)
except subprocess.CalledProcessError:
@@ -382,10 +389,10 @@ def run_operations(pkgman, entry):
libcalamares.utils.debug(warn_text)
elif key == "remove":
_change_mode(REMOVE)
pkgman.remove(entry[key])
pkgman.remove(package_list)
elif key == "try_remove":
_change_mode(REMOVE)
for package in entry[key]:
for package in package_list:
try:
pkgman.remove([package])
except subprocess.CalledProcessError:
@@ -394,9 +401,9 @@ def run_operations(pkgman, entry):
libcalamares.utils.debug(warn_text)
elif key == "localInstall":
_change_mode(INSTALL)
pkgman.install(entry[key], from_local=True)
pkgman.install(package_list, from_local=True)
completed_packages += len(entry[key])
completed_packages += len(package_list)
libcalamares.job.setprogress(completed_packages * 1.0 / total_packages)
libcalamares.utils.debug(pretty_name())
@@ -422,6 +429,11 @@ def run():
else:
return "Bad backend", "backend=\"{}\"".format(backend)
skip_this = libcalamares.job.configuration.get("skip_if_no_internet", False)
if skip_this and not libcalamares.globalstorage.value("hasInternet"):
libcalamares.utils.debug( "WARNING: packages installation has been skipped: no internet" )
return None
update_db = libcalamares.job.configuration.get("update_db", False)
if update_db and libcalamares.globalstorage.value("hasInternet"):
pkgman.update_db()
@@ -435,7 +447,7 @@ def run():
completed_packages = 0
for op in operations:
for packagelist in op.values():
total_packages += len(packagelist)
total_packages += len(subst_locale(packagelist))
if not total_packages:
# Avoids potential divide-by-zero in progress reporting

View File

@@ -14,9 +14,20 @@
#
backend: dummy
# If set to true, a package-manager specific update procedure
# is run first (only if there is internet) to update the list
# of packages and dependencies.
# Often package installation needs an internet connection.
# Since you may allow system installation without a connection
# and want to offer **optional** package installation, it's
# possible to have no internet, yet have this packages module
# enabled in settings.
#
# You can skip the whole module when there is no internet
# by setting *skip_if_no_internet* to true.
#
# You can run a package-manager specific update procedure
# before installing packages (for instance, to update the
# list of packages and dependencies); this is done only if there
# is an internet connection. Set *update_db* to true to do so.
skip_if_no_internet: false
update_db: true
#
@@ -29,9 +40,10 @@ update_db: true
# packages that need to be installed or removed can run before
# this one. Distro developers may want to install locale packages
# or remove drivers not needed on the installed system.
# This job will populate a list of dictionaries in the global
# storage called "packageOperations" and it is processed
# after the static list in the job configuration.
# Such a job would populate a list of dictionaries in the global
# storage called "packageOperations" and that list is processed
# after the static list in the job configuration (i.e. the list
# that is in this configuration file).
#
# Allowed package operations are:
# - install, try_install: will call the package manager to
@@ -49,7 +61,7 @@ update_db: true
# while try_remove carries on. Packages may be listed as
# (localized) names.
#
# There are two formats for naming packages: as a name # or as package-data,
# There are two formats for naming packages: as a name or as package-data,
# which is an object notation providing package-name, as well as pre- and
# post-install scripts.
#
@@ -64,7 +76,7 @@ update_db: true
# pre-script: touch /tmp/installing-vi
# post-script: rm -f /tmp/installing-vi
#
# The pre- and post-scripts are optional, but not both optional: using
# The pre- and post-scripts are optional, but you cannot leave both out: using
# "package: vi" with neither script option will trick Calamares into
# trying to install a package named "package: vi", which is unlikely to work.
#
@@ -72,17 +84,23 @@ update_db: true
# packages for software based on the selected system locale. By including
# the string LOCALE in the package name, the following happens:
#
# - if the system locale is English (generally US English; en_GB is a valid
# localization), then the package is not installed at all,
# - otherwise LOCALE is replaced by the Bcp47 name of the selected system
# locale, e.g. nl_BE.
# - if the system locale is English (any variety), then the package is not
# installed at all,
# - otherwise $LOCALE or ${LOCALE} is replaced by the **lower-cased** BCP47
# name of the **language** part of the selected system locale (not the
# country/region/dialect part), e.g. selecting *nl_BE* will use *nl*
# here.
#
# Take care that just plain LOCALE will not be replaced, so foo-LOCALE will
# be left unchanged, while foo-$LOCALE will be changed. However, foo-LOCALE
# **will** be removed from the list of packages, if English is selected.
#
# The following installs localizations for vi, if they are relevant; if
# there is no localization, installation continues normally.
#
# - install
# - vi-LOCALE
# - package: vi-LOCALE
# - vi-$LOCALE
# - package: vi-${LOCALE}
# pre-script: touch /tmp/installing-vi
# post-script: rm -f /tmp/installing-vi
#
@@ -114,6 +132,7 @@ update_db: true
operations:
- install:
- vi
- vi-${LOCALE}
- wget
- binutils
- remove:

View File

@@ -1,5 +1,4 @@
find_package(ECM 5.10.0 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH})
find_package(ECM ${ECM_VERSION} REQUIRED NO_MODULE)
include(KDEInstallDirs)
include(GenerateExportHeader)
@@ -9,10 +8,22 @@ find_package( KF5 REQUIRED CoreAddons )
find_package( KF5 REQUIRED Config I18n IconThemes KIO Service )
find_package( KPMcore 3.1.50 QUIET )
if ( ${KPMcore_FOUND} )
if ( KPMcore_FOUND )
add_definitions(-DWITH_KPMCORE22)
endif()
find_package( KPMcore 3.0.3 REQUIRED )
find_package( KPMcore 3.0.3 QUIET )
# 3.0.3 and newer has fixes for NVMe support; allow 3.0.2, but warn
# about it .. needs to use a different feature name because it otherwise
# gets reported as KPMcore (the package).
if ( KPMcore_FOUND )
message( STATUS "KPMCore supports NVMe operations" )
add_feature_info( KPMcoreNVMe KPMcore_FOUND "KPMcore with NVMe support" )
else()
find_package( KPMcore 3.0.2 REQUIRED )
message( WARNING "KPMCore 3.0.2 is known to have bugs with NVMe devices" )
add_feature_info( KPMcoreNVMe KPMcore_FOUND "Older KPMcore with no NVMe support" )
endif()
find_library( atasmart_LIB atasmart )
find_library( blkid_LIB blkid )
if( NOT atasmart_LIB )
@@ -58,7 +69,6 @@ calamares_add_plugin( partition
gui/PrettyRadioButton.cpp
gui/ScanningDialog.cpp
gui/ReplaceWidget.cpp
jobs/CheckFileSystemJob.cpp
jobs/ClearMountsJob.cpp
jobs/ClearTempMountsJob.cpp
jobs/CreatePartitionJob.cpp
@@ -66,7 +76,6 @@ calamares_add_plugin( partition
jobs/DeletePartitionJob.cpp
jobs/FillGlobalStorageJob.cpp
jobs/FormatPartitionJob.cpp
jobs/MoveFileSystemJob.cpp
jobs/PartitionJob.cpp
jobs/ResizePartitionJob.cpp
jobs/SetPartitionFlagsJob.cpp

View File

@@ -1,83 +0,0 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2016, Teo Mrnjavac <teo@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 "jobs/CheckFileSystemJob.h"
#include <utils/Logger.h>
// KPMcore
#include <kpmcore/core/partition.h>
#include <kpmcore/fs/filesystem.h>
#include <kpmcore/util/report.h>
#include <QThread>
CheckFileSystemJob::CheckFileSystemJob( Partition* partition )
: PartitionJob( partition )
{}
QString
CheckFileSystemJob::prettyName() const
{
QString path = partition()->partitionPath();
return tr( "Checking file system on partition %1." ).arg( path );
}
QString
CheckFileSystemJob::prettyStatusMessage() const
{
return prettyName();
}
Calamares::JobResult
CheckFileSystemJob::exec()
{
FileSystem& fs = partition()->fileSystem();
// if we cannot check, assume everything is fine
if ( fs.supportCheck() != FileSystem::cmdSupportFileSystem )
return Calamares::JobResult::ok();
Report report( nullptr );
bool ok = fs.check( report, partition()->partitionPath() );
int retries = 0;
const int MAX_RETRIES = 10;
while ( !ok )
{
cDebug() << "Partition" << partition()->partitionPath()
<< "might not be ready yet, retrying (" << ++retries
<< "/" << MAX_RETRIES << ") ...";
QThread::sleep( 2 /*seconds*/ );
ok = fs.check( report, partition()->partitionPath() );
if ( retries == MAX_RETRIES )
break;
}
if ( !ok )
return Calamares::JobResult::error(
tr( "The file system check on partition %1 failed." )
.arg( partition()->partitionPath() ),
report.toText()
);
return Calamares::JobResult::ok();
}

View File

@@ -1,239 +0,0 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@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/>.
*/
// This class is heavily based on the MoveFileSystemJob class from KDE Partition
// Manager.
// The copyBlock functions come from Partition Manager Job class.
// Original copyright follow:
/***************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include <jobs/MoveFileSystemJob.h>
#include <utils/Logger.h>
// KPMcore
#include <kpmcore/core/copysourcedevice.h>
#include <kpmcore/core/copytargetdevice.h>
#include <kpmcore/core/device.h>
#include <kpmcore/core/partition.h>
#include <kpmcore/fs/filesystem.h>
#include <kpmcore/util/report.h>
MoveFileSystemJob::MoveFileSystemJob( Device* device, Partition* partition, qint64 oldFirstSector, qint64 newFirstSector, qint64 length )
: PartitionJob( partition )
, m_device( device )
, m_oldFirstSector( oldFirstSector )
, m_newFirstSector( newFirstSector )
, m_length( length )
{}
QString
MoveFileSystemJob::prettyName() const
{
return tr( "Move file system of partition %1." ).arg( partition()->partitionPath() );
}
Calamares::JobResult
MoveFileSystemJob::exec()
{
Report report( nullptr );
QString partitionPath = partition()->partitionPath();
CopySourceDevice moveSource( *m_device, m_oldFirstSector, m_oldFirstSector + m_length - 1 );
CopyTargetDevice moveTarget( *m_device, m_newFirstSector, m_newFirstSector + m_length - 1 );
if ( !moveSource.open() )
return Calamares::JobResult::error(
QString(),
tr( "Could not open file system on partition %1 for moving." ).arg( partitionPath )
);
if ( !moveTarget.open() )
return Calamares::JobResult::error(
QString(),
tr( "Could not create target for moving file system on partition %1." ).arg( partitionPath )
);
bool ok = copyBlocks( report, moveTarget, moveSource );
if ( !ok )
{
if ( rollbackCopyBlocks( report, moveTarget, moveSource ) )
return Calamares::JobResult::error(
QString(),
tr( "Moving of partition %1 failed, changes have been rolled back." ).arg( partitionPath )
+ '\n' + report.toText()
);
else
return Calamares::JobResult::error(
QString(),
tr( "Moving of partition %1 failed. Roll back of the changes have failed." ).arg( partitionPath )
+ '\n' + report.toText()
);
}
FileSystem& fs = partition()->fileSystem();
fs.setFirstSector( m_newFirstSector );
fs.setLastSector( m_newFirstSector + m_length - 1 );
if ( !fs.updateBootSector( report, partitionPath ) )
return Calamares::JobResult::error(
QString(),
tr( "Updating boot sector after the moving of partition %1 failed." ).arg( partitionPath )
+ '\n' + report.toText()
);
return Calamares::JobResult::ok();
}
bool
MoveFileSystemJob::copyBlocks( Report& report, CopyTargetDevice& target, CopySourceDevice& source )
{
/** @todo copyBlocks() assumes that source.sectorSize() == target.sectorSize(). */
if ( source.sectorSize() != target.sectorSize() )
{
report.line() << tr( "The logical sector sizes in the source and target for copying are not the same. This is currently unsupported." );
return false;
}
bool rval = true;
const qint64 blockSize = 16065 * 8; // number of sectors per block to copy
const qint64 blocksToCopy = source.length() / blockSize;
qint64 readOffset = source.firstSector();
qint64 writeOffset = target.firstSector();
qint32 copyDir = 1;
if ( target.firstSector() > source.firstSector() )
{
readOffset = source.firstSector() + source.length() - blockSize;
writeOffset = target.firstSector() + source.length() - blockSize;
copyDir = -1;
}
qint64 blocksCopied = 0;
Q_ASSERT( blockSize > 0 );
Q_ASSERT( source.sectorSize() > 0 );
Q_ASSERT( blockSize * source.sectorSize() > 0 );
void* buffer = malloc( size_t( blockSize * source.sectorSize() ) );
qint64 percent = 0;
while ( blocksCopied < blocksToCopy )
{
rval = source.readSectors( buffer, readOffset + blockSize * blocksCopied * copyDir, blockSize );
if ( !rval )
break;
rval = target.writeSectors( buffer, writeOffset + blockSize * blocksCopied * copyDir, blockSize );
if ( !rval )
break;
if ( ++blocksCopied * 100 / blocksToCopy != percent )
{
percent = blocksCopied * 100 / blocksToCopy;
progress( percent / 100. );
}
}
const qint64 lastBlock = source.length() % blockSize;
// copy the remainder
if ( rval && lastBlock > 0 )
{
Q_ASSERT( lastBlock < blockSize );
const qint64 lastBlockReadOffset = copyDir > 0 ? readOffset + blockSize * blocksCopied : source.firstSector();
const qint64 lastBlockWriteOffset = copyDir > 0 ? writeOffset + blockSize * blocksCopied : target.firstSector();
rval = source.readSectors( buffer, lastBlockReadOffset, lastBlock );
if ( rval )
rval = target.writeSectors( buffer, lastBlockWriteOffset, lastBlock );
if ( rval )
emit progress( 1.0 );
}
free( buffer );
return rval;
}
bool
MoveFileSystemJob::rollbackCopyBlocks( Report& report, CopyTargetDevice& origTarget, CopySourceDevice& origSource )
{
if ( !origSource.overlaps( origTarget ) )
{
report.line() << tr( "Source and target for copying do not overlap: Rollback is not required." );
return true;
}
// default: use values as if we were copying from front to back.
qint64 undoSourceFirstSector = origTarget.firstSector();
qint64 undoSourceLastSector = origTarget.firstSector() + origTarget.sectorsWritten() - 1;
qint64 undoTargetFirstSector = origSource.firstSector();
qint64 undoTargetLastSector = origSource.firstSector() + origTarget.sectorsWritten() - 1;
if ( origTarget.firstSector() > origSource.firstSector() )
{
// we were copying from back to front
undoSourceFirstSector = origTarget.firstSector() + origSource.length() - origTarget.sectorsWritten();
undoSourceLastSector = origTarget.firstSector() + origSource.length() - 1;
undoTargetFirstSector = origSource.lastSector() - origTarget.sectorsWritten() + 1;
undoTargetLastSector = origSource.lastSector();
}
CopySourceDevice undoSource( origTarget.device(), undoSourceFirstSector, undoSourceLastSector );
if ( !undoSource.open() )
{
report.line() << tr( "Could not open device %1 to rollback copying." )
.arg( origTarget.device().deviceNode() );
return false;
}
CopyTargetDevice undoTarget( origSource.device(), undoTargetFirstSector, undoTargetLastSector );
if ( !undoTarget.open() )
{
report.line() << tr( "Could not open device %1 to rollback copying." )
.arg( origSource.device().deviceNode() );
return false;
}
return copyBlocks( report, undoTarget, undoSource );
}

View File

@@ -1,76 +0,0 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@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/>.
*/
// This class is heavily based on the MoveFileSystemJob class from KDE Partition
// Manager. Original copyright follow:
/***************************************************************************
* Copyright (C) 2008 by Volker Lanz <vl@fidra.de> *
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#ifndef MOVEFILESYSTEMJOB_H
#define MOVEFILESYSTEMJOB_H
#include <jobs/PartitionJob.h>
class CopySourceDevice;
class CopyTargetDevice;
class Device;
class Partition;
class Report;
/**
* This job moves the data of a filesystem from one position on the disk to
* another.
*
* It is used by the ResizePartitionJob.
*/
class MoveFileSystemJob : public PartitionJob
{
Q_OBJECT
public:
MoveFileSystemJob( Device* device, Partition* partition, qint64 oldFirstSector, qint64 newFirstSector, qint64 length );
QString prettyName() const override;
Calamares::JobResult exec() override;
private:
Device* m_device;
qint64 m_oldFirstSector;
qint64 m_newFirstSector;
qint64 m_length;
bool copyBlocks( Report& report, CopyTargetDevice& target, CopySourceDevice& source );
bool rollbackCopyBlocks( Report& report, CopyTargetDevice& origTarget, CopySourceDevice& origSource );
};
#endif /* MOVEFILESYSTEMJOB_H */

View File

@@ -2,6 +2,7 @@
*
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Andrius Štikonas <andrius@stikonas.eu>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,156 +18,12 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
// This class is heavily based on the ResizeOperation class from KDE Partition
// Manager. Original copyright follow:
/***************************************************************************
* Copyright (C) 2008,2012 by Volker Lanz <vl@fidra.de> *
* *
* This program 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 2 of the License, or *
* (at your option) any later version. *
* *
* This program 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 this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
***************************************************************************/
#include "jobs/ResizePartitionJob.h"
#include "jobs/CheckFileSystemJob.h"
#include "jobs/MoveFileSystemJob.h"
#include "utils/Logger.h"
// KPMcore
#include <kpmcore/backend/corebackend.h>
#include <kpmcore/backend/corebackendmanager.h>
#include <kpmcore/backend/corebackenddevice.h>
#include <kpmcore/backend/corebackendpartition.h>
#include <kpmcore/backend/corebackendpartitiontable.h>
#include <kpmcore/core/device.h>
#include <kpmcore/core/partition.h>
#include <kpmcore/util/report.h>
// Qt
#include <QScopedPointer>
//- ResizeFileSystemJob --------------------------------------------------------
class ResizeFileSystemJob : public Calamares::Job
{
Q_OBJECT
public:
ResizeFileSystemJob( Device* device, CoreBackendPartitionTable* backendPartitionTable, Partition* partition, qint64 length )
: m_device( device )
, m_backendPartitionTable( backendPartitionTable )
, m_partition( partition )
, m_length( length )
{}
QString prettyName() const override
{
QString path = m_partition->partitionPath();
return tr( "Resize file system on partition %1." ).arg( path );
}
Calamares::JobResult exec() override
{
Report report( nullptr );
FileSystem& fs = m_partition->fileSystem();
FileSystem::CommandSupportType support = m_length < fs.length() ? fs.supportShrink() : fs.supportGrow();
switch ( support )
{
case FileSystem::cmdSupportBackend:
if ( !backendResize( &report ) )
return Calamares::JobResult::error(
QString(),
tr( "Parted failed to resize filesystem." ) + '\n' + report.toText()
);
break;
case FileSystem::cmdSupportFileSystem:
{
qint64 byteLength = m_device->logicalSize() * m_length;
bool ok = fs.resize( report, m_partition->partitionPath(), byteLength );
if ( !ok )
return Calamares::JobResult::error(
QString(),
tr( "Failed to resize filesystem." ) + '\n' + report.toText()
);
break;
}
default:
break;
}
fs.setLastSector( fs.firstSector() + m_length - 1 );
return Calamares::JobResult::ok();
}
private:
Device* m_device;
CoreBackendPartitionTable* m_backendPartitionTable;
Partition* m_partition;
qint64 m_length;
bool backendResize( Report* report )
{
bool ok = m_backendPartitionTable->resizeFileSystem( *report, *m_partition, m_length );
if ( !ok )
return false;
m_backendPartitionTable->commit();
return true;
}
};
//- SetPartGeometryJob ---------------------------------------------------------
class SetPartGeometryJob : public Calamares::Job
{
Q_OBJECT
public:
SetPartGeometryJob( CoreBackendPartitionTable* backendPartitionTable, Partition* partition, qint64 firstSector, qint64 length )
: m_backendPartitionTable( backendPartitionTable )
, m_partition( partition )
, m_firstSector( firstSector )
, m_length( length )
{}
QString prettyName() const override
{
QString path = m_partition->partitionPath();
return tr( "Update geometry of partition %1." ).arg( path );
}
Calamares::JobResult exec() override
{
Report report( nullptr );
qint64 lastSector = m_firstSector + m_length - 1;
bool ok = m_backendPartitionTable->updateGeometry( report, *m_partition, m_firstSector, lastSector );
if ( !ok )
{
return Calamares::JobResult::error(
QString(),
tr( "Failed to change the geometry of the partition." ) + '\n' + report.toText() );
}
m_partition->setFirstSector( m_firstSector );
m_partition->setLastSector( lastSector );
m_backendPartitionTable->commit();
return Calamares::JobResult::ok();
}
private:
CoreBackendPartitionTable* m_backendPartitionTable;
Partition* m_partition;
qint64 m_firstSector;
qint64 m_length;
};
#include <core/device.h>
#include <ops/resizeoperation.h>
#include <util/report.h>
//- ResizePartitionJob ---------------------------------------------------------
ResizePartitionJob::ResizePartitionJob( Device* device, Partition* partition, qint64 firstSector, qint64 lastSector )
@@ -194,7 +51,7 @@ ResizePartitionJob::prettyDescription() const
return tr( "Resize <strong>%2MB</strong> partition <strong>%1</strong> to "
"<strong>%3MB</strong>." )
.arg( partition()->partitionPath() )
.arg( ( m_oldLastSector - m_oldFirstSector ) * partition()->sectorSize() / 1024 / 1024 )
.arg( ( m_oldLastSector - m_oldFirstSector + 1 ) * partition()->sectorSize() / 1024 / 1024 )
.arg( ( m_newLastSector - m_newFirstSector + 1 ) * partition()->sectorSize() / 1024 / 1024 );
}
@@ -205,7 +62,7 @@ ResizePartitionJob::prettyStatusMessage() const
return tr( "Resizing %2MB partition %1 to "
"%3MB." )
.arg( partition()->partitionPath() )
.arg( ( m_oldLastSector - m_oldFirstSector ) * partition()->sectorSize() / 1024 / 1024 )
.arg( ( m_oldLastSector - m_oldFirstSector + 1 ) * partition()->sectorSize() / 1024 / 1024 )
.arg( ( m_newLastSector - m_newFirstSector + 1 ) * partition()->sectorSize() / 1024 / 1024 );
}
@@ -213,64 +70,21 @@ ResizePartitionJob::prettyStatusMessage() const
Calamares::JobResult
ResizePartitionJob::exec()
{
qint64 oldLength = m_oldLastSector - m_oldFirstSector + 1;
qint64 newLength = m_newLastSector - m_newFirstSector + 1;
// Assuming updatePreview() has been called, `partition` uses its new
// position and size. Reset it to the old values: part of the libparted
// backend relies on this (for example:
// LibPartedPartitionTable::updateGeometry())
// The jobs are responsible for updating the partition back when they are
// done.
Report report (nullptr);
// Restore partition sectors that were modified for preview
m_partition->setFirstSector( m_oldFirstSector );
m_partition->setLastSector( m_oldLastSector );
ResizeOperation op(*m_device, *m_partition, m_newFirstSector, m_newLastSector);
op.setStatus(Operation::StatusRunning);
connect(&op, &Operation::progress, [&](int percent) { emit progress(percent / 100.0); } );
CoreBackend* backend = CoreBackendManager::self()->backend();
QScopedPointer<CoreBackendDevice> backendDevice( backend->openDevice( m_device->deviceNode() ) );
if ( !backendDevice.data() )
{
QString errorMessage = tr( "The installer failed to resize partition %1 on disk '%2'." )
.arg( m_partition->partitionPath() )
.arg( m_device->name() );
return Calamares::JobResult::error(
errorMessage,
tr( "Could not open device '%1'." ).arg( m_device->deviceNode() )
);
}
QScopedPointer<CoreBackendPartitionTable> backendPartitionTable( backendDevice->openPartitionTable() );
QString errorMessage = tr( "The installer failed to resize partition %1 on disk '%2'." )
.arg( m_partition->partitionPath() )
.arg( m_device->name() );
if (op.execute(report))
return Calamares::JobResult::ok();
// Create jobs
QList< Calamares::job_ptr > jobs;
jobs << Calamares::job_ptr( new CheckFileSystemJob( partition() ) );
if ( m_partition->roles().has( PartitionRole::Extended ) )
jobs << Calamares::job_ptr( new SetPartGeometryJob( backendPartitionTable.data(), m_partition, m_newFirstSector, newLength ) );
else
{
bool shrink = newLength < oldLength;
bool grow = newLength > oldLength;
bool moveRight = m_newFirstSector > m_oldFirstSector;
bool moveLeft = m_newFirstSector < m_oldFirstSector;
if ( shrink )
{
jobs << Calamares::job_ptr( new ResizeFileSystemJob( m_device, backendPartitionTable.data(), m_partition, newLength ) );
jobs << Calamares::job_ptr( new SetPartGeometryJob( backendPartitionTable.data(), m_partition, m_oldFirstSector, newLength ) );
}
if ( moveRight || moveLeft )
{
// At this point, we need to set the partition's length to either the resized length, if it has already been
// shrunk, or to the original length (it may or may not then later be grown, we don't care here)
const qint64 length = shrink ? newLength : oldLength;
jobs << Calamares::job_ptr( new SetPartGeometryJob( backendPartitionTable.data(), m_partition, m_newFirstSector, length ) );
jobs << Calamares::job_ptr( new MoveFileSystemJob( m_device, m_partition, m_oldFirstSector, m_newFirstSector, length ) );
}
if ( grow )
{
jobs << Calamares::job_ptr( new SetPartGeometryJob( backendPartitionTable.data(), m_partition, m_newFirstSector, newLength ) );
jobs << Calamares::job_ptr( new ResizeFileSystemJob( m_device, backendPartitionTable.data(), m_partition, newLength ) );
}
}
jobs << Calamares::job_ptr( new CheckFileSystemJob( partition() ) );
return execJobList( jobs );
return Calamares::JobResult::error(errorMessage, report.toText());
}
void
@@ -290,31 +104,3 @@ ResizePartitionJob::device() const
{
return m_device;
}
Calamares::JobResult
ResizePartitionJob::execJobList( const QList< Calamares::job_ptr >& jobs )
{
QString errorMessage = tr( "The installer failed to resize partition %1 on disk '%2'." )
.arg( m_partition->partitionPath() )
.arg( m_device->name() );
int nbJobs = jobs.size();
int count = 0;
for ( Calamares::job_ptr job : jobs )
{
cLog() << "- " + job->prettyName();
Calamares::JobResult result = job->exec();
if ( !result )
{
if ( result.message().isEmpty() )
result.setMessage( errorMessage );
return result;
}
++count;
progress( qreal( count ) / nbJobs );
}
return Calamares::JobResult::ok();
}
#include "ResizePartitionJob.moc"

View File

@@ -51,8 +51,6 @@ private:
qint64 m_oldLastSector;
qint64 m_newFirstSector;
qint64 m_newLastSector;
Calamares::JobResult execJobList( const QList< Calamares::job_ptr >& jobs );
};
#endif /* RESIZEPARTITIONJOB_H */

View File

@@ -9,11 +9,9 @@ set( partitionjobtests_SRCS
${PartitionModule_SOURCE_DIR}/core/KPMHelpers.cpp
${PartitionModule_SOURCE_DIR}/core/PartitionInfo.cpp
${PartitionModule_SOURCE_DIR}/core/PartitionIterator.cpp
${PartitionModule_SOURCE_DIR}/jobs/CheckFileSystemJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/CreatePartitionJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/CreatePartitionTableJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/DeletePartitionJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/MoveFileSystemJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/PartitionJob.cpp
${PartitionModule_SOURCE_DIR}/jobs/ResizePartitionJob.cpp
PartitionJobTests.cpp

View File

@@ -0,0 +1,55 @@
find_package(ECM ${ECM_VERSION} REQUIRED NO_MODULE)
# Requires a sufficiently recent Plasma framework, but also
# needs a runtime support component (which we don't test for).
set( lnf_ver 5.41 )
find_package( KF5Config ${lnf_ver} )
find_package( KF5Plasma ${lnf_ver} )
find_package( KF5Package ${lnf_ver} )
set_package_properties(
KF5Config PROPERTIES
PURPOSE "For finding default Plasma Look-and-Feel"
)
set_package_properties(
KF5Plasma PROPERTIES
PURPOSE "For Plasma Look-and-Feel selection"
)
set_package_properties(
KF5Package PROPERTIES
PURPOSE "For Plasma Look-and-Feel selection"
)
if ( KF5Plasma_FOUND AND KF5Package_FOUND )
if ( KF5Config_FOUND )
set( option_kf5 Config )
set( option_defs WITH_KCONFIG )
# set( option_libs KF5::Config ) # Not needed anyway
endif()
find_package( KF5 ${lnf_ver} REQUIRED CoreAddons Plasma Package ${option_kf5} )
calamares_add_plugin( plasmalnf
TYPE viewmodule
EXPORT_MACRO PLUGINDLLEXPORT_PRO
COMPILE_DEFINITIONS
${option_defs}
SOURCES
PlasmaLnfViewStep.cpp
PlasmaLnfPage.cpp
PlasmaLnfJob.cpp
ThemeWidget.cpp
RESOURCES
page_plasmalnf.qrc
UI
page_plasmalnf.ui
LINK_PRIVATE_LIBRARIES
calamaresui
${option_libs}
KF5::Package
KF5::Plasma
SHARED_LIB
)
else()
calamares_skip_module( "plasmalnf (missing requirements)" )
endif()

View File

@@ -0,0 +1,78 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, 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 "PlasmaLnfJob.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
PlasmaLnfJob::PlasmaLnfJob( const QString& lnfPath, const QString& id )
: m_lnfPath( lnfPath )
, m_id( id )
{
}
PlasmaLnfJob::~PlasmaLnfJob()
{
}
QString
PlasmaLnfJob::prettyName() const
{
return tr( "Plasma Look-and-Feel Job" );
}
QString
PlasmaLnfJob::prettyDescription() const
{
return prettyName();
}
QString PlasmaLnfJob::prettyStatusMessage() const
{
return prettyName();
}
Calamares::JobResult
PlasmaLnfJob::exec()
{
cDebug() << "Plasma Look-and-Feel Job";
auto system = CalamaresUtils::System::instance();
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
QStringList command(
{
"sudo", "-E", "-H", "-u", gs->value( "username" ).toString(),
m_lnfPath, "-platform", "minimal", "--resetLayout", "--apply", m_id
} );
int r = system->targetEnvCall( command );
if ( r )
return Calamares::JobResult::error(
tr( "Could not select KDE Plasma Look-and-Feel package" ),
tr( "Could not select KDE Plasma Look-and-Feel package" ) );
return Calamares::JobResult::ok();
}

View File

@@ -1,6 +1,6 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
* Copyright 2017, 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
@@ -16,23 +16,31 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHECKFILESYSTEMJOB_H
#define CHECKFILESYSTEMJOB_H
#ifndef PLASMALNFJOB_H
#define PLASMALNFJOB_H
#include <jobs/PartitionJob.h>
#include <QObject>
#include <QVariantMap>
/**
* Runs a file system check on an existing partition.
*/
class CheckFileSystemJob : public PartitionJob
#include <Job.h>
class PlasmaLnfJob : public Calamares::Job
{
Q_OBJECT
public:
CheckFileSystemJob( Partition* partition );
explicit PlasmaLnfJob( const QString& lnfPath, const QString& id );
virtual ~PlasmaLnfJob() override;
QString prettyName() const override;
QString prettyDescription() const override;
QString prettyStatusMessage() const override;
Calamares::JobResult exec() override;
private:
QString m_lnfPath;
QString m_id;
};
#endif /* CHECKFILESYSTEMJOB_H */
#endif // PLASMALNFJOB_H

View File

@@ -0,0 +1,196 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, 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 "PlasmaLnfPage.h"
#include "ui_page_plasmalnf.h"
#include "utils/Logger.h"
#include "utils/Retranslator.h"
#include <QAbstractButton>
#include <KPackage/Package>
#include <KPackage/PackageLoader>
ThemeInfo::ThemeInfo( const KPluginMetaData& data )
: id( data.pluginId() )
, name( data.name() )
, description( data.description() )
, widget( nullptr )
{
}
static ThemeInfoList plasma_themes()
{
ThemeInfoList packages;
QList<KPluginMetaData> pkgs = KPackage::PackageLoader::self()->listPackages( "Plasma/LookAndFeel" );
for ( const KPluginMetaData& data : pkgs )
{
if ( data.isValid() && !data.isHidden() && !data.name().isEmpty() )
{
packages << ThemeInfo{ data };
}
}
return packages;
}
PlasmaLnfPage::PlasmaLnfPage( QWidget* parent )
: QWidget( parent )
, ui( new Ui::PlasmaLnfPage )
, m_showAll( false )
, m_buttonGroup( nullptr )
{
ui->setupUi( this );
CALAMARES_RETRANSLATE(
{
ui->retranslateUi( this );
ui->generalExplanation->setText( tr(
"Please choose a look-and-feel for the KDE Plasma Desktop. "
"You can also skip this step and configure the look-and-feel "
"once the system is installed. Clicking on a look-and-feel "
"selection will give you a live preview of that look-and-feel.") );
updateThemeNames();
fillUi();
}
)
}
void
PlasmaLnfPage::setLnfPath( const QString& path )
{
m_lnfPath = path;
}
void
PlasmaLnfPage::setEnabledThemes(const ThemeInfoList& themes, bool showAll )
{
m_enabledThemes = themes;
if ( showAll )
{
auto plasmaThemes = plasma_themes();
for ( auto& installed_theme : plasmaThemes )
if ( !m_enabledThemes.findById( installed_theme.id ) )
m_enabledThemes.append( installed_theme );
}
updateThemeNames();
winnowThemes();
fillUi();
}
void
PlasmaLnfPage::setEnabledThemesAll()
{
// Don't need to set showAll=true, because we're already passing in
// the complete list of installed themes.
setEnabledThemes( plasma_themes(), false );
}
void
PlasmaLnfPage::setPreselect( const QString& id )
{
m_preselect = id;
if ( !m_enabledThemes.isEmpty() )
fillUi();
}
void PlasmaLnfPage::updateThemeNames()
{
auto plasmaThemes = plasma_themes();
for ( auto& enabled_theme : m_enabledThemes )
{
ThemeInfo* t = plasmaThemes.findById( enabled_theme.id );
if ( t != nullptr )
{
enabled_theme.name = t->name;
enabled_theme.description = t->description;
}
}
}
void PlasmaLnfPage::winnowThemes()
{
auto plasmaThemes = plasma_themes();
bool winnowed = true;
int winnow_index = 0;
while ( winnowed )
{
winnowed = false;
winnow_index = 0;
for ( auto& enabled_theme : m_enabledThemes )
{
ThemeInfo* t = plasmaThemes.findById( enabled_theme.id );
if ( t == nullptr )
{
cDebug() << "Removing" << enabled_theme.id;
winnowed = true;
break;
}
++winnow_index;
}
if ( winnowed )
{
m_enabledThemes.removeAt( winnow_index );
}
}
}
void PlasmaLnfPage::fillUi()
{
if ( m_enabledThemes.isEmpty() )
{
return;
}
if ( !m_buttonGroup )
{
m_buttonGroup = new QButtonGroup( this );
m_buttonGroup->setExclusive( true );
}
int c = 1; // After the general explanation
for ( auto& theme : m_enabledThemes )
{
if ( !theme.widget )
{
ThemeWidget* w = new ThemeWidget( theme );
m_buttonGroup->addButton( w->button() );
ui->verticalLayout->insertWidget( c, w );
connect( w, &ThemeWidget::themeSelected, this, &PlasmaLnfPage::plasmaThemeSelected);
theme.widget = w;
}
else
{
theme.widget->updateThemeName( theme );
}
if ( theme.id == m_preselect )
{
const QSignalBlocker b( theme.widget->button() );
theme.widget->button()->setChecked( true );
}
++c;
}
}

View File

@@ -0,0 +1,82 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, 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 PLASMALNFPAGE_H
#define PLASMALNFPAGE_H
#include <QButtonGroup>
#include <QList>
#include <QString>
#include <QStringList>
#include <QWidget>
#include "ThemeInfo.h"
#include "ThemeWidget.h"
namespace Ui
{
class PlasmaLnfPage;
}
/** @brief Page for selecting a Plasma Look-and-Feel theme.
*
* You must call setEnabledThemes -- either overload -- once
* to get the selection widgets. Note that calling that with
* an empty list will result in zero (0) selectable themes.
*/
class PlasmaLnfPage : public QWidget
{
Q_OBJECT
public:
explicit PlasmaLnfPage( QWidget* parent = nullptr );
void setLnfPath( const QString& path );
/** @brief enable only the listed themes.
*
* Shows the listed @p themes with full information (e.g. screenshot).
* If @p showAll is true, then also show all installed themes
* not explicitly listed (without a screenshot).
*/
void setEnabledThemes( const ThemeInfoList& themes, bool showAll );
/** @brief enable all installed plasma themes. */
void setEnabledThemesAll();
/** @brief set which theme is to be preselected. */
void setPreselect( const QString& id );
signals:
void plasmaThemeSelected( const QString& id );
private:
/** @brief Intersect the list of enabled themes with the installed ones. */
void winnowThemes();
/** @brief Get the translated names for all enabled themes. */
void updateThemeNames();
/** @brief show enabled themes in the UI. */
void fillUi();
Ui::PlasmaLnfPage* ui;
QString m_lnfPath;
QString m_preselect;
bool m_showAll; // If true, don't winnow according to enabledThemes
ThemeInfoList m_enabledThemes;
QButtonGroup *m_buttonGroup;
QList< ThemeWidget* > m_widgets;
};
#endif //PLASMALNFPAGE_H

View File

@@ -0,0 +1,225 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, 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 "PlasmaLnfViewStep.h"
#include "PlasmaLnfJob.h"
#include "PlasmaLnfPage.h"
#include "ThemeInfo.h"
#include "utils/Logger.h"
#include <QProcess>
#include <QVariantMap>
#ifdef WITH_KCONFIG
#include <KConfigGroup>
#include <KSharedConfig>
#endif
CALAMARES_PLUGIN_FACTORY_DEFINITION( PlasmaLnfViewStepFactory, registerPlugin<PlasmaLnfViewStep>(); )
static QString
currentPlasmaTheme()
{
#ifdef WITH_KCONFIG
KConfigGroup cg( KSharedConfig::openConfig( QStringLiteral( "kdeglobals" ) ), "KDE" );
return cg.readEntry( "LookAndFeelPackage", QString() );
#else
cWarning() << "No KConfig support, cannot determine Plasma theme.";
return QString();
#endif
}
PlasmaLnfViewStep::PlasmaLnfViewStep( QObject* parent )
: Calamares::ViewStep( parent )
, m_widget( new PlasmaLnfPage )
{
connect( m_widget, &PlasmaLnfPage::plasmaThemeSelected, this, &PlasmaLnfViewStep::themeSelected );
emit nextStatusChanged( false );
}
PlasmaLnfViewStep::~PlasmaLnfViewStep()
{
if ( m_widget && m_widget->parent() == nullptr )
m_widget->deleteLater();
}
QString
PlasmaLnfViewStep::prettyName() const
{
return tr( "Look-and-Feel" );
}
QWidget*
PlasmaLnfViewStep::widget()
{
return m_widget;
}
void
PlasmaLnfViewStep::next()
{
emit done();
}
void
PlasmaLnfViewStep::back()
{}
bool
PlasmaLnfViewStep::isNextEnabled() const
{
return true;
}
bool
PlasmaLnfViewStep::isBackEnabled() const
{
return true;
}
bool
PlasmaLnfViewStep::isAtBeginning() const
{
return true;
}
bool
PlasmaLnfViewStep::isAtEnd() const
{
return true;
}
void PlasmaLnfViewStep::onLeave()
{
}
QList<Calamares::job_ptr>
PlasmaLnfViewStep::jobs() const
{
QList<Calamares::job_ptr> l;
cDebug() << "Creating Plasma LNF jobs ..";
if ( !m_themeId.isEmpty() )
{
if ( !m_lnfPath.isEmpty() )
l.append( Calamares::job_ptr( new PlasmaLnfJob( m_lnfPath, m_themeId ) ) );
else
cDebug() << "WARNING: no lnftool given for plasmalnf module.";
}
return l;
}
void
PlasmaLnfViewStep::setConfigurationMap( const QVariantMap& configurationMap )
{
QString lnfPath;
if ( configurationMap.contains( "lnftool" ) && configurationMap.value( "lnftool" ).type() == QVariant::String )
lnfPath = configurationMap.value( "lnftool" ).toString();
m_lnfPath = lnfPath;
m_widget->setLnfPath( m_lnfPath );
if ( m_lnfPath.isEmpty() )
cDebug() << "WARNING: no lnftool given for plasmalnf module.";
QString liveUser;
if ( configurationMap.contains( "liveuser" ) && configurationMap.value( "liveuser" ).type() == QVariant::String )
liveUser = configurationMap.value( "liveuser" ).toString();
m_liveUser = liveUser;
QString preselect;
if ( configurationMap.contains( "preselect" ) && configurationMap.value( "preselect" ).type() == QVariant::String )
preselect = configurationMap.value( "preselect" ).toString();
if ( preselect == QStringLiteral( "*" ) )
preselect = currentPlasmaTheme();
if ( !preselect.isEmpty() )
m_widget->setPreselect( preselect );
bool showAll( false );
if ( configurationMap.contains( "showAll" ) && configurationMap.value( "showAll" ).type() == QVariant::Bool )
showAll = configurationMap.value( "showAll" ).toBool();
if ( configurationMap.contains( "themes" ) &&
configurationMap.value( "themes" ).type() == QVariant::List )
{
ThemeInfoList listedThemes;
auto themeList = configurationMap.value( "themes" ).toList();
// Create the ThemInfo objects for the listed themes; information
// about the themes from Plasma (e.g. human-readable name and description)
// are filled in by update_names() in PlasmaLnfPage.
for ( const auto& i : themeList )
if ( i.type() == QVariant::Map )
{
auto iv = i.toMap();
listedThemes.append( ThemeInfo( iv.value( "theme" ).toString(), iv.value( "image" ).toString() ) );
}
else if ( i.type() == QVariant::String )
listedThemes.append( ThemeInfo( i.toString() ) );
if ( listedThemes.length() == 1 )
cDebug() << "WARNING: only one theme enabled in plasmalnf";
m_widget->setEnabledThemes( listedThemes, showAll );
}
else
m_widget->setEnabledThemesAll(); // All of them
}
void
PlasmaLnfViewStep::themeSelected( const QString& id )
{
m_themeId = id;
if ( m_lnfPath.isEmpty() )
{
cDebug() << "WARNING: no lnftool given for plasmalnf module.";
return;
}
QProcess lnftool;
if ( !m_liveUser.isEmpty() )
lnftool.start( "sudo", {"-E", "-H", "-u", m_liveUser, m_lnfPath, "--resetLayout", "--apply", id} );
else
lnftool.start( m_lnfPath, {"--resetLayout", "--apply", id} );
if ( !lnftool.waitForStarted( 1000 ) )
{
cDebug() << "WARNING: could not start look-and-feel" << m_lnfPath;
return;
}
if ( !lnftool.waitForFinished() )
{
cDebug() << "WARNING:" << m_lnfPath << "timed out.";
return;
}
if ( ( lnftool.exitCode() == 0 ) && ( lnftool.exitStatus() == QProcess::NormalExit ) )
cDebug() << "Plasma look-and-feel applied" << id;
else
cDebug() << "WARNING: could not apply look-and-feel" << id;
}

View File

@@ -0,0 +1,71 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, 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 PLASMALNFVIEWSTEP_H
#define PLASMALNFVIEWSTEP_H
#include <utils/PluginFactory.h>
#include <viewpages/ViewStep.h>
#include <PluginDllMacro.h>
#include <QObject>
#include <QUrl>
#include <QVariantMap>
class PlasmaLnfPage;
class PLUGINDLLEXPORT PlasmaLnfViewStep : public Calamares::ViewStep
{
Q_OBJECT
public:
explicit PlasmaLnfViewStep( QObject* parent = nullptr );
virtual ~PlasmaLnfViewStep() override;
QString prettyName() const override;
QWidget* widget() override;
void next() override;
void back() override;
bool isNextEnabled() const override;
bool isBackEnabled() const override;
bool isAtBeginning() const override;
bool isAtEnd() const override;
void onLeave() override;
QList<Calamares::job_ptr> jobs() const override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
public slots:
void themeSelected( const QString& id );
private:
PlasmaLnfPage* m_widget;
QString m_lnfPath; // Path to the lnf tool
QString m_themeId; // Id of selected theme
QString m_liveUser; // Name of the live user (for OEM mode)
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( PlasmaLnfViewStepFactory )
#endif // PLASMALNFVIEWSTEP_H

View File

@@ -0,0 +1,97 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, 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 PLASMALNF_THEMEINFO_H
#define PLASMALNF_THEMEINFO_H
#include <QList>
#include <QString>
class KPluginMetaData;
class ThemeWidget;
/** @brief describes a single plasma LnF theme.
*
* A theme description has an id, which is really the name of the desktop
* file (e.g. org.kde.breeze.desktop), a name which is human-readable and
* translated, and an optional image Page, which points to a local screenshot
* of that theme.
*/
struct ThemeInfo
{
QString id;
QString name;
QString description;
QString imagePath;
ThemeWidget* widget;
ThemeInfo()
: widget( nullptr )
{}
explicit ThemeInfo( const QString& _id )
: id( _id )
, widget( nullptr )
{
}
explicit ThemeInfo( const QString& _id, const QString& image )
: id( _id )
, imagePath( image )
, widget( nullptr )
{}
// Defined in PlasmaLnfPage.cpp
explicit ThemeInfo( const KPluginMetaData& );
bool isValid() const { return !id.isEmpty(); }
} ;
class ThemeInfoList : public QList< ThemeInfo >
{
public:
/** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */
ThemeInfo* findById( const QString& id )
{
for ( ThemeInfo& i : *this )
{
if ( i.id == id )
return &i;
}
return nullptr;
}
/** @brief Looks for a given @p id in the list of themes, returns nullptr if not found. */
const ThemeInfo* findById( const QString& id ) const
{
for ( const ThemeInfo& i : *this )
{
if ( i.id == id )
return &i;
}
return nullptr;
}
/** @brief Checks if a given @p id is in the list of themes. */
bool contains( const QString& id ) const
{
return findById( id ) != nullptr;
}
} ;
#endif

View File

@@ -0,0 +1,85 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, 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 "ThemeWidget.h"
#include "ThemeInfo.h"
#include "utils/Logger.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QRadioButton>
ThemeWidget::ThemeWidget(const ThemeInfo& info, QWidget* parent)
: QWidget( parent )
, m_check( new QRadioButton( info.name.isEmpty() ? info.id : info.name, parent ) )
, m_description( new QLabel( info.description, parent ) )
, m_id( info.id )
{
QHBoxLayout* layout = new QHBoxLayout( this );
this->setLayout( layout );
layout->addWidget( m_check, 1 );
constexpr QSize image_size{120, 80};
QPixmap image( info.imagePath );
if ( info.imagePath.isEmpty() )
{
// Image can't possibly be valid
image = QPixmap( ":/view-preview.png" );
}
else if ( image.isNull() )
{
// Not found or not specified, so convert the name into some (horrible, likely)
// color instead.
image = QPixmap( image_size );
uint hash_color = qHash( info.imagePath.isEmpty() ? info.id : info.imagePath );
cDebug() << "Theme image" << info.imagePath << "not found, hash" << hash_color;
image.fill( QColor( QRgb( hash_color ) ) );
}
else
image.scaled( image_size );
QLabel* image_label = new QLabel( this );
image_label->setPixmap( image );
layout->addWidget( image_label, 1 );
layout->addWidget( m_description, 3 );
connect( m_check, &QRadioButton::toggled, this, &ThemeWidget::clicked );
}
void
ThemeWidget::clicked( bool checked )
{
if ( checked )
emit themeSelected( m_id );
}
QAbstractButton*
ThemeWidget::button() const
{
return m_check;
}
void ThemeWidget::updateThemeName(const ThemeInfo& info)
{
m_check->setText( info.name );
m_description->setText( info.description );
}

View File

@@ -0,0 +1,53 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, 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 PLASMALNF_THEMEWIDGET_H
#define PLASMALNF_THEMEWIDGET_H
#include <QWidget>
class QAbstractButton;
class QLabel;
class QRadioButton;
struct ThemeInfo;
class ThemeWidget : public QWidget
{
Q_OBJECT
public:
explicit ThemeWidget( const ThemeInfo& info, QWidget* parent = nullptr );
QAbstractButton* button() const;
void updateThemeName( const ThemeInfo& info );
signals:
void themeSelected( const QString& id );
public slots:
void clicked( bool );
private:
QString m_id;
QRadioButton* m_check;
QLabel* m_description;
} ;
#endif

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource>
<file>view-preview.png</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PlasmaLnfPage</class>
<widget class="QWidget" name="PlasmaLnfPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>799</width>
<height>400</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
<item>
<widget class="QLabel" name="generalExplanation">
<property name="text">
<string>Placeholder</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources>
<include location="page_plasmalnf.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,53 @@
---
# Full path to the Plasma look-and-feel tool (CLI program
# for querying and applying Plasma themes). If this is not
# set, no LNF setting will happen.
lnftool: "/usr/bin/lookandfeeltool"
# For systems where the user Calamares runs as (usually root,
# via either sudo or pkexec) has a clean environment, set this
# to the originating username; the lnftool will be run through
# "sudo -H -u <liveuser>" instead of directly.
#
# liveuser: "live"
# You can limit the list of Plasma look-and-feel themes by listing ids
# here. If this key is not present, all of the installed themes are listed.
# If the key is present, only installed themes that are **also** included
# in the list are shown (could be none!). See the *showAll* key, below,
# to change that.
#
# Themes may be listed by id, (e.g. fluffy-bunny, below) or as a theme
# and an image (e.g. breeze) which will be used to show a screenshot.
# Themes with no image get a "missing screenshot" image; if the
# image file is not found, they get a color swatch based on the image name.
themes:
- org.kde.fuzzy-pig.desktop
- theme: org.kde.breeze.desktop
image: "breeze.png"
- theme: org.kde.breezedark.desktop
image: "breeze-dark.png"
- org.kde.fluffy-bunny.desktop
# If *showAll* is true, then all installed themes are shown in the
# UI for selection, even if they are not listed in *themes*. This
# allows selection of all themes even while not all of them are
# listed in *themes* -- which is useful to show screenshots for those
# you do have a screenshot for.
showAll: false
# You can pre-select one of the themes; it is not applied
# immediately, but its radio-button is switched on to indicate
# that that is the theme (that is most likely) currently in use.
# Do this only on Live images where you are reasonably sure
# that the user is not going to change the theme out from under
# themselves before running the installer.
#
# If this key is present, its value should be the id of the theme
# which should be pre-selected. If absent, empty, or the pre-selected
# theme is not found on the live system, no theme will be pre-selected.
#
# As a special setting, use "*", to try to find the currently-
# selected theme by reading the Plasma configuration. This requires
# KF5::Config at build- and run-time.
preselect: "*"

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

View File

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#4d4d4d;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="m4 4v24h24v-24zm1 1h22v22h-22zm6 2a4 4 0 0 0 -4 4 4 4 0 0 0 4 4 4 4 0 0 0 4 -4 4 4 0 0 0 -4 -4m0 1a3 3 0 0 1 3 3 3 3 0 0 1 -3 3 3 3 0 0 1 -3 -3 3 3 0 0 1 3 -3m9.5 6.793l-5 5-2-2-6.5 6.5.707.707 5.793-5.793 2 2 5-5 3.793 3.793.707-.707z"
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 570 B

View File

@@ -1,6 +1,5 @@
find_package(ECM 5.10.0 NO_MODULE)
find_package(ECM ${ECM_VERSION} NO_MODULE)
if( ECM_FOUND )
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${CMAKE_MODULE_PATH})
include( ECMAddTests )
endif()

View File

@@ -213,12 +213,16 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
bool ok = false;
m_requiredStorageGB = configurationMap.value( "requiredStorage" ).toDouble( &ok );
if ( !ok )
{
cDebug() << "WARNING: RequirementsChecker entry 'requiredStorage' is invalid.";
m_requiredStorageGB = 3.;
}
Calamares::JobQueue::instance()->globalStorage()->insert( "requiredStorageGB", m_requiredStorageGB );
}
else
{
cDebug() << "WARNING: RequirementsChecker entry 'requiredStorage' is missing.";
m_requiredStorageGB = 3.;
incompleteConfiguration = true;
}
@@ -231,12 +235,14 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
m_requiredRamGB = configurationMap.value( "requiredRam" ).toDouble( &ok );
if ( !ok )
{
cDebug() << "WARNING: RequirementsChecker entry 'requiredRam' is invalid.";
m_requiredRamGB = 1.;
incompleteConfiguration = true;
}
}
else
{
cDebug() << "WARNING: RequirementsChecker entry 'requiredRam' is missing.";
m_requiredRamGB = 1.;
incompleteConfiguration = true;
}
@@ -248,7 +254,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
if ( m_checkHasInternetUrl.isEmpty() ||
!QUrl( m_checkHasInternetUrl ).isValid() )
{
cDebug() << "Invalid internetCheckUrl in welcome.conf" << m_checkHasInternetUrl
cDebug() << "WARNING: RequirementsChecker entry 'internetCheckUrl' is invalid in welcome.conf" << m_checkHasInternetUrl
<< "reverting to default (http://example.com).";
m_checkHasInternetUrl = "http://example.com";
incompleteConfiguration = true;
@@ -256,8 +262,9 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
}
else
{
cDebug() << "internetCheckUrl is undefined in welcome.conf, "
cDebug() << "WARNING: RequirementsChecker entry 'internetCheckUrl' is undefined in welcome.conf,"
"reverting to default (http://example.com).";
m_checkHasInternetUrl = "http://example.com";
incompleteConfiguration = true;
}
@@ -269,7 +276,10 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
m_entriesToCheck.append( configurationMap.value( "check" ).toStringList() );
}
else
{
cDebug() << "WARNING: RequirementsChecker entry 'check' is incomplete.";
incompleteConfiguration = true;
}
if ( configurationMap.contains( "required" ) &&
configurationMap.value( "required" ).type() == QVariant::List )
@@ -278,18 +288,13 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
m_entriesToRequire.append( configurationMap.value( "required" ).toStringList() );
}
else
{
cDebug() << "WARNING: RequirementsChecker entry 'required' is incomplete.";
incompleteConfiguration = true;
}
if ( incompleteConfiguration )
{
cDebug() << "WARNING: The RequirementsChecker configuration map provided by "
"the welcome module configuration file is incomplete or "
"incorrect.\n"
"Startup will continue for debugging purposes, but one or "
"more checks might not function correctly.\n"
"RequirementsChecker configuration map:\n"
<< configurationMap;
}
cDebug() << "WARNING: RequirementsChecker configuration map:\n" << configurationMap;
}

View File

@@ -25,6 +25,6 @@ requirements:
# If any of these conditions are not met, the user cannot
# continue past the welcome page.
required:
- storage
# - storage
- ram
- root
# - root