diff --git a/3rdparty/kdsingleapplicationguard/kdsingleapplicationguard.cpp b/3rdparty/kdsingleapplicationguard/kdsingleapplicationguard.cpp index 4c13e1da0..cd8fadcce 100644 --- a/3rdparty/kdsingleapplicationguard/kdsingleapplicationguard.cpp +++ b/3rdparty/kdsingleapplicationguard/kdsingleapplicationguard.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -764,7 +765,7 @@ void KDSingleApplicationGuard::Private::create( const QStringList & arguments ) } const int maxWaitMSecs = 1000 * 60; // stop waiting after 60 seconds - QTime waitTimer; + QElapsedTimer waitTimer; waitTimer.start(); // lets wait till the other instance initialized the register diff --git a/CHANGES b/CHANGES index d6f5de059..2bf44c8a9 100644 --- a/CHANGES +++ b/CHANGES @@ -6,14 +6,28 @@ website will have to do for older versions. # 3.2.25 (unreleased) # This release contains contributions from (alphabetically by first name): - - No external contributors yet + - Anke Boersma + - FLVAL + - Gaël PORTAY ## Core ## - - No core changes yet + - The slideshow in `branding.desc` can be configured with QML (recommended, + as it has been for the past umpteen releases) or with a list of + images (new). + - It is possible to turn off all the new QML code -- navigation, slideshow, + QML-based modules -- with a single `-DWITH_QML=OFF` at CMake time. + This removes QML from Calamares' dependency footprint (but only saves + 200kB in Calamares itself). + - Tests have been extended and now support a tests/CMakeTests.txt file + for fine-tuning tests for Python modules. ## Modules ## - - No module changes yet - + - The QML based *welcomeq* module is now a viable alternative to the + *welcome*(widgets based) module. Using QML files means it no longer + is needed to have pop-up windows for additional information or warnings, + all loads in the Calamares window itself. Additional features include the + option to customize the *About* info and load files like Release Notes + direct into Calamares, QML files added to the branding directory can be used. # 3.2.24 (2020-05-11) # diff --git a/CMakeLists.txt b/CMakeLists.txt index 62cf971c4..b5095de09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,11 +50,14 @@ set( CALAMARES_VERSION_RC 0 ) # Set to 0 during release cycle, 1 during develop option( INSTALL_CONFIG "Install configuration files" OFF ) option( INSTALL_POLKIT "Install Polkit configuration" ON ) option( INSTALL_COMPLETION "Install shell completions" OFF ) -option( BUILD_TESTING "Build the testing tree." 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 ) +# Options for the calamares executable option( WITH_KF5Crash "Enable crash reporting with KCrash." ON ) option( WITH_KF5DBus "Use DBus service for unique-application." OFF ) +# When adding WITH_* that affects the ABI offered by libcalamares, +# also update libcalamares/CalamaresConfig.h.in +option( WITH_PYTHON "Enable Python modules API (requires Boost.Python)." ON ) +option( WITH_PYTHONQT "Enable Python view modules API (deprecated, requires PythonQt)." OFF ) +option( WITH_QML "Enable QML UI options." ON ) # Possible debugging flags are: # - DEBUG_TIMEZONES draws latitude and longitude lines on the timezone @@ -159,6 +162,7 @@ if(NOT CMAKE_VERSION VERSION_LESS "3.10.0") ) endif() +include( CTest ) ### C++ SETUP # @@ -250,7 +254,10 @@ include( CMakeColors ) ### DEPENDENCIES # -find_package( Qt5 ${QT_VERSION} CONFIG REQUIRED Concurrent Core Gui Widgets LinguistTools Svg Quick QuickWidgets ) +find_package( Qt5 ${QT_VERSION} CONFIG REQUIRED Concurrent Core Gui LinguistTools Network Svg Widgets ) +if( WITH_QML ) + find_package( Qt5 ${QT_VERSION} CONFIG REQUIRED Quick QuickWidgets ) +endif() if( Qt5_VERSION VERSION_GREATER 5.12.1 ) # At least Qt 5.12.2 seems to support Esperanto in QLocale if( "eo" IN_LIST _tx_incomplete ) @@ -312,10 +319,6 @@ if( NOT KF5DBusAddons_FOUND ) set( WITH_KF5DBus OFF ) endif() -if( BUILD_TESTING ) - enable_testing() -endif () - find_package( PythonLibs ${PYTHONLIBS_VERSION} ) set_package_properties( PythonLibs PROPERTIES @@ -496,7 +499,11 @@ if ( CALAMARES_VERSION_RC EQUAL 0 ) endif() # enforce using constBegin, constEnd for const-iterators -add_definitions( "-DQT_STRICT_ITERATORS" ) +add_definitions( + -DQT_STRICT_ITERATORS + -DQT_SHARED + -DQT_SHAREDPOINTER_TRACK_POINTERS +) # set paths set( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" ) diff --git a/CMakeModules/CalamaresAddModuleSubdirectory.cmake b/CMakeModules/CalamaresAddModuleSubdirectory.cmake index 1af520ca8..981ec4a01 100644 --- a/CMakeModules/CalamaresAddModuleSubdirectory.cmake +++ b/CMakeModules/CalamaresAddModuleSubdirectory.cmake @@ -126,10 +126,10 @@ function( calamares_add_module_subdirectory ) endif() message( "" ) # We copy over the lang directory, if any - if( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/lang" ) + if( IS_DIRECTORY "${_mod_dir}/lang" ) install_calamares_gettext_translations( ${SUBDIRECTORY} - SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/lang" + SOURCE_DIR "${_mod_dir}/lang" FILENAME ${SUBDIRECTORY}.mo RENAME calamares-${SUBDIRECTORY}.mo ) @@ -162,6 +162,16 @@ function( calamares_add_module_subdirectory ) # may try to do things to the running system. Needs work to make that a # safe thing to do. # + # If the module has a tests/ subdirectory with *.global and *.job + # files (YAML files holding global and job-configurations for + # testing purposes) then those files are used to drive additional + # tests. The files must be numbered (starting from 1) for this to work; + # 1.global and 1.job together make the configuration for test 1. + # + # If the module has a tests/CMakeLists.txt while it doesn't have its + # own CMakeLists.txt (e.g. a Python module), then the subdirectory + # for tests/ is added on its own. + # if ( BUILD_TESTING AND _mod_enabled AND _mod_testing ) add_test( NAME load-${SUBDIRECTORY} @@ -170,7 +180,7 @@ function( calamares_add_module_subdirectory ) ) # Try it with the tests/ configurations shipped with the module set( _count 1 ) - set( _testdir ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/tests ) + set( _testdir ${_mod_dir}/tests ) while ( EXISTS "${_testdir}/${_count}.global" OR EXISTS "${_testdir}/${_count}.job" ) set( _dash_g "" ) set( _dash_j "" ) @@ -187,5 +197,8 @@ function( calamares_add_module_subdirectory ) ) math( EXPR _count "${_count} + 1" ) endwhile() + if ( EXISTS ${_testdir}/CMakeTests.txt AND NOT EXISTS ${_mod_dir}/CMakeLists.txt ) + include( ${_testdir}/CMakeTests.txt ) + endif() endif() endfunction() diff --git a/lang/calamares_fa.ts b/lang/calamares_fa.ts index 0375254d3..a4de510ad 100644 --- a/lang/calamares_fa.ts +++ b/lang/calamares_fa.ts @@ -6,17 +6,17 @@ The <strong>boot environment</strong> of this system.<br><br>Older x86 systems only support <strong>BIOS</strong>.<br>Modern systems usually use <strong>EFI</strong>, but may also show up as BIOS if started in compatibility mode. - + <strong>محیط بوت</strong> این سیستم. <br><br>سیستم‌های قدیمی x86 فقط از <strong>بایوس</strong> پشتیبانی می‌کنند. <br>سیستم‌های مدرن معمولا از <strong>ای.اف.آی</strong> استفاده می‌کنند، اما ممکن است در صورتی که در حالت سازگاری اجرا شوند همچنان به صورت بایوس نشان داده شوند This system was started with an <strong>EFI</strong> boot environment.<br><br>To configure startup from an EFI environment, this installer must deploy a boot loader application, like <strong>GRUB</strong> or <strong>systemd-boot</strong> on an <strong>EFI System Partition</strong>. This is automatic, unless you choose manual partitioning, in which case you must choose it or create it on your own. - + سیستم با محیط بوت <strong>ای.اف.آی</strong> آغاز شد. <br><br>به منظور پیکربندی راه‌اندازی از یک محیط ای.اف.آی، این نصاب باید حتما‌ یک برنامه بالاآورنده بوت، مانند <strong>گراب</strong> یا <strong>سیستم‌بوت</strong> را روی یک پارتیشن سیستم ای.اف.آی مستقر نماید. این به صورت خودکار است مگر اینکه شما پارتیشن‌بندی دستی را انتخاب کنید که در این صورت باید خودتان انتخاب کنید یا به صورت دستی ایجاد کنید. This system was started with a <strong>BIOS</strong> boot environment.<br><br>To configure startup from a BIOS environment, this installer must install a boot loader, like <strong>GRUB</strong>, either at the beginning of a partition or on the <strong>Master Boot Record</strong> near the beginning of the partition table (preferred). This is automatic, unless you choose manual partitioning, in which case you must set it up on your own. - + سیستم با محیط بوت <strong>بایوس</strong> آغاز شد. <br><br>به منظور پیکربندی راه‌انداری از یک محیط بایوس، این نصاب باید حتما‌ یک برنامه بالاآورنده بوت، مانند <strong>گراب</strong> را یا در شروع یک پارتیشن و یا روی <strong>رکورد راه‌انداز اصلی</strong> نزدیک شروع جدول پارتیشن (ترجیحا) نصب کند. این به صورت خودکار است مگر اینکه شما پارتیشن‌بندی دستی را انتخاب کنید که در این صورت باید خودتان به صورت دستی آن را راه‌اندازی کنید. @@ -24,27 +24,27 @@ Master Boot Record of %1 - + رکورد راه انداز اصلی یا همان ام.بی.آر ٪1 Boot Partition - + پارتیشن بوت System Partition - + پارتیشن سیستمی Do not install a boot loader - + بوت لودر نصب نکن. %1 (%2) - + %1 (%2) @@ -52,7 +52,7 @@ Blank Page - + صفحه خالی @@ -60,58 +60,58 @@ Form - + فرم GlobalStorage - + ذخیره‌سازی همگانی JobQueue - + صف کارها Modules - + ماژول‌ها Type: - + نوع: none - + هیچ Interface: - + رابط: Tools - + ابزارها Reload Stylesheet - + بارگزاری مجدد برگه‌شیوه Widget Tree - + درخت ابزارک‌ها Debug information - + اطلاعات رفع اشکال @@ -119,12 +119,12 @@ Set up - + راه‌اندازی Install - + نصب @@ -132,12 +132,12 @@ Job failed (%1) - + کار شکست خورد. (%1) Programmed job failure was explicitly requested. - + عدم موفقیت کار برنامه ریزی شده به صورت صریح درخواست شد @@ -145,7 +145,7 @@ Done - + انجام شد. @@ -153,7 +153,7 @@ Example job (%1) - + کار نمونه (%1) @@ -161,17 +161,17 @@ Run command '%1' in target system. - + دستور '%1' را در سیستم هدف اجرا کنید Run command '%1'. - + دستور '%1' را اجرا کنید Running command %1 %2 - + اجرای دستور %1 %2 @@ -179,32 +179,32 @@ Running %1 operation. - + اجرا عملیات %1 Bad working directory path - + مسیر شاخه جاری نامناسب Working directory %1 for python job %2 is not readable. - + شاخه جاری %1 برای کار پایتونی %2 خواندنی نیست Bad main script file - + اسکریپت اصلی مشکل‌دار Main script file %1 for python job %2 is not readable. - + فایل اسکریپت اصلی %1 برای کار پایتون %2 قابل خواندن نیست. Boost.Python error in job "%1". - + Boost.Python error in job "%1". @@ -212,17 +212,17 @@ Loading ... - + در حال بارگذاری ... QML Step <i>%1</i>. - + مرحله QML <i>%1</i>. Loading failed. - + بارگذاری شکست خورد. @@ -230,9 +230,9 @@ Waiting for %n module(s). - - - + + منتظر ماندن برای n% ماژول + منتظر ماندن برای n% ماژول (ها). @@ -246,7 +246,7 @@ System-requirements checking is complete. - + چک کردن نیازمندی‌های سیستم تمام شد. @@ -254,171 +254,173 @@ Setup Failed - + راه‌اندازی شکست خورد. Installation Failed - + نصب شکست خورد. Would you like to paste the install log to the web? - + آیا مایلید که گزارش‌ها در وب الصاق شوند؟ Error - + خطا &Yes - + &بله &No - + &خیر &Close - + &بسته Install Log Paste URL - + Install Log Paste URL The upload was unsuccessful. No web-paste was done. - + The upload was unsuccessful. No web-paste was done. Calamares Initialization Failed - + راه اندازی کالاماریس شکست خورد. %1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution. - + %1 نمی‌تواند نصب شود. کالاماریس نمی‌تواند همه ماژول‌های پیکربندی را بالا بیاورد. این یک مشکل در نحوه استفاده کالاماریس توسط توزیع است. <br/>The following modules could not be loaded: - + <br/>این ماژول نمی‌تواند بالا بیاید: Continue with setup? - + راه اندازی ادامه یابد؟ Continue with installation? - + نصب ادامه یابد؟ The %1 setup program is about to make changes to your disk in order to set up %2.<br/><strong>You will not be able to undo these changes.</strong> - + برنامه نصب %1 در شرف ایجاد تغییرات در دیسک شما به منظور راه‌اندازی %2 است. <br/><strong>شما قادر نخواهید بود تا این تغییرات را برگردانید.</strong> The %1 installer is about to make changes to your disk in order to install %2.<br/><strong>You will not be able to undo these changes.</strong> - + نصاب %1 در شرف ایجاد تغییرات در دیسک شما به منظور نصب %2 است. <br/><strong>شما قادر نخواهید بود تا این تغییرات را برگردانید.</strong> &Set up now - + &همین حالا راه‌انداری کنید &Install now - + &همین حالا نصب کنید Go &back - + برگردید به &عقب &Set up - + &راه‌اندازی &Install - + &نصب Setup is complete. Close the setup program. - + نصب انجام شد. برنامه نصب را ببندید. The installation is complete. Close the installer. - + نصب انجام شد. نصاب را ببندید. Cancel setup without changing the system. - + لغو راه‌اندازی بدون تغییر سیستم. Cancel installation without changing the system. - + لغو نصب بدون تغییر کردن سیستم. &Next - + &بعدی &Back - + &قبلی &Done - + &انجام شد &Cancel - + &لغو Cancel setup? - + لغو راه‌اندازی؟ Cancel installation? - + لغو نصب؟ Do you really want to cancel the current setup process? The setup program will quit and all changes will be lost. - + آیا واقعا می‌خواهید روند راه‌اندازی فعلی رو لغو کنید؟ +برنامه راه اندازی ترک می شود و همه تغییرات از بین می روند. Do you really want to cancel the current install process? The installer will quit and all changes will be lost. - + آیا واقعاً می خواهید روند نصب فعلی را لغو کنید؟ +نصاب ترک می شود و همه تغییرات از بین می روند. @@ -426,22 +428,22 @@ The installer will quit and all changes will be lost. Unknown exception type - + نوع ناشناخته استثنا unparseable Python error - + unparseable Python error unparseable Python traceback - + unparseable Python traceback Unfetchable Python error. - + Unfetchable Python error. @@ -450,7 +452,8 @@ The installer will quit and all changes will be lost. Install log posted to: %1 - + نصب رخدادهای ارسال شده به: +%1 @@ -458,32 +461,32 @@ The installer will quit and all changes will be lost. Show debug information - + نمایش اطلاعات دیباگ &Back - + &قبلی &Next - + &بعدی &Cancel - + &لغو %1 Setup Program - + %1 برنامه راه‌اندازی %1 Installer - + %1 نصاب @@ -491,7 +494,7 @@ The installer will quit and all changes will be lost. Gathering system information... - + جمع‌آوری اطلاعات سیستم... @@ -499,12 +502,12 @@ The installer will quit and all changes will be lost. Form - + فرم Select storage de&vice: - + انتخاب &دستگاه ذخیره‌سازی: @@ -512,62 +515,62 @@ The installer will quit and all changes will be lost. Current: - + فعلی: After: - + بعد از: <strong>Manual partitioning</strong><br/>You can create or resize partitions yourself. Having a GPT partition table and <strong>fat32 512Mb /boot partition is a must for UEFI installs</strong>, either use an existing without formatting or create one. - + <strong>پارتیشن‌بندی دستی</strong><br/>شما می‌توانید خودتان پارتیشن‌ها را بسازید و یا تغییر سایز دهید. با داشتن یک جدول پارتیشن GPT و <strong>پارتیشن /boot با اندازه 512 مگابیتی fat32 برای نصب‌های UEFI الزامی است</strong>، چه با استفاده از نمونه موجود آن بدون قالب‌بندی یا ساخت آن. Reuse %1 as home partition for %2. - + استفاده مجدد از %1 به عنوان پارتیشن خانه برای %2. <strong>Select a partition to shrink, then drag the bottom bar to resize</strong> - + <strong>انتخاب یک پارتیشن برای کوجک کردن و ایجاد پارتیشن جدید از آن، سپس نوار دکمه را بکشید تا تغییر اندازه دهد</strong> %1 will be shrunk to %2MiB and a new %3MiB partition will be created for %4. - + %1 تغییر سایز خواهد داد به %2 مبی‌بایت و یک پارتیشن %3 مبی‌بایتی برای %4 ساخته خواهد شد. Boot loader location: - + مکان بالاآورنده بوت: <strong>Select a partition to install on</strong> - + <strong>یک پارتیشن را برای نصب بر روی آن، انتخاب کنید</strong> An EFI system partition cannot be found anywhere on this system. Please go back and use manual partitioning to set up %1. - + پارتیشن سیستم ای.اف.آی نمی‌تواند در هیچ جایی از این سیستم یافت شود. لطفا برگردید و از پارتیشن بندی دستی استفاده کنید تا %1 را راه‌اندازی کنید. The EFI system partition at %1 will be used for starting %2. - + پارتیشن سیستم ای.اف.آی در %1 برای شروع %2 استفاده خواهد شد. EFI system partition: - + پارتیشن سیستم ای.اف.آی This storage device does not seem to have an operating system on it. What would you like to do?<br/>You will be able to review and confirm your choices before any change is made to the storage device. - + به نظر می‌رسد در دستگاه ذخیره‌سازی هیچ سیستم‌عاملی وجود ندارد. تمایل به انجام چه کاری دارید؟<br/>شما می‌توانید انتخاب‌هایتان را قبل از اعمال هر تغییری در دستگاه ذخیره‌سازی، مرور و تأیید نمایید. @@ -575,7 +578,7 @@ The installer will quit and all changes will be lost. <strong>Erase disk</strong><br/>This will <font color="red">delete</font> all data currently present on the selected storage device. - + <strong>پاک کردن دیسک</strong><br/>این کار تمام داده‌های موجود بر روی دستگاه ذخیره‌سازی انتخاب شده را <font color="red">حذف می‌کند</font>. @@ -583,7 +586,7 @@ The installer will quit and all changes will be lost. <strong>Install alongside</strong><br/>The installer will shrink a partition to make room for %1. - + <strong>نصب در امتداد</strong><br/>این نصاب از یک پارتیشن برای ساخت یک اتاق برای %1 استفاده می‌کند. @@ -611,7 +614,7 @@ The installer will quit and all changes will be lost. No Swap - + بدون Swap @@ -1097,13 +1100,13 @@ The installer will quit and all changes will be lost. %1 - %2 (%3) device[name] - size[number] (device-node[name]) - + %1 - %2 (%3) %1 - (%2) device[name] - (device-node[name]) - + %1 - (%2) @@ -1111,7 +1114,7 @@ The installer will quit and all changes will be lost. Write LUKS configuration for Dracut to %1 - + Write LUKS configuration for Dracut to %1 @@ -1195,7 +1198,7 @@ The installer will quit and all changes will be lost. Form - + فرم @@ -1261,7 +1264,7 @@ The installer will quit and all changes will be lost. Form - + فرم @@ -1543,7 +1546,7 @@ The installer will quit and all changes will be lost. &Cancel - + &لغو @@ -1556,7 +1559,7 @@ The installer will quit and all changes will be lost. Form - + فرم @@ -2157,7 +2160,7 @@ The installer will quit and all changes will be lost. Form - + فرم @@ -2198,7 +2201,7 @@ The installer will quit and all changes will be lost. Name - + نام @@ -2211,7 +2214,7 @@ The installer will quit and all changes will be lost. Form - + فرم @@ -2229,7 +2232,7 @@ The installer will quit and all changes will be lost. Form - + فرم @@ -2326,43 +2329,43 @@ The installer will quit and all changes will be lost. Root - + ریشه Home - + خانه Boot - + بوت EFI system - + سیستم ای.اف.آی Swap - + Swap New partition for %1 - + پارتیشن جدید برای %1 New partition - + پارتیشن جدید %1 %2 size[number] filesystem[name] - + %1 %2 @@ -2371,23 +2374,23 @@ The installer will quit and all changes will be lost. Free Space - + فضای خالی New partition - + پارتیشن جدید Name - + نام File System - + سیستم فایل @@ -2405,7 +2408,7 @@ The installer will quit and all changes will be lost. Form - + فرم @@ -2483,32 +2486,32 @@ The installer will quit and all changes will be lost. Gathering system information... - + جمع‌آوری اطلاعات سیستم... Partitions - + پارتیشن‌ها Install %1 <strong>alongside</strong> another operating system. - + نصب %1 <strong>در امتداد</strong> سیستم عامل دیگر. <strong>Erase</strong> disk and install %1. - + <strong>پاک کردن</strong> دیسک و نصب %1. <strong>Replace</strong> a partition with %1. - + <strong>جایگزینی</strong> یک پارتیشن و با %1 <strong>Manual</strong> partitioning. - + <strong>پارتیشن‌بندی</strong> دستی. @@ -2538,12 +2541,12 @@ The installer will quit and all changes will be lost. Current: - + فعلی: After: - + بعد از: @@ -2578,7 +2581,7 @@ The installer will quit and all changes will be lost. Boot partition not encrypted - + پارتیشن بوت رمزشده نیست @@ -2593,7 +2596,7 @@ The installer will quit and all changes will be lost. There are no partitions to install on. - + هیچ پارتیشنی برای نصب وجود ندارد @@ -2615,7 +2618,7 @@ The installer will quit and all changes will be lost. Form - + فرم @@ -2667,7 +2670,7 @@ There was no output from the command. Output: - + خروجی @@ -2725,7 +2728,7 @@ Output: %1 (%2) - + %1 (%2) @@ -2834,7 +2837,7 @@ Output: Form - + فرم @@ -2896,12 +2899,12 @@ Output: The EFI system partition at %1 will be used for starting %2. - + پارتیشن سیستم ای.اف.آی در %1 برای شروع %2 استفاده خواهد شد. EFI system partition: - + پارتیشن سیستم ای.اف.آی @@ -3396,7 +3399,7 @@ Output: Form - + فرم @@ -3569,7 +3572,7 @@ Output: Form - + فرم diff --git a/lang/calamares_zh_CN.ts b/lang/calamares_zh_CN.ts index 44fcb8272..7467aa120 100644 --- a/lang/calamares_zh_CN.ts +++ b/lang/calamares_zh_CN.ts @@ -2558,12 +2558,12 @@ The installer will quit and all changes will be lost. An EFI system partition is necessary to start %1.<br/><br/>To configure an EFI system partition, go back and select or create a FAT32 filesystem with the <strong>%3</strong> flag enabled and mount point <strong>%2</strong>.<br/><br/>You can continue without setting up an EFI system partition but your system may fail to start. - + 必须有 EFI 系统分区才能启动 %1 。<br/><br/>要配置 EFI 系统分区,后退一步,然后创建或选中一个 FAT32 分区并为之设置 <strong>%3</strong> 标记及挂载点 <strong>%2</strong>。<br/><br/>你可以不创建 EFI 系统分区并继续安装,但是你的系统可能无法启动。 An EFI system partition is necessary to start %1.<br/><br/>A partition was configured with mount point <strong>%2</strong> but its <strong>%3</strong> flag is not set.<br/>To set the flag, go back and edit the partition.<br/><br/>You can continue without setting the flag but your system may fail to start. - + 必须有 EFI 系统分区才能启动 %1 。<br/><br/>已有挂载点为 <strong>%2</strong> 的分区,但是未设置 <strong>%3</strong> 标记。<br/>要设置此标记,后退并编辑分区。<br/><br/>你可以不创建 EFI 系统分区并继续安装,但是你的系统可能无法启动。 @@ -3804,7 +3804,28 @@ Output: </ul> <p>The vertical scrollbar is adjustable, current width set to 10.</p> - + <h3>%1</h3> + <p>这是一个QML 示例文件,显示了具有 Flickable 内容的 RichText 选项。</p> + + <p>带有 RichText 的 QML 可以使用 HTML 标签, + Flickable 内容对于触摸屏很有用。</p> + + <p><b>这是粗体字</b></p> + <p><i>这是斜体字</i></p> + <p><u>这是带下划线的文字</u></p> + <p><center>此文本将居中对齐。</center></p> + <p><s>这是删除线</s></p> + + <p>代码示例: + <code>ls -l /home</code></p> + + <p><b>列表:</b></p> + <ul> + <li>Intel CPU 系统</li> + <li>AMD CPU 系统</li> + </ul> + + <p>垂直滚动条是可调的,当前宽度设置为10。</p> @@ -3818,7 +3839,8 @@ Output: <h3>Welcome to the %1 <quote>%2</quote> installer</h3> <p>This program will ask you some questions and set up %1 on your computer.</p> - + <h3>欢迎来到 %1 <quote>%2</quote> 安装程序</h3> + <p>这个程序将询问您一些问题并在您的计算机上安装 %1。</p> diff --git a/lang/python/fi_FI/LC_MESSAGES/python.mo b/lang/python/fi_FI/LC_MESSAGES/python.mo index 6ed36a933..9f9791235 100644 Binary files a/lang/python/fi_FI/LC_MESSAGES/python.mo and b/lang/python/fi_FI/LC_MESSAGES/python.mo differ diff --git a/lang/python/fi_FI/LC_MESSAGES/python.po b/lang/python/fi_FI/LC_MESSAGES/python.po index 3aa0f8db2..c05931e77 100644 --- a/lang/python/fi_FI/LC_MESSAGES/python.po +++ b/lang/python/fi_FI/LC_MESSAGES/python.po @@ -24,7 +24,7 @@ msgstr "" #: src/modules/packages/main.py:59 src/modules/packages/main.py:68 #: src/modules/packages/main.py:78 msgid "Install packages." -msgstr "Asenna paketteja." +msgstr "Asenna paketit." #: src/modules/packages/main.py:66 #, python-format @@ -108,7 +108,7 @@ msgstr "Kuvan purkaminen epäonnistui \"{}\"" #: src/modules/unpackfs/main.py:399 msgid "No mount point for root partition" -msgstr "Ei liitoskohtaa juuri root-osiolle" +msgstr "Ei liitoskohtaa juuri root osiolle" #: src/modules/unpackfs/main.py:400 msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing" diff --git a/src/branding/default/branding.desc b/src/branding/default/branding.desc index 2e6a02bba..f8cc88295 100644 --- a/src/branding/default/branding.desc +++ b/src/branding/default/branding.desc @@ -141,8 +141,23 @@ images: # The slideshow is displayed during execution steps (e.g. when the # installer is actually writing to disk and doing other slow things). +# +# The slideshow can be a QML file (recommended) which can display +# arbitrary things -- text, images, animations, or even play a game -- +# during the execution step. The QML **is** abruptly stopped when the +# execution step is done, though, so maybe a game isn't a great idea. +# +# The slideshow can also be a sequence of images (not recommended unless +# you don't want QML at all in your Calamares). The images are displayed +# at a rate of 1 every 2 seconds during the execution step. +# +# To configure a QML file, list a single filename: +# slideshow: "show.qml" +# To configure images, like the filenames (here, as an inline list): +# slideshow: [ "/etc/calamares/slideshow/0.png", "/etc/logo.png" ] slideshow: "show.qml" -# There are two available APIs for the slideshow: + +# There are two available APIs for a QML slideshow: # - 1 (the default) loads the entire slideshow when the installation- # slideshow page is shown and starts the QML then. The QML # is never stopped (after installation is done, times etc. @@ -151,6 +166,8 @@ slideshow: "show.qml" # onLeave() in the root object. After the installation is done, # the show is stopped (first by calling onLeave(), then destroying # the QML components). +# +# An image slideshow does not need to have the API defined. slideshowAPI: 2 diff --git a/src/calamares/CMakeLists.txt b/src/calamares/CMakeLists.txt index 5c5a68a97..b632567b8 100644 --- a/src/calamares/CMakeLists.txt +++ b/src/calamares/CMakeLists.txt @@ -10,6 +10,20 @@ set( calamaresSources progresstree/ProgressTreeView.cpp ) +if( NOT WITH_KF5DBus ) + set( kdsagSources "" ) + foreach( _s + kdsingleapplicationguard/kdsingleapplicationguard.cpp + kdsingleapplicationguard/kdsharedmemorylocker.cpp + kdsingleapplicationguard/kdtoolsglobal.cpp + kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp + ) + list( APPEND kdsagSources ${CMAKE_SOURCE_DIR}/3rdparty/${_s} ) + endforeach() + mark_thirdparty_code( ${kdsagSources} ) + list( APPEND calamaresSources ${kdsagSources} ) +endif() + include_directories( ${CMAKE_SOURCE_DIR}/src/libcalamares ${CMAKE_SOURCE_DIR}/src/libcalamaresui diff --git a/src/calamares/CalamaresWindow.cpp b/src/calamares/CalamaresWindow.cpp index 06a31a0e9..2ab7cd5fa 100644 --- a/src/calamares/CalamaresWindow.cpp +++ b/src/calamares/CalamaresWindow.cpp @@ -22,6 +22,7 @@ #include "CalamaresWindow.h" #include "Branding.h" +#include "CalamaresConfig.h" #include "DebugWindow.h" #include "Settings.h" #include "ViewManager.h" @@ -38,8 +39,10 @@ #include #include #include +#ifdef WITH_QML #include #include +#endif #include static inline int @@ -132,18 +135,6 @@ CalamaresWindow::getWidgetSidebar( QWidget* parent, int desiredWidth ) return sideBox; } -QWidget* -CalamaresWindow::getQmlSidebar( QWidget* parent, int ) -{ - CalamaresUtils::registerCalamaresModels(); - QQuickWidget* w = new QQuickWidget( parent ); - w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); - w->setResizeMode( QQuickWidget::SizeRootObjectToView ); - w->setSource( QUrl( - CalamaresUtils::searchQmlFile( CalamaresUtils::QmlSearch::Both, QStringLiteral( "calamares-sidebar" ) ) ) ); - return w; -} - /** @brief Get a button-sized icon. */ static inline QPixmap getButtonIcon( const QString& name ) @@ -213,6 +204,19 @@ CalamaresWindow::getWidgetNavigation( QWidget* parent ) return navigation; } +#ifdef WITH_QML +QWidget* +CalamaresWindow::getQmlSidebar( QWidget* parent, int ) +{ + CalamaresUtils::registerCalamaresModels(); + QQuickWidget* w = new QQuickWidget( parent ); + w->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + w->setResizeMode( QQuickWidget::SizeRootObjectToView ); + w->setSource( QUrl( + CalamaresUtils::searchQmlFile( CalamaresUtils::QmlSearch::Both, QStringLiteral( "calamares-sidebar" ) ) ) ); + return w; +} + QWidget* CalamaresWindow::getQmlNavigation( QWidget* parent ) { @@ -231,6 +235,19 @@ CalamaresWindow::getQmlNavigation( QWidget* parent ) return w; } +#else +// Bogus to keep the linker happy +QWidget * CalamaresWindow::getQmlSidebar(QWidget* , int ) +{ + return nullptr; +} +QWidget * CalamaresWindow::getQmlNavigation(QWidget* ) +{ + return nullptr; +} + + +#endif /**@brief Picks one of two methods to call * @@ -243,16 +260,21 @@ flavoredWidget( Calamares::Branding::PanelFlavor flavor, CalamaresWindow* w, QWidget* parent, widgetMaker widget, - widgetMaker qml, + widgetMaker qml, // Only if WITH_QML is on args... a ) { +#ifndef WITH_QML + Q_UNUSED( qml ) +#endif // Member-function calling syntax is (object.*member)(args) switch ( flavor ) { case Calamares::Branding::PanelFlavor::Widget: return ( w->*widget )( parent, a... ); +#ifdef WITH_QML case Calamares::Branding::PanelFlavor::Qml: return ( w->*qml )( parent, a... ); +#endif case Calamares::Branding::PanelFlavor::None: return nullptr; } diff --git a/src/calamares/testmain.cpp b/src/calamares/testmain.cpp index cd06c5d03..f353fa6d5 100644 --- a/src/calamares/testmain.cpp +++ b/src/calamares/testmain.cpp @@ -252,6 +252,12 @@ main( int argc, char* argv[] ) cDebug() << " .. got" << m->name() << m->typeString() << m->interfaceString(); if ( m->type() == Calamares::Module::Type::View ) { + if ( !qobject_cast< QApplication* >(aw) ) + { + auto* replace_app = new QApplication( argc, argv ); + replace_app->setQuitOnLastWindowClosed( true ); + aw = replace_app; + } mw = module.m_ui ? new QMainWindow() : nullptr; (void)new Calamares::Branding( module.m_branding ); diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index dd6f01fb1..fa4265d6e 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -1,12 +1,8 @@ # libcalamares is the non-GUI part of Calamares, which includes handling # translations, configurations, logging, utilities, global storage, and (non-GUI) jobs. -add_definitions( - ${QT_DEFINITIONS} - -DQT_SHARED - -DQT_SHAREDPOINTER_TRACK_POINTERS - -DDLLEXPORT_PRO -) +add_definitions( -DDLLEXPORT_PRO ) +include_directories( ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/CalamaresConfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/CalamaresConfig.h ) @@ -65,22 +61,6 @@ set( libSources utils/Variant.cpp utils/Yaml.cpp ) -set( _kdsagSources - kdsingleapplicationguard/kdsingleapplicationguard.cpp - kdsingleapplicationguard/kdsharedmemorylocker.cpp - kdsingleapplicationguard/kdtoolsglobal.cpp - kdsingleapplicationguard/kdlockedsharedmemorypointer.cpp -) -set( kdsagSources "" ) -foreach( _s ${_kdsagSources} ) - list( APPEND kdsagSources ${CMAKE_SOURCE_DIR}/3rdparty/${_s} ) -endforeach() -mark_thirdparty_code( ${kdsagSources} ) - -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} -) ### OPTIONAL Python support # @@ -156,7 +136,7 @@ endif() ### LIBRARY # # -add_library( calamares SHARED ${libSources} ${kdsagSources} ) +add_library( calamares SHARED ${libSources} ) set_target_properties( calamares PROPERTIES VERSION ${CALAMARES_VERSION_SHORT} diff --git a/src/libcalamares/CalamaresConfig.h.in b/src/libcalamares/CalamaresConfig.h.in index 55468cf15..b31de95b5 100644 --- a/src/libcalamares/CalamaresConfig.h.in +++ b/src/libcalamares/CalamaresConfig.h.in @@ -11,5 +11,6 @@ //cmakedefines for CMake variables (e.g. for optdepends) go here #cmakedefine WITH_PYTHON #cmakedefine WITH_PYTHONQT +#cmakedefine WITH_QML #endif // CALAMARESCONFIG_H diff --git a/src/libcalamares/DllMacro.h b/src/libcalamares/DllMacro.h index 712bf5732..528a70c2d 100644 --- a/src/libcalamares/DllMacro.h +++ b/src/libcalamares/DllMacro.h @@ -20,7 +20,7 @@ #ifndef DLLMACRO_H #define DLLMACRO_H -#include +#include /* * Mark symbols exported from Calamares non-GUI library with DLLEXPORT. diff --git a/src/libcalamares/PythonJobApi.h b/src/libcalamares/PythonJobApi.h index 6fb27cd62..f91572b3d 100644 --- a/src/libcalamares/PythonJobApi.h +++ b/src/libcalamares/PythonJobApi.h @@ -20,10 +20,10 @@ #ifndef PYTHONJOBAPI_H #define PYTHONJOBAPI_H -#include "qglobal.h" // For qreal - #include "utils/BoostPython.h" +#include // For qreal + namespace Calamares { class PythonJob; diff --git a/src/libcalamaresui/Branding.cpp b/src/libcalamaresui/Branding.cpp index ae8f3910f..a5909fd61 100644 --- a/src/libcalamaresui/Branding.cpp +++ b/src/libcalamaresui/Branding.cpp @@ -41,6 +41,13 @@ #include #endif +[[noreturn]] static void +bail( const QString& descriptorPath, const QString& message ) +{ + cError() << "FATAL in" << descriptorPath << Logger::Continuation << Logger::NoQuote {} << message; + ::exit( EXIT_FAILURE ); +} + namespace Calamares { @@ -153,7 +160,7 @@ Branding::Branding( const QString& brandingFilePath, QObject* parent ) QDir componentDir( componentDirectory() ); if ( !componentDir.exists() ) { - bail( "Bad component directory path." ); + bail( m_descriptorPath, "Bad component directory path." ); } QFile file( brandingFilePath ); @@ -168,10 +175,12 @@ Branding::Branding( const QString& brandingFilePath, QObject* parent ) m_componentName = QString::fromStdString( doc[ "componentName" ].as< std::string >() ); if ( m_componentName != componentDir.dirName() ) - bail( "The branding component name should match the name of the " + bail( m_descriptorPath, + "The branding component name should match the name of the " "component directory." ); initSimpleSettings( doc ); + initSlideshowSettings( doc ); #ifdef WITH_KOSRelease // Copy the os-release information into a QHash for use by KMacroExpander. @@ -194,17 +203,15 @@ Branding::Branding( const QString& brandingFilePath, QObject* parent ) { QStringLiteral( "VARIANT" ), relInfo.variant() }, { QStringLiteral( "VARIANT_ID" ), relInfo.variantId() }, { QStringLiteral( "LOGO" ), relInfo.logo() } } }; - auto expand = [ & ]( const QString& s ) -> QString { + auto expand = [&]( const QString& s ) -> QString { return KMacroExpander::expandMacros( s, relMap, QLatin1Char( '@' ) ); }; #else auto expand = []( const QString& s ) -> QString { return s; }; #endif - - // Massage the strings, images and style sections. loadStrings( m_strings, doc, "strings", expand ); - loadStrings( m_images, doc, "images", [ & ]( const QString& s ) -> QString { + loadStrings( m_images, doc, "images", [&]( const QString& s ) -> QString { // See also image() const QString imageName( expand( s ) ); QFileInfo imageFi( componentDir.absoluteFilePath( imageName ) ); @@ -214,58 +221,19 @@ Branding::Branding( const QString& brandingFilePath, QObject* parent ) // Not found, bail out with the filename used if ( icon.isNull() ) { - bail( QString( "Image file %1 does not exist." ).arg( imageFi.absoluteFilePath() ) ); + bail( m_descriptorPath, + QString( "Image file %1 does not exist." ).arg( imageFi.absoluteFilePath() ) ); } return imageName; // Not turned into a path } return imageFi.absoluteFilePath(); } ); loadStrings( m_style, doc, "style", []( const QString& s ) -> QString { return s; } ); - - if ( doc[ "slideshow" ].IsSequence() ) - { - QStringList slideShowPictures; - doc[ "slideshow" ] >> slideShowPictures; - for ( int i = 0; i < slideShowPictures.count(); ++i ) - { - QString pathString = slideShowPictures[ i ]; - QFileInfo imageFi( componentDir.absoluteFilePath( pathString ) ); - if ( !imageFi.exists() ) - { - bail( QString( "Slideshow file %1 does not exist." ).arg( imageFi.absoluteFilePath() ) ); - } - - slideShowPictures[ i ] = imageFi.absoluteFilePath(); - } - - //FIXME: implement a GenericSlideShow.qml that uses these slideShowPictures - } - else if ( doc[ "slideshow" ].IsScalar() ) - { - QString slideshowPath = QString::fromStdString( doc[ "slideshow" ].as< std::string >() ); - QFileInfo slideshowFi( componentDir.absoluteFilePath( slideshowPath ) ); - if ( !slideshowFi.exists() || !slideshowFi.fileName().toLower().endsWith( ".qml" ) ) - bail( QString( "Slideshow file %1 does not exist or is not a valid QML file." ) - .arg( slideshowFi.absoluteFilePath() ) ); - m_slideshowPath = slideshowFi.absoluteFilePath(); - } - else - { - bail( "Syntax error in slideshow sequence." ); - } - - int api = doc[ "slideshowAPI" ].IsScalar() ? doc[ "slideshowAPI" ].as< int >() : -1; - if ( ( api < 1 ) || ( api > 2 ) ) - { - cWarning() << "Invalid or missing *slideshowAPI* in branding file."; - api = 1; - } - m_slideshowAPI = api; } catch ( YAML::Exception& e ) { CalamaresUtils::explainYamlException( e, ba, file.fileName() ); - bail( e.what() ); + bail( m_descriptorPath, e.what() ); } QDir translationsDir( componentDir.filePath( "lang" ) ); @@ -423,8 +391,11 @@ flavorAndSide( const YAML::Node& doc, const char* key, Branding::PanelFlavor& fl static const NamedEnumTable< PanelFlavor > sidebarFlavorNames { { QStringLiteral( "widget" ), PanelFlavor::Widget }, { QStringLiteral( "none" ), PanelFlavor::None }, - { QStringLiteral( "hidden" ), PanelFlavor::None }, + { QStringLiteral( "hidden" ), PanelFlavor::None } +#ifdef WITH_QML + , { QStringLiteral( "qml" ), PanelFlavor::Qml } +#endif }; static const NamedEnumTable< PanelSide > panelSideNames { { QStringLiteral( "left" ), PanelSide::Left }, @@ -540,12 +511,62 @@ Branding::initSimpleSettings( const YAML::Node& doc ) } } - -[[noreturn]] void -Branding::bail( const QString& message ) +void +Branding::initSlideshowSettings( const YAML::Node& doc ) { - cError() << "FATAL in" << m_descriptorPath << Logger::Continuation << Logger::NoQuote {} << message; - ::exit( EXIT_FAILURE ); + QDir componentDir( componentDirectory() ); + + if ( doc[ "slideshow" ].IsSequence() ) + { + QStringList slideShowPictures; + doc[ "slideshow" ] >> slideShowPictures; + for ( int i = 0; i < slideShowPictures.count(); ++i ) + { + QString pathString = slideShowPictures[ i ]; + QFileInfo imageFi( componentDir.absoluteFilePath( pathString ) ); + if ( !imageFi.exists() ) + { + bail( m_descriptorPath, + QString( "Slideshow file %1 does not exist." ).arg( imageFi.absoluteFilePath() ) ); + } + + slideShowPictures[ i ] = imageFi.absoluteFilePath(); + } + + m_slideshowFilenames = slideShowPictures; + m_slideshowAPI = -1; + } +#ifdef WITH_QML + else if ( doc[ "slideshow" ].IsScalar() ) + { + QString slideshowPath = QString::fromStdString( doc[ "slideshow" ].as< std::string >() ); + QFileInfo slideshowFi( componentDir.absoluteFilePath( slideshowPath ) ); + if ( !slideshowFi.exists() || !slideshowFi.fileName().toLower().endsWith( ".qml" ) ) + bail( m_descriptorPath, + QString( "Slideshow file %1 does not exist or is not a valid QML file." ) + .arg( slideshowFi.absoluteFilePath() ) ); + m_slideshowPath = slideshowFi.absoluteFilePath(); + + // API choice is relevant for QML slideshow + int api = doc[ "slideshowAPI" ].IsScalar() ? doc[ "slideshowAPI" ].as< int >() : -1; + if ( ( api < 1 ) || ( api > 2 ) ) + { + cWarning() << "Invalid or missing *slideshowAPI* in branding file."; + api = 1; + } + m_slideshowAPI = api; + } +#else + else if ( doc[ "slideshow" ].IsScalar() ) + { + cWarning() << "Invalid *slideshow* setting, must be list of images."; + } +#endif + else + { + bail( m_descriptorPath, "Syntax error in slideshow sequence." ); + } } + } // namespace Calamares diff --git a/src/libcalamaresui/Branding.h b/src/libcalamaresui/Branding.h index ce694a644..e84e23680 100644 --- a/src/libcalamaresui/Branding.h +++ b/src/libcalamaresui/Branding.h @@ -22,8 +22,8 @@ #ifndef BRANDING_H #define BRANDING_H +#include "CalamaresConfig.h" #include "DllMacro.h" - #include "utils/NamedSuffix.h" #include @@ -131,8 +131,11 @@ public: enum class PanelFlavor { None, - Widget, + Widget +#ifdef WITH_QML + , Qml +#endif }; Q_ENUM( PanelFlavor ) ///@brief Where to place a panel (sidebar, navigation) @@ -165,8 +168,16 @@ public: */ QString translationsDirectory() const { return m_translationsPathPrefix; } - /** @brief Path to the slideshow QML file, if any. */ + /** @brief Path to the slideshow QML file, if any. (API == 1 or 2)*/ QString slideshowPath() const { return m_slideshowPath; } + /// @brief List of pathnames of slideshow images, if any. (API == -1) + QStringList slideshowImages() const { return m_slideshowFilenames; } + /** @brief Which slideshow API to use for the slideshow? + * + * - 2 For QML-based slideshows loaded asynchronously (current) + * - 1 For QML-based slideshows, loaded when shown (legacy) + * - -1 For oldschool image-slideshows. + */ int slideshowAPI() const { return m_slideshowAPI; } QPixmap image( Branding::ImageEntry imageEntry, const QSize& size ) const; @@ -230,19 +241,29 @@ private: static const QStringList s_imageEntryStrings; static const QStringList s_styleEntryStrings; - [[noreturn]] void bail( const QString& message ); - QString m_descriptorPath; // Path to descriptor (e.g. "/etc/calamares/default/branding.desc") QString m_componentName; // Matches last part of full path to containing directory QMap< QString, QString > m_strings; QMap< QString, QString > m_images; QMap< QString, QString > m_style; + + /* The slideshow can be done in one of two ways: + * - as a sequence of images + * - as a QML file + * The slideshow: setting selects which one is used. If it is + * a list (of filenames) then it is a sequence of images, and otherwise + * it is a QML file which is run. (For QML, the slideshow API is + * important). + */ + QStringList m_slideshowFilenames; QString m_slideshowPath; int m_slideshowAPI; QString m_translationsPathPrefix; /** @brief Initialize the simple settings below */ void initSimpleSettings( const YAML::Node& doc ); + ///@brief Initialize the slideshow settings, above + void initSlideshowSettings( const YAML::Node& doc ); bool m_welcomeStyleCalamares; bool m_welcomeExpandingLogo; diff --git a/src/libcalamaresui/CMakeLists.txt b/src/libcalamaresui/CMakeLists.txt index e813b0009..32fec2cb1 100644 --- a/src/libcalamaresui/CMakeLists.txt +++ b/src/libcalamaresui/CMakeLists.txt @@ -14,15 +14,15 @@ set( calamaresui_SOURCES utils/CalamaresUtilsGui.cpp utils/ImageRegistry.cpp utils/Paste.cpp - utils/Qml.cpp viewpages/BlankViewStep.cpp viewpages/ExecutionViewStep.cpp - viewpages/QmlViewStep.cpp + viewpages/Slideshow.cpp viewpages/ViewStep.cpp widgets/ClickableLabel.cpp widgets/FixedAspectRatioLabel.cpp + widgets/PrettyRadioButton.cpp widgets/WaitingWidget.cpp ${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp @@ -44,10 +44,6 @@ if( WITH_PYTHON ) endif() if( WITH_PYTHONQT ) - include_directories(${PYTHON_INCLUDE_DIRS}) - # *_DIRS because we also use extensions - include_directories(${PYTHONQT_INCLUDE_DIRS}) - list( APPEND calamaresui_SOURCES modulesystem/PythonQtViewModule.cpp utils/PythonQtUtils.cpp @@ -56,25 +52,33 @@ if( WITH_PYTHONQT ) viewpages/PythonQtGlobalStorageWrapper.cpp viewpages/PythonQtUtilsWrapper.cpp ) - set( OPTIONAL_PYTHON_LIBRARIES - ${PYTHON_LIBRARIES} - ${PYTHONQT_LIBRARIES} +endif() + +if( WITH_QML ) + list( APPEND calamaresui_SOURCES + utils/Qml.cpp + viewpages/QmlViewStep.cpp ) endif() calamares_add_library( calamaresui SOURCES ${calamaresui_SOURCES} EXPORT_MACRO UIDLLEXPORT_PRO - LINK_PRIVATE_LIBRARIES - ${OPTIONAL_PYTHON_LIBRARIES} LINK_LIBRARIES Qt5::Svg - Qt5::QuickWidgets RESOURCES libcalamaresui.qrc EXPORT CalamaresLibraryDepends VERSION ${CALAMARES_VERSION_SHORT} ) -if ( KF5CoreAddons_FOUND AND KF5CoreAddons_VERSION VERSION_GREATER_EQUAL 5.58 ) +if( KF5CoreAddons_FOUND AND KF5CoreAddons_VERSION VERSION_GREATER_EQUAL 5.58 ) target_compile_definitions( calamaresui PRIVATE WITH_KOSRelease ) endif() +if( WITH_PYTHONQT ) + # *_DIRS because we also use extensions + target_include_directories( calamaresui PRIVATE ${PYTHON_INCLUDE_DIRS} ${PYTHONQT_INCLUDE_DIRS} ) + target_link_libraries( calamaresui PRIVATE ${PYTHON_LIBRARIES} ${PYTHONQT_LIBRARIES} ) +endif() +if( WITH_QML ) + target_link_libraries( calamaresui PUBLIC Qt5::QuickWidgets ) +endif() diff --git a/src/libcalamaresui/viewpages/ExecutionViewStep.cpp b/src/libcalamaresui/viewpages/ExecutionViewStep.cpp index c9bc4b8c3..2dd4b79df 100644 --- a/src/libcalamaresui/viewpages/ExecutionViewStep.cpp +++ b/src/libcalamaresui/viewpages/ExecutionViewStep.cpp @@ -20,12 +20,14 @@ #include "ExecutionViewStep.h" +#include "Slideshow.h" + #include "Branding.h" +#include "CalamaresConfig.h" #include "Job.h" #include "JobQueue.h" #include "Settings.h" #include "ViewManager.h" - #include "modulesystem/Module.h" #include "modulesystem/ModuleManager.h" #include "utils/CalamaresUtilsGui.h" @@ -37,12 +39,28 @@ #include #include #include -#include -#include -#include -#include #include +static Calamares::Slideshow* +makeSlideshow( QWidget* parent ) +{ + const int api = Calamares::Branding::instance()->slideshowAPI(); + switch ( api ) + { + case -1: + return new Calamares::SlideshowPictures( parent ); +#ifdef WITH_QML + case 1: + FALLTHRU; + case 2: + return new Calamares::SlideshowQML( parent ); +#endif + default: + cWarning() << "Unknown Branding slideshow API" << api; + return new Calamares::SlideshowPictures( parent ); + } +} + namespace Calamares { @@ -51,20 +69,14 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent ) , m_widget( new QWidget ) , m_progressBar( new QProgressBar ) , m_label( new QLabel ) - , m_qmlShow( new QQuickWidget ) - , m_qmlComponent( nullptr ) - , m_qmlObject( nullptr ) + , m_slideshow( makeSlideshow( m_widget ) ) { QVBoxLayout* layout = new QVBoxLayout( m_widget ); QVBoxLayout* innerLayout = new QVBoxLayout; m_progressBar->setMaximum( 10000 ); - m_qmlShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); - m_qmlShow->setResizeMode( QQuickWidget::SizeRootObjectToView ); - m_qmlShow->engine()->addImportPath( CalamaresUtils::qmlModulesDir().absolutePath() ); - - layout->addWidget( m_qmlShow ); + layout->addWidget( m_slideshow->widget() ); CalamaresUtils::unmarginLayout( layout ); layout->addLayout( innerLayout ); @@ -72,17 +84,7 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent ) innerLayout->addWidget( m_progressBar ); innerLayout->addWidget( m_label ); - cDebug() << "QML import paths:" << Logger::DebugList( m_qmlShow->engine()->importPathList() ); - if ( Branding::instance()->slideshowAPI() == 2 ) - { - cDebug() << "QML load on startup, API 2."; - loadQmlV2(); - } - connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue ); -#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 ) - CALAMARES_RETRANSLATE( m_qmlShow->engine()->retranslate(); ) -#endif } @@ -139,108 +141,10 @@ ExecutionViewStep::isAtEnd() const return !JobQueue::instance()->isRunning(); } -void -ExecutionViewStep::loadQmlV2() -{ - if ( !m_qmlComponent && !Calamares::Branding::instance()->slideshowPath().isEmpty() ) - { - m_qmlComponent = new QQmlComponent( m_qmlShow->engine(), - QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ), - QQmlComponent::CompilationMode::Asynchronous ); - connect( m_qmlComponent, &QQmlComponent::statusChanged, this, &ExecutionViewStep::loadQmlV2Complete ); - } -} - -/// @brief State-change of the slideshow, for changeSlideShowState() -enum class Slideshow -{ - Start, - Stop -}; - -/** @brief Tells the slideshow we activated or left the show. - * - * If @p state is @c Slideshow::Start, calls suitable activation procedures. - * If @p state is @c Slideshow::Stop, calls deactivation procedures. - * - * Applies V1 and V2 QML activation / deactivation: - * - V1 loads the QML in @p widget on activation. Sets root object property - * *activatedInCalamares* as appropriate. - * - V2 calls onActivate() or onLeave() in the QML as appropriate. Also - * sets the *activatedInCalamares* property. - */ -static void -changeSlideShowState( Slideshow state, QQuickItem* slideshow, QQuickWidget* widget ) -{ - bool activate = state == Slideshow::Start; - - if ( Branding::instance()->slideshowAPI() == 2 ) - { - // The QML was already loaded in the constructor, need to start it - CalamaresUtils::callQMLFunction( slideshow, activate ? "onActivate" : "onLeave" ); - } - else if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() ) - { - // API version 1 assumes onCompleted is the trigger - if ( activate ) - { - widget->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ) ); - } - // needs the root object for property setting, below - slideshow = widget->rootObject(); - } - - // V1 API has picked up the root object for use, V2 passed it in. - if ( slideshow ) - { - static const char propertyName[] = "activatedInCalamares"; - auto property = slideshow->property( propertyName ); - if ( property.isValid() && ( property.type() == QVariant::Bool ) && ( property.toBool() != activate ) ) - { - slideshow->setProperty( propertyName, activate ); - } - } -} - -void -ExecutionViewStep::loadQmlV2Complete() -{ - if ( m_qmlComponent && m_qmlComponent->isReady() && !m_qmlObject ) - { - cDebug() << "QML component complete, API 2"; - // Don't do this again - disconnect( m_qmlComponent, &QQmlComponent::statusChanged, this, &ExecutionViewStep::loadQmlV2Complete ); - - QObject* o = m_qmlComponent->create(); - m_qmlObject = qobject_cast< QQuickItem* >( o ); - if ( !m_qmlObject ) - { - delete o; - } - else - { - cDebug() << Logger::SubEntry << "Loading" << Calamares::Branding::instance()->slideshowPath(); - - // setContent() is public API, but not documented publicly. - // It is marked \internal in the Qt sources, but does exactly - // what is needed: sets up visual parent by replacing the root - // item, and handling resizes. - m_qmlShow->setContent( - QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ), m_qmlComponent, m_qmlObject ); - if ( ViewManager::instance()->currentStep() == this ) - { - // We're alreay visible! Must have been slow QML loading, and we - // passed onActivate already. - changeSlideShowState( Slideshow::Start, m_qmlObject, m_qmlShow ); - } - } - } -} - void ExecutionViewStep::onActivate() { - changeSlideShowState( Slideshow::Start, m_qmlObject, m_qmlShow ); + m_slideshow->changeSlideShowState( Slideshow::Start ); JobQueue* queue = JobQueue::instance(); foreach ( const QString& instanceKey, m_jobInstanceKeys ) @@ -288,13 +192,7 @@ ExecutionViewStep::updateFromJobQueue( qreal percent, const QString& message ) void ExecutionViewStep::onLeave() { - changeSlideShowState( Slideshow::Stop, m_qmlObject, m_qmlShow ); - // API version 2 is explicitly stopped; version 1 keeps running - if ( Branding::instance()->slideshowAPI() == 2 ) - { - delete m_qmlObject; - m_qmlObject = nullptr; - } + m_slideshow->changeSlideShowState( Slideshow::Stop ); } } // namespace Calamares diff --git a/src/libcalamaresui/viewpages/ExecutionViewStep.h b/src/libcalamaresui/viewpages/ExecutionViewStep.h index e797c3cb2..48604fe93 100644 --- a/src/libcalamaresui/viewpages/ExecutionViewStep.h +++ b/src/libcalamaresui/viewpages/ExecutionViewStep.h @@ -27,13 +27,12 @@ class QLabel; class QObject; class QProgressBar; -class QQmlComponent; -class QQuickItem; -class QQuickWidget; namespace Calamares { +class Slideshow; + class ExecutionViewStep : public ViewStep { Q_OBJECT @@ -60,20 +59,14 @@ public: void appendJobModuleInstanceKey( const QString& instanceKey ); -public slots: - void loadQmlV2Complete(); - private: QWidget* m_widget; QProgressBar* m_progressBar; QLabel* m_label; - QQuickWidget* m_qmlShow; - QQmlComponent* m_qmlComponent; - QQuickItem* m_qmlObject; ///< The actual show + Slideshow* m_slideshow; QStringList m_jobInstanceKeys; - void loadQmlV2(); ///< Loads the slideshow QML (from branding) for API version 2 void updateFromJobQueue( qreal percent, const QString& message ); }; diff --git a/src/libcalamaresui/viewpages/Slideshow.cpp b/src/libcalamaresui/viewpages/Slideshow.cpp new file mode 100644 index 000000000..85551f797 --- /dev/null +++ b/src/libcalamaresui/viewpages/Slideshow.cpp @@ -0,0 +1,262 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Aurélien Gâteau + * Copyright 2014-2015, Teo Mrnjavac + * Copyright 2018, Adriaan de Groot + * + * 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 . + */ + +#include "Slideshow.h" + +#include "Branding.h" +#include "utils/Dirs.h" +#include "utils/Logger.h" +#include "utils/Qml.h" +#include "utils/Retranslator.h" + +#include +#include +#ifdef WITH_QML +#include +#include +#include +#include +#endif +#include + +#include + +namespace Calamares +{ + +Slideshow::~Slideshow() {} + +#ifdef WITH_QML +SlideshowQML::SlideshowQML( QWidget* parent ) + : Slideshow( parent ) + , m_qmlShow( new QQuickWidget ) + , m_qmlComponent( nullptr ) + , m_qmlObject( nullptr ) +{ + m_qmlShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + m_qmlShow->setResizeMode( QQuickWidget::SizeRootObjectToView ); + m_qmlShow->engine()->addImportPath( CalamaresUtils::qmlModulesDir().absolutePath() ); + + cDebug() << "QML import paths:" << Logger::DebugList( m_qmlShow->engine()->importPathList() ); +#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 ) + CALAMARES_RETRANSLATE( if ( m_qmlShow ) { m_qmlShow->engine()->retranslate(); } ) +#endif + + if ( Branding::instance()->slideshowAPI() == 2 ) + { + cDebug() << "QML load on startup, API 2."; + loadQmlV2(); + } +} + +SlideshowQML::~SlideshowQML() +{ + delete m_qmlObject; + delete m_qmlComponent; + delete m_qmlShow; +} + +QWidget* +SlideshowQML::widget() +{ + return m_qmlShow; +} + +void +SlideshowQML::loadQmlV2() +{ + QMutexLocker l( &m_mutex ); + if ( !m_qmlComponent && !Calamares::Branding::instance()->slideshowPath().isEmpty() ) + { + m_qmlComponent = new QQmlComponent( m_qmlShow->engine(), + QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ), + QQmlComponent::CompilationMode::Asynchronous ); + connect( m_qmlComponent, &QQmlComponent::statusChanged, this, &SlideshowQML::loadQmlV2Complete ); + } +} + +void +SlideshowQML::loadQmlV2Complete() +{ + QMutexLocker l( &m_mutex ); + if ( m_qmlComponent && m_qmlComponent->isReady() && !m_qmlObject ) + { + cDebug() << "QML component complete, API 2"; + // Don't do this again + disconnect( m_qmlComponent, &QQmlComponent::statusChanged, this, &SlideshowQML::loadQmlV2Complete ); + + QObject* o = m_qmlComponent->create(); + m_qmlObject = qobject_cast< QQuickItem* >( o ); + if ( !m_qmlObject ) + { + delete o; + } + else + { + cDebug() << Logger::SubEntry << "Loading" << Calamares::Branding::instance()->slideshowPath(); + + // setContent() is public API, but not documented publicly. + // It is marked \internal in the Qt sources, but does exactly + // what is needed: sets up visual parent by replacing the root + // item, and handling resizes. + m_qmlShow->setContent( + QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ), m_qmlComponent, m_qmlObject ); + if ( isActive() ) + { + // We're alreay visible! Must have been slow QML loading, and we + // passed onActivate already. + changeSlideShowState( Slideshow::Start ); + } + } + } +} + +/* + * Applies V1 and V2 QML activation / deactivation: + * - V1 loads the QML in @p widget on activation. Sets root object property + * *activatedInCalamares* as appropriate. + * - V2 calls onActivate() or onLeave() in the QML as appropriate. Also + * sets the *activatedInCalamares* property. + */ +void +SlideshowQML::changeSlideShowState( Action state ) +{ + QMutexLocker l( &m_mutex ); + bool activate = state == Slideshow::Start; + + if ( Branding::instance()->slideshowAPI() == 2 ) + { + // The QML was already loaded in the constructor, need to start it + CalamaresUtils::callQMLFunction( m_qmlObject, activate ? "onActivate" : "onLeave" ); + } + else if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() ) + { + // API version 1 assumes onCompleted is the trigger + if ( activate ) + { + m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ) ); + } + // needs the root object for property setting, below + m_qmlObject = m_qmlShow->rootObject(); + } + + // V1 API has picked up the root object for use, V2 passed it in. + if ( m_qmlObject ) + { + static const char propertyName[] = "activatedInCalamares"; + auto property = m_qmlObject->property( propertyName ); + if ( property.isValid() && ( property.type() == QVariant::Bool ) && ( property.toBool() != activate ) ) + { + m_qmlObject->setProperty( propertyName, activate ); + } + } + + if ( ( Branding::instance()->slideshowAPI() == 2 ) && ( state == Slideshow::Stop ) ) + { + delete m_qmlObject; + m_qmlObject = nullptr; + } + + m_state = state; +} +#endif + +SlideshowPictures::SlideshowPictures( QWidget* parent ) + : Slideshow( parent ) + , m_label( new QLabel( parent ) ) + , m_timer( new QTimer( this ) ) + , m_imageIndex( 0 ) + , m_images( Branding::instance()->slideshowImages() ) +{ + m_label->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + m_label->setAlignment( Qt::AlignCenter ); + m_timer->setInterval( std::chrono::milliseconds( 2000 ) ); + connect( m_timer, &QTimer::timeout, this, &SlideshowPictures::next ); +} + +SlideshowPictures::~SlideshowPictures() +{ + delete m_timer; + delete m_label; +} + +QWidget* +SlideshowPictures::widget() +{ + return m_label; +} + +void +SlideshowPictures::changeSlideShowState( Calamares::Slideshow::Action a ) +{ + QMutexLocker l( &m_mutex ); + m_state = a; + if ( a == Slideshow::Start ) + { + m_imageIndex = -1; + if ( m_images.count() < 1 ) + { + m_label->setPixmap( QPixmap( ":/data/images/squid.svg" ) ); + } + else + { + + m_timer->start(); + QTimer::singleShot( 0, this, &SlideshowPictures::next ); + } + } + else + { + m_timer->stop(); + } +} + +void +SlideshowPictures::next() +{ + QMutexLocker l( &m_mutex ); + + if ( m_imageIndex < 0 ) + { + // Initialization, don't do the advance-by-one + m_imageIndex = 0; + } + else + { + m_imageIndex++; + if ( m_imageIndex >= m_images.count() ) + { + m_imageIndex = 0; + } + } + + if ( m_imageIndex >= m_images.count() ) + { + // Unusual case: timer is running, but we have 0 images to display. + // .. this would have been caught in changeSlideShowState(), which + // .. special-cases 0 images. + return; + } + + m_label->setPixmap( QPixmap( m_images.at( m_imageIndex ) ) ); +} + + +} // namespace Calamares diff --git a/src/libcalamaresui/viewpages/Slideshow.h b/src/libcalamaresui/viewpages/Slideshow.h new file mode 100644 index 000000000..f338d44e2 --- /dev/null +++ b/src/libcalamaresui/viewpages/Slideshow.h @@ -0,0 +1,148 @@ +/* === This file is part of Calamares - === + * + * Copyright 2014, Aurélien Gâteau + * Copyright 2014-2015, Teo Mrnjavac + * Copyright 2018, Adriaan de Groot + * + * 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 . + */ + +#ifndef LIBCALAMARESUI_SLIDESHOW_H +#define LIBCALAMARESUI_SLIDESHOW_H + +#include "CalamaresConfig.h" + +#include +#include +#include + +class QLabel; +class QTimer; +#ifdef WITH_QML +class QQmlComponent; +class QQuickItem; +class QQuickWidget; +#endif + +namespace Calamares +{ + +/** @brief API for Slideshow objects + * + * A Slideshow (subclass) object is created by the ExecutionViewStep + * and needs to manage its own configuration (e.g. from Branding). + * The slideshow is started and stopped when it becomes visible + * and when installation is over, by calling changeSlideShowState() + * as appropriate. + */ +class Slideshow : public QObject +{ + Q_OBJECT +public: + /// @brief State-change of the slideshow, for changeSlideShowState() + enum Action + { + Start, + Stop + }; + + Slideshow( QWidget* parent = nullptr ) + : QObject( parent ) + { + } + virtual ~Slideshow(); + + /// @brief Is the slideshow being shown **right now**? + bool isActive() const { return m_state == Start; } + + /** @brief The actual widget to show the user. + * + * Depending on the style of slideshow, this might be a QQuickWidget, + * or a QLabel, or something else entirely. + */ + virtual QWidget* widget() = 0; + + /** @brief Tells the slideshow we activated or left the show. + * + * If @p state is @c Slideshow::Start, calls suitable activation procedures. + * If @p state is @c Slideshow::Stop, calls deactivation procedures. + */ + virtual void changeSlideShowState( Action a ) = 0; + +protected: + QMutex m_mutex; + Action m_state = Stop; +}; + +#ifdef WITH_QML +/** @brief Slideshow using a QML file + * + * This is the "classic" slideshow in Calamares, which runs some QML + * while the installation is in progress. It is configured through + * Branding settings *slideshow* and *slideshowAPI*, showing the QML + * file from *slideshow*. The API version influences when and how the + * QML is loaded; version 1 does so only when the slideshow is activated, + * while version 2 does so asynchronously. + */ +class SlideshowQML : public Slideshow +{ + Q_OBJECT +public: + SlideshowQML( QWidget* parent ); + virtual ~SlideshowQML() override; + + QWidget* widget() override; + void changeSlideShowState( Action a ) override; + +public slots: + void loadQmlV2Complete(); + void loadQmlV2(); ///< Loads the slideshow QML (from branding) for API version 2 + +private: + QQuickWidget* m_qmlShow; + QQmlComponent* m_qmlComponent; + QQuickItem* m_qmlObject; ///< The actual show +}; +#endif + +/** @brief Slideshow using images + * + * This is an "oldschool" slideshow, but new in Calamares, which + * displays static image files one-by-one. It is for systems that + * do not use QML at all. It is configured through the Branding + * setting *slideshow*. When using this widget, the setting must + * be a list of filenames; the API is set to -1. + */ +class SlideshowPictures : public Slideshow +{ + Q_OBJECT +public: + SlideshowPictures( QWidget* parent ); + virtual ~SlideshowPictures() override; + + QWidget* widget() override; + virtual void changeSlideShowState( Action a ) override; + +public slots: + void next(); + +private: + QLabel* m_label; + QTimer* m_timer; + int m_imageIndex; + QStringList m_images; +}; + +} // namespace Calamares +#endif diff --git a/src/libcalamaresui/widgets/ClickableLabel.cpp b/src/libcalamaresui/widgets/ClickableLabel.cpp index 6e6f54459..8f2323fa4 100644 --- a/src/libcalamaresui/widgets/ClickableLabel.cpp +++ b/src/libcalamaresui/widgets/ClickableLabel.cpp @@ -18,7 +18,10 @@ #include "ClickableLabel.h" -#include +#include // for doubleClickInterval() + +namespace Calamares +{ ClickableLabel::ClickableLabel( QWidget* parent ) @@ -53,3 +56,5 @@ ClickableLabel::mouseReleaseEvent( QMouseEvent* event ) emit clicked(); } } + +} // namespace Calamares diff --git a/src/libcalamaresui/widgets/ClickableLabel.h b/src/libcalamaresui/widgets/ClickableLabel.h index fd66082c5..f60a247ca 100644 --- a/src/libcalamaresui/widgets/ClickableLabel.h +++ b/src/libcalamaresui/widgets/ClickableLabel.h @@ -17,13 +17,25 @@ * along with Calamares. If not, see . */ -#ifndef CLICKABLELABEL_H -#define CLICKABLELABEL_H +#ifndef LIBCALAMARESUI_CLICKABLELABEL_H +#define LIBCALAMARESUI_CLICKABLELABEL_H +#include #include -#include -class ClickableLabel : public QLabel +#include "DllMacro.h" + +namespace Calamares +{ + +/** @brief A Label where the whole label area is clickable + * + * When clicking anywhere on the Label (text, background, whatever) + * the signal clicked() is emitted. Use this as a buddy for radio + * buttons or other clickable things where you want mouse interaction + * with the label, to be the same as mouse interaction with the control. + */ +class UIDLLEXPORT ClickableLabel : public QLabel { Q_OBJECT public: @@ -39,7 +51,9 @@ protected: virtual void mouseReleaseEvent( QMouseEvent* event ) override; private: - QTime m_time; + QElapsedTimer m_time; }; -#endif // CLICKABLELABEL_H +} // namespace Calamares + +#endif // LIBCALAMARESUI_CLICKABLELABEL_H diff --git a/src/modules/partition/gui/PrettyRadioButton.cpp b/src/libcalamaresui/widgets/PrettyRadioButton.cpp similarity index 80% rename from src/modules/partition/gui/PrettyRadioButton.cpp rename to src/libcalamaresui/widgets/PrettyRadioButton.cpp index 18627f41c..1cf348315 100644 --- a/src/modules/partition/gui/PrettyRadioButton.cpp +++ b/src/libcalamaresui/widgets/PrettyRadioButton.cpp @@ -21,11 +21,14 @@ #include "utils/CalamaresUtilsGui.h" #include "widgets/ClickableLabel.h" +#include #include #include #include #include +namespace Calamares +{ PrettyRadioButton::PrettyRadioButton( QWidget* parent ) : QWidget( parent ) @@ -45,10 +48,8 @@ PrettyRadioButton::PrettyRadioButton( QWidget* parent ) m_mainLayout->addWidget( m_label, 0, 1 ); m_mainLayout->setContentsMargins( 0, 0, 0, 0 ); - connect( m_label, &ClickableLabel::clicked, - m_radio, &QRadioButton::click ); - connect( m_radio, &QRadioButton::toggled, - this, &PrettyRadioButton::toggleOptions ); + connect( m_label, &ClickableLabel::clicked, m_radio, &QRadioButton::click ); + connect( m_radio, &QRadioButton::toggled, this, &PrettyRadioButton::toggleOptions ); } @@ -80,17 +81,33 @@ PrettyRadioButton::iconSize() const } -QRadioButton* -PrettyRadioButton::buttonWidget() const +void +PrettyRadioButton::setChecked( bool checked ) { - return m_radio; + m_radio->setChecked( checked ); } + +bool +PrettyRadioButton::isChecked() const +{ + return m_radio->isChecked(); +} + +void +PrettyRadioButton::addToGroup( QButtonGroup* group, int id ) +{ + group->addButton( m_radio, id ); +} + + void PrettyRadioButton::addOptionsComboBox( QComboBox* box ) { if ( !box ) + { return; + } if ( !m_optionsLayout ) { @@ -105,12 +122,16 @@ PrettyRadioButton::addOptionsComboBox( QComboBox* box ) toggleOptions( m_radio->isChecked() ); } - m_optionsLayout->insertWidget( m_optionsLayout->count()-1, box ); + m_optionsLayout->insertWidget( m_optionsLayout->count() - 1, box ); } void PrettyRadioButton::toggleOptions( bool toggle ) { if ( m_optionsLayout ) + { m_optionsLayout->parentWidget()->setVisible( toggle ); + } } + +} // namespace Calamares diff --git a/src/modules/partition/gui/PrettyRadioButton.h b/src/libcalamaresui/widgets/PrettyRadioButton.h similarity index 58% rename from src/modules/partition/gui/PrettyRadioButton.h rename to src/libcalamaresui/widgets/PrettyRadioButton.h index c88c00728..9c7139526 100644 --- a/src/modules/partition/gui/PrettyRadioButton.h +++ b/src/libcalamaresui/widgets/PrettyRadioButton.h @@ -16,41 +16,59 @@ * along with Calamares. If not, see . */ -#ifndef PRETTYRADIOBUTTON_H -#define PRETTYRADIOBUTTON_H +#ifndef LIBCALAMARESUI_PRETTYRADIOBUTTON_H +#define LIBCALAMARESUI_PRETTYRADIOBUTTON_H + +#include "DllMacro.h" #include -class ClickableLabel; +class QButtonGroup; class QComboBox; class QGridLayout; class QHBoxLayout; +namespace Calamares +{ +class ClickableLabel; + /** @brief A radio button with fancy label next to it. + * + * The fancy label is used so that the text alongside the radio + * button can word-wrap, be multi-line, and support rich text. * * The radio button itself can be retrieved with buttonWidget(), * and the whole behaves a lot like a label. Extra options can be * added to the display (options are hidden when the button is * not selected) with addOptionsComboBox(). */ -class PrettyRadioButton : public QWidget +class UIDLLEXPORT PrettyRadioButton : public QWidget { Q_OBJECT public: explicit PrettyRadioButton( QWidget* parent = nullptr ); - virtual ~PrettyRadioButton() {} + virtual ~PrettyRadioButton() { } - virtual void setText( const QString& text ); + /// @brief Passes @p text on to the ClickableLabel + void setText( const QString& text ); - virtual void setIconSize( const QSize& size ); + // Icon applies to the radio-button part + void setIconSize( const QSize& size ); + QSize iconSize() const; + void setIcon( const QIcon& icon ); - virtual void setIcon( const QIcon& icon ); + // Applies to the radio-button part + void setChecked( bool checked ); + bool isChecked() const; - virtual QSize iconSize() const; + /** @brief Adds the radio-button part to the given @p group + * + * For managing the pretty-radio-button in button groups like normal + * radio buttons, call addToGroup() rather that group->addButton(). + */ + void addToGroup( QButtonGroup* group, int id = -1 ); - virtual QRadioButton* buttonWidget() const; - - /** @brief Add an options drop-down to this button. */ + /// @brief Add an options drop-down to this button. void addOptionsComboBox( QComboBox* ); protected slots: @@ -64,4 +82,5 @@ protected: QHBoxLayout* m_optionsLayout; }; -#endif // PRETTYRADIOBUTTON_H +} // namespace Calamares +#endif // LIBCALAMARESUI_PRETTYRADIOBUTTON_H diff --git a/src/modules/bootloader/main.py b/src/modules/bootloader/main.py index 674484527..87288b583 100644 --- a/src/modules/bootloader/main.py +++ b/src/modules/bootloader/main.py @@ -57,7 +57,6 @@ def get_uuid(): :return: """ - root_mount_point = libcalamares.globalstorage.value("rootMountPoint") partitions = libcalamares.globalstorage.value("partitions") for partition in partitions: diff --git a/src/modules/fstab/fstab.conf b/src/modules/fstab/fstab.conf index 576e505b6..db66488ac 100644 --- a/src/modules/fstab/fstab.conf +++ b/src/modules/fstab/fstab.conf @@ -20,6 +20,23 @@ efiMountOptions: umask=0077 # If a filesystem is on an SSD, add the following options. If a specific # filesystem is listed here, use those options, otherwise no additional # options are set (i.e. there is no *default* like in *mountOptions*). +# +# This example configuration applies the *discard* option to most +# common filesystems on an SSD. This may not be the right option +# for your distribution. If you use a systemd timer to trim the +# SSD, it may interfere with the *discard* option. Opinions vary +# as to whether *discard* is worth the effort -- it depends on +# the usage pattern of the disk as well. +# +# ssdExtraMountOptions: +# ext4: discard +# jfs: discard +# xfs: discard +# swap: discard +# btrfs: discard,compress=lzo +# +# The standard configuration applies only lzo compression to btrfs +# and does nothing for other filesystems. ssdExtraMountOptions: btrfs: ssd,compress=zstd,commit=120 diff --git a/src/modules/grubcfg/tests/CMakeTests.txt b/src/modules/grubcfg/tests/CMakeTests.txt new file mode 100644 index 000000000..299fccf07 --- /dev/null +++ b/src/modules/grubcfg/tests/CMakeTests.txt @@ -0,0 +1,12 @@ +# Special cases for grubcfg configuration tests: +# - 2.global specifies /tmp/calamares as the rootMountPath, +# so we end up editing files there. Create the directory +# beforehand, so the test doesn't blow up. +set(_grub_root /tmp/calamares/etc/default) +set(_grub_file ${_grub_root}/bogus) + +add_test( + NAME make-grubcfg-dirs + COMMAND ${CMAKE_COMMAND} -E make_directory ${_grub_root} + ) +set_tests_properties(load-grubcfg-2 PROPERTIES DEPENDS make-grubcfg-dirs) diff --git a/src/modules/keyboardq/CMakeLists.txt b/src/modules/keyboardq/CMakeLists.txt index f5fd2b64b..729748a7f 100644 --- a/src/modules/keyboardq/CMakeLists.txt +++ b/src/modules/keyboardq/CMakeLists.txt @@ -1,3 +1,8 @@ +if( NOT WITH_QML ) + calamares_skip_module( "keyboardq (QML is not supported in this build)" ) + return() +endif() + set( _keyboard ${CMAKE_CURRENT_SOURCE_DIR}/../keyboard ) include_directories( ${_keyboard} ) diff --git a/src/modules/locale/Config.cpp b/src/modules/locale/Config.cpp index ea1dc5423..cde0a5e09 100644 --- a/src/modules/locale/Config.cpp +++ b/src/modules/locale/Config.cpp @@ -81,16 +81,16 @@ Config::setLocaleInfo( const QString& initialRegion, const QString& initialZone, auto* region = m_regionList.find< TZRegion >( initialRegion ); if ( region && region->zones().find< TZZone >( initialZone ) ) { - this->m_regionModel->setCurrentIndex( m_regionModel->indexOf( initialRegion ) ); + m_regionModel->setCurrentIndex( m_regionModel->indexOf( initialRegion ) ); m_zonesModel->setList( region->zones() ); - this->m_zonesModel->setCurrentIndex( m_zonesModel->indexOf( initialZone ) ); + m_zonesModel->setCurrentIndex( m_zonesModel->indexOf( initialZone ) ); } else { - this->m_regionModel->setCurrentIndex( m_regionModel->indexOf( "America" ) ); + m_regionModel->setCurrentIndex( m_regionModel->indexOf( "America" ) ); m_zonesModel->setList( static_cast< const TZRegion* >( m_regionModel->item( m_regionModel->currentIndex() ) )->zones() ); - this->m_zonesModel->setCurrentIndex( m_zonesModel->indexOf( "New_York" ) ); + m_zonesModel->setCurrentIndex( m_zonesModel->indexOf( "New_York" ) ); } // Some distros come with a meaningfully commented and easy to parse locale.gen, diff --git a/src/modules/localeq/CMakeLists.txt b/src/modules/localeq/CMakeLists.txt index 280c95c62..c9ed1cd55 100644 --- a/src/modules/localeq/CMakeLists.txt +++ b/src/modules/localeq/CMakeLists.txt @@ -1,3 +1,8 @@ +if( NOT WITH_QML ) + calamares_skip_module( "localeq (QML is not supported in this build)" ) + return() +endif() + # When debugging the timezone widget, add this debugging definition # to have a debugging-friendly timezone widget, debug logging, # and no intrusive timezone-setting while clicking around. diff --git a/src/modules/notesqml/CMakeLists.txt b/src/modules/notesqml/CMakeLists.txt index 6aedab5aa..7ac808fa7 100644 --- a/src/modules/notesqml/CMakeLists.txt +++ b/src/modules/notesqml/CMakeLists.txt @@ -1,3 +1,8 @@ +if( NOT WITH_QML ) + calamares_skip_module( "notesqml (QML is not supported in this build)" ) + return() +endif() + calamares_add_plugin( notesqml TYPE viewmodule EXPORT_MACRO PLUGINDLLEXPORT_PRO diff --git a/src/modules/partition/CMakeLists.txt b/src/modules/partition/CMakeLists.txt index d01a7d983..d40bbcd1c 100644 --- a/src/modules/partition/CMakeLists.txt +++ b/src/modules/partition/CMakeLists.txt @@ -80,7 +80,6 @@ if ( KPMcore_FOUND AND Qt5DBus_FOUND AND KF5CoreAddons_FOUND AND KF5Config_FOUND gui/PartitionSizeController.cpp gui/PartitionSplitterWidget.cpp gui/PartitionViewStep.cpp - gui/PrettyRadioButton.cpp gui/ResizeVolumeGroupDialog.cpp gui/ScanningDialog.cpp gui/ReplaceWidget.cpp diff --git a/src/modules/partition/core/PartitionModel.cpp b/src/modules/partition/core/PartitionModel.cpp index d6f996c4f..1135f5719 100644 --- a/src/modules/partition/core/PartitionModel.cpp +++ b/src/modules/partition/core/PartitionModel.cpp @@ -241,7 +241,7 @@ PartitionModel::data( const QModelIndex& index, int role ) const return partition->partitionPath(); case PartitionPtrRole: - return qVariantFromValue( (void*)partition ); + return QVariant::fromValue( (void*)partition ); // Osprober roles: case OsproberNameRole: diff --git a/src/modules/partition/gui/ChoicePage.cpp b/src/modules/partition/gui/ChoicePage.cpp index c69768f70..5c90ea7b0 100644 --- a/src/modules/partition/gui/ChoicePage.cpp +++ b/src/modules/partition/gui/ChoicePage.cpp @@ -35,20 +35,19 @@ #include "PartitionBarsView.h" #include "PartitionLabelsView.h" #include "PartitionSplitterWidget.h" -#include "PrettyRadioButton.h" #include "ReplaceWidget.h" #include "ScanningDialog.h" +#include "Branding.h" #include "GlobalStorage.h" #include "JobQueue.h" #include "partition/PartitionIterator.h" #include "partition/PartitionQuery.h" +#include "utils/CalamaresUtilsGui.h" #include "utils/Logger.h" #include "utils/Retranslator.h" #include "utils/Units.h" - -#include "Branding.h" -#include "utils/CalamaresUtilsGui.h" +#include "widgets/PrettyRadioButton.h" #include #include @@ -69,6 +68,7 @@ using PartitionActions::Choices::SwapChoice; using CalamaresUtils::Partition::PartitionIterator; using CalamaresUtils::Partition::isPartitionFreeSpace; using CalamaresUtils::Partition::findPartitionByPath; +using Calamares::PrettyRadioButton; /** @brief Given a set of swap choices, return a sensible value from it. * @@ -259,14 +259,14 @@ ChoicePage::setupChoices() m_alongsideButton->setIcon( CalamaresUtils::defaultPixmap( CalamaresUtils::PartitionAlongside, CalamaresUtils::Original, iconSize ) ); - m_grp->addButton( m_alongsideButton->buttonWidget(), Alongside ); + m_alongsideButton->addToGroup( m_grp, Alongside ); m_eraseButton = new PrettyRadioButton; m_eraseButton->setIconSize( iconSize ); m_eraseButton->setIcon( CalamaresUtils::defaultPixmap( CalamaresUtils::PartitionEraseAuto, CalamaresUtils::Original, iconSize ) ); - m_grp->addButton( m_eraseButton->buttonWidget(), Erase ); + m_eraseButton->addToGroup( m_grp, Erase ); m_replaceButton = new PrettyRadioButton; @@ -274,7 +274,7 @@ ChoicePage::setupChoices() m_replaceButton->setIcon( CalamaresUtils::defaultPixmap( CalamaresUtils::PartitionReplaceOs, CalamaresUtils::Original, iconSize ) ); - m_grp->addButton( m_replaceButton->buttonWidget(), Replace ); + m_replaceButton->addToGroup( m_grp, Replace ); // Fill up swap options // .. TODO: only if enabled in the config @@ -294,7 +294,7 @@ ChoicePage::setupChoices() CalamaresUtils::Original, iconSize ) ); m_itemsLayout->addWidget( m_somethingElseButton ); - m_grp->addButton( m_somethingElseButton->buttonWidget(), Manual ); + m_somethingElseButton->addToGroup( m_grp, Manual ); m_itemsLayout->addStretch(); @@ -1193,7 +1193,7 @@ force_uncheck(QButtonGroup* grp, PrettyRadioButton* button) { button->hide(); grp->setExclusive( false ); - button->buttonWidget()->setChecked( false ); + button->setChecked( false ); grp->setExclusive( true ); } @@ -1288,8 +1288,8 @@ ChoicePage::setupActions() m_replaceButton->hide(); m_alongsideButton->hide(); m_grp->setExclusive( false ); - m_replaceButton->buttonWidget()->setChecked( false ); - m_alongsideButton->buttonWidget()->setChecked( false ); + m_replaceButton->setChecked( false ); + m_alongsideButton->setChecked( false ); m_grp->setExclusive( true ); } else if ( osproberEntriesForCurrentDevice.count() == 1 ) diff --git a/src/modules/partition/gui/ChoicePage.h b/src/modules/partition/gui/ChoicePage.h index baf575d49..1ff8f0d40 100644 --- a/src/modules/partition/gui/ChoicePage.h +++ b/src/modules/partition/gui/ChoicePage.h @@ -23,7 +23,6 @@ #include "ui_ChoicePage.h" -#include #include "core/OsproberEntry.h" #include "core/PartitionActions.h" @@ -31,17 +30,22 @@ #include #include #include +#include class QBoxLayout; class QComboBox; class QLabel; class QListView; +namespace Calamares +{ +class PrettyRadioButton; +} + class PartitionBarsView; class PartitionSplitterWidget; class PartitionLabelsView; class PartitionCoreModule; -class PrettyRadioButton; class DeviceInfoWidget; class Device; @@ -153,10 +157,10 @@ private: QComboBox* m_drivesCombo; QButtonGroup* m_grp; - PrettyRadioButton* m_alongsideButton; - PrettyRadioButton* m_eraseButton; - PrettyRadioButton* m_replaceButton; - PrettyRadioButton* m_somethingElseButton; + Calamares::PrettyRadioButton* m_alongsideButton; + Calamares::PrettyRadioButton* m_eraseButton; + Calamares::PrettyRadioButton* m_replaceButton; + Calamares::PrettyRadioButton* m_somethingElseButton; QComboBox* m_eraseSwapChoiceComboBox; // UI, see also m_eraseSwapChoice DeviceInfoWidget* m_deviceInfoWidget; @@ -182,4 +186,4 @@ private: QMutex m_coreMutex; }; -#endif // CHOICEPAGE_H +#endif // CHOICEPAGE_H diff --git a/src/modules/rawfs/tests/CMakeTests.txt b/src/modules/rawfs/tests/CMakeTests.txt new file mode 100644 index 000000000..44a7777c8 --- /dev/null +++ b/src/modules/rawfs/tests/CMakeTests.txt @@ -0,0 +1,8 @@ +# Special cases for rawfs tests +# +# - On FreeBSD, /proc/mounts doesn't exist (/proc is only about processes, +# and is rarely used). Expect the test to fail. + +if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + set_tests_properties(load-rawfs-1 PROPERTIES WILL_FAIL TRUE) +endif() diff --git a/src/modules/welcome/checker/GeneralRequirements.cpp b/src/modules/welcome/checker/GeneralRequirements.cpp index f30950da2..ba6ebe89f 100644 --- a/src/modules/welcome/checker/GeneralRequirements.cpp +++ b/src/modules/welcome/checker/GeneralRequirements.cpp @@ -80,7 +80,6 @@ struct MaybeChecked MaybeChecked& operator=( bool b ) { - cDebug() << "Assigning" << b; hasBeenChecked = true; value = b; return *this; diff --git a/src/modules/welcomeq/CMakeLists.txt b/src/modules/welcomeq/CMakeLists.txt index 9cb89c3d9..4a040344e 100644 --- a/src/modules/welcomeq/CMakeLists.txt +++ b/src/modules/welcomeq/CMakeLists.txt @@ -1,6 +1,11 @@ # This is a re-write of the welcome module using QML view steps # instead of widgets. +if( NOT WITH_QML ) + calamares_skip_module( "welcomeq (QML is not supported in this build)" ) + return() +endif() + set( _welcome ${CMAKE_CURRENT_SOURCE_DIR}/../welcome ) include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ${CMAKE_CURRENT_SOURCE_DIR}/../../libcalamares ${_welcome} ) diff --git a/src/modules/welcomeq/Recommended.qml b/src/modules/welcomeq/Recommended.qml index 373509104..636311b11 100644 --- a/src/modules/welcomeq/Recommended.qml +++ b/src/modules/welcomeq/Recommended.qml @@ -1,6 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2020, Anke Boersma + * Copyright 2020, Adriaan de Groot * * 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,6 +17,7 @@ * along with Calamares. If not, see . */ +import io.calamares.core 1.0 import io.calamares.ui 1.0 import QtQuick 2.7 @@ -27,41 +29,70 @@ Rectangle { focus: true Kirigami.Theme.backgroundColor: Kirigami.Theme.backgroundColor anchors.fill: parent - anchors.topMargin: 70 + anchors.topMargin: 50 TextArea { id: recommended anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top - anchors.topMargin: 20 + anchors.topMargin: 1 + horizontalAlignment: TextEdit.AlignHCenter width: 640 - font.pointSize: 12 + font.pointSize: 11 textFormat: Text.RichText antialiasing: true activeFocusOnPress: false wrapMode: Text.WordWrap - text: qsTr("

This computer does not satisfy some of the recommended requirements for setting up %1.

-

Setup can continue, but some features might be disabled.

").arg(Branding.string(Branding.VersionedName)) + text: qsTr("

This computer does not satisfy some of the recommended requirements for setting up %1.
+ Setup can continue, but some features might be disabled.

").arg(Branding.string(Branding.VersionedName)) } - TextArea { + Rectangle { + width: 640 + height: 360 anchors.horizontalCenter: parent.horizontalCenter anchors.top: recommended.bottom - anchors.topMargin: 20 - width: 640 - background: Rectangle { - implicitWidth: 640 - implicitHeight: 50 - border.color: "#ff0000" - color: "#b0e0e6" - } - font.pointSize: 12 - textFormat: Text.RichText - antialiasing: true - activeFocusOnPress: false - wrapMode: Text.WordWrap + anchors.topMargin: 5 - text: qsTr("

The system is not connected to the internet.

")//.arg(requirementsModel) + Component { + id: requirementsDelegate + + Item { + width: 640 + height: 35 + + Column { + anchors.centerIn: parent + + Rectangle { + implicitWidth: 640 + implicitHeight: 35 + border.color: satisfied ? "#228b22" : "#ffa411" + color: satisfied ? "#f0fff0" : "#ffefd5" + + Image { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.margins: 20 + source: satisfied ? "qrc:/data/images/yes.svgz" : "qrc:/data/images/information.svgz" + } + + Text { + text: satisfied ? details : negatedText + anchors.centerIn: parent + font.pointSize: 11 + } + } + } + } + } + + ListView { + anchors.fill: parent + spacing: 5 + model: config.requirementsModel + delegate: requirementsDelegate + } } } diff --git a/src/modules/welcomeq/Requirements.qml b/src/modules/welcomeq/Requirements.qml index 4f5520270..e81d0a2e6 100644 --- a/src/modules/welcomeq/Requirements.qml +++ b/src/modules/welcomeq/Requirements.qml @@ -1,6 +1,7 @@ /* === This file is part of Calamares - === * * Copyright 2020, Anke Boersma + * Copyright 2020, Adriaan de Groot * * 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,6 +17,7 @@ * along with Calamares. If not, see . */ +import io.calamares.core 1.0 import io.calamares.ui 1.0 import QtQuick 2.7 @@ -27,41 +29,71 @@ Rectangle { focus: true Kirigami.Theme.backgroundColor: Kirigami.Theme.backgroundColor anchors.fill: parent - anchors.topMargin: 70 + anchors.topMargin: 50 TextArea { id: required anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top - anchors.topMargin: 20 + anchors.topMargin: 1 + horizontalAlignment: TextEdit.AlignHCenter width: 640 - font.pointSize: 12 + font.pointSize: 11 textFormat: Text.RichText antialiasing: true activeFocusOnPress: false wrapMode: Text.WordWrap - text: qsTr("

This computer does not satisfy the minimum requirements for setting up %1.

-

Setup cannot continue.

").arg(Branding.string(Branding.VersionedName)) + text: qsTr("

This computer does not satisfy the minimum requirements for installing %1.
+ Installation cannot continue.

").arg(Branding.string(Branding.VersionedName)) } - TextArea { + Rectangle { + width: 640 + height: 360 anchors.horizontalCenter: parent.horizontalCenter anchors.top: required.bottom - anchors.topMargin: 20 - width: 640 - background: Rectangle { - implicitWidth: 640 - implicitHeight: 50 - border.color: "#ff0000" - color: "#ffc0cb" - } - font.pointSize: 12 - textFormat: Text.RichText - antialiasing: true - activeFocusOnPress: false - wrapMode: Text.WordWrap + anchors.topMargin: 5 - text: qsTr("

The installer is not running with administrator rights.

")//.arg(requirementsModel) + Component { + id: requirementsDelegate + + Item { + width: 640 + height: 35 + + Column { + anchors.centerIn: parent + + Rectangle { + implicitWidth: 640 + implicitHeight: 35 + border.color: mandatory ? "#228b22" : "#ff0000" + color: mandatory ? "#f0fff0" : "#ffc0cb" + + Image { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.margins: 20 + source: mandatory ? "qrc:/data/images/yes.svgz" : "qrc:/data/images/no.svgz" + } + + Text { + text: mandatory ? details : negatedText + anchors.centerIn: parent + font.pointSize: 11 + } + } + } + } + } + + ListView { + anchors.fill: parent + spacing: 5 + model: config.requirementsModel + delegate: requirementsDelegate + } } } + diff --git a/src/modules/welcomeq/welcomeq.conf b/src/modules/welcomeq/welcomeq.conf index a5ab97f50..2553e157a 100644 --- a/src/modules/welcomeq/welcomeq.conf +++ b/src/modules/welcomeq/welcomeq.conf @@ -25,3 +25,40 @@ showReleaseNotesUrl: true # branding.desc string) # # showDonateUrl: https://kde.org/community/donations/ + +# Requirements checking. These are general, generic, things +# that are checked. They may not match with the actual requirements +# imposed by other modules in the system. +requirements: + # Amount of available disk, in GiB. Floating-point is allowed here. + # Note that this does not account for *usable* disk, so it is possible + # to pass this requirement, yet have no space to install to. + requiredStorage: 5.5 + + # Amount of available RAM, in GiB. Floating-point is allowed here. + requiredRam: 1.0 + + # To check for internet connectivity, Calamares does a HTTP GET + # on this URL; on success (e.g. HTTP code 200) internet is OK. + internetCheckUrl: http://google.com + + # List conditions to check. Each listed condition will be + # probed in some way, and yields true or false according to + # the host system satisfying the condition. + # + # This sample file lists all the conditions that are known. + check: + - storage + - ram + - power + - internet + - root + - screen + # List conditions that **must** be satisfied (from the list + # of conditions, above) for installation to proceed. + # If any of these conditions are not met, the user cannot + # continue past the welcome page. + required: + # - storage + - ram + # - root diff --git a/src/modules/welcomeq/welcomeq.qml b/src/modules/welcomeq/welcomeq.qml index 2a29c5d9a..b92ff9628 100644 --- a/src/modules/welcomeq/welcomeq.qml +++ b/src/modules/welcomeq/welcomeq.qml @@ -57,16 +57,10 @@ Page } Recommended { - property var required: "yes" //requirementsModel - property var satisfied: "yes" //satisfiedRequirements - property var requiredMet: (required != satisfied) ? true : false visible: !config.requirementsModel.satisfiedRequirements } Requirements { - property var required: "yes" //requirementsModel - property var mandatory: "yes" //satisfiedMandatory - property var mandatoryMet: (required != mandatory) ? true : false visible: !config.requirementsModel.satisfiedMandatory }