From cbe14bbf03994ddef9af77863ded9412ec8a1885 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sat, 1 Jun 2019 23:26:08 +0200 Subject: [PATCH 01/15] [libcalamaresui] Rename m_slideShow -> m_qmlShow - It could be any QML, so it's not a slideshow per se. - Minor prep-work for fixing up loading times. --- src/libcalamaresui/ExecutionViewStep.cpp | 23 ++++++++++------------- src/libcalamaresui/ExecutionViewStep.h | 2 +- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index a65ab3a1c..fc6bd2b58 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -36,10 +36,9 @@ #include #include #include -#include -#include #include - +#include +#include namespace Calamares { @@ -54,21 +53,21 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent ) QVBoxLayout* layout = new QVBoxLayout( m_widget ); QVBoxLayout* innerLayout = new QVBoxLayout; - m_slideShow = new QQuickWidget; - layout->addWidget( m_slideShow ); + m_qmlShow = new QQuickWidget; + layout->addWidget( m_qmlShow ); CalamaresUtils::unmarginLayout( layout ); layout->addLayout( innerLayout ); - m_slideShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); - m_slideShow->setResizeMode( QQuickWidget::SizeRootObjectToView ); + m_qmlShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); + m_qmlShow->setResizeMode( QQuickWidget::SizeRootObjectToView ); - m_slideShow->engine()->addImportPath( CalamaresUtils::qmlModulesDir().absolutePath() ); + m_qmlShow->engine()->addImportPath( CalamaresUtils::qmlModulesDir().absolutePath() ); innerLayout->addSpacing( CalamaresUtils::defaultFontHeight() / 2 ); innerLayout->addWidget( m_progressBar ); innerLayout->addWidget( m_label ); - cDebug() << "QML import paths:" << Logger::DebugList( m_slideShow->engine()->importPathList() ); + cDebug() << "QML import paths:" << Logger::DebugList( m_qmlShow->engine()->importPathList() ); connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue ); @@ -136,16 +135,14 @@ ExecutionViewStep::onActivate() { CALAMARES_RETRANSLATE_WIDGET( m_widget, if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() ) - m_slideShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance() + m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance() ->slideshowPath() ) ); ) - JobQueue* queue = JobQueue::instance(); foreach ( const QString& instanceKey, m_jobInstanceKeys ) { - Calamares::Module* module = Calamares::ModuleManager::instance() - ->moduleInstance( instanceKey ); + Calamares::Module* module = Calamares::ModuleManager::instance()->moduleInstance( instanceKey ); if ( module ) { auto jl = module->jobs(); diff --git a/src/libcalamaresui/ExecutionViewStep.h b/src/libcalamaresui/ExecutionViewStep.h index ed6de4382..c6e2897c9 100644 --- a/src/libcalamaresui/ExecutionViewStep.h +++ b/src/libcalamaresui/ExecutionViewStep.h @@ -60,7 +60,7 @@ private: QWidget* m_widget; QProgressBar* m_progressBar; QLabel* m_label; - QQuickWidget* m_slideShow; + QQuickWidget* m_qmlShow; QStringList m_jobInstanceKeys; From 5973dbf74c0bf5b2dfeae2b22cdfbbb692ce753f Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sat, 1 Jun 2019 23:39:39 +0200 Subject: [PATCH 02/15] [libcalamaresui] Shuffle code for QML slideshow - Create widgets earlier - Group layouting code - Add retranslator only once, not on every activate - Load QML only once, preferably at activation --- src/libcalamaresui/ExecutionViewStep.cpp | 35 ++++++++++++++---------- src/libcalamaresui/ExecutionViewStep.h | 1 + 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index fc6bd2b58..4ce9eb8ed 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -46,31 +46,36 @@ namespace Calamares ExecutionViewStep::ExecutionViewStep( QObject* parent ) : ViewStep( parent ) , m_widget( new QWidget ) + , m_progressBar( new QProgressBar ) + , m_label( new QLabel ) + , m_qmlShow( new QQuickWidget ) + , m_qmlShowLoaded( false ) { - m_progressBar = new QProgressBar; - m_progressBar->setMaximum( 10000 ); - m_label = new QLabel; QVBoxLayout* layout = new QVBoxLayout( m_widget ); QVBoxLayout* innerLayout = new QVBoxLayout; - m_qmlShow = new QQuickWidget; - layout->addWidget( m_qmlShow ); - CalamaresUtils::unmarginLayout( layout ); + m_progressBar->setMaximum( 10000 ); - layout->addLayout( innerLayout ); m_qmlShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); m_qmlShow->setResizeMode( QQuickWidget::SizeRootObjectToView ); - m_qmlShow->engine()->addImportPath( CalamaresUtils::qmlModulesDir().absolutePath() ); + layout->addWidget( m_qmlShow ); + CalamaresUtils::unmarginLayout( layout ); + layout->addLayout( innerLayout ); + innerLayout->addSpacing( CalamaresUtils::defaultFontHeight() / 2 ); innerLayout->addWidget( m_progressBar ); innerLayout->addWidget( m_label ); cDebug() << "QML import paths:" << Logger::DebugList( m_qmlShow->engine()->importPathList() ); - connect( JobQueue::instance(), &JobQueue::progress, - this, &ExecutionViewStep::updateFromJobQueue ); + connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue ); + + CALAMARES_RETRANSLATE_WIDGET( m_widget, + if ( m_qmlShowLoaded ) + m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ) ); + ) } @@ -133,11 +138,11 @@ ExecutionViewStep::isAtEnd() const void ExecutionViewStep::onActivate() { - CALAMARES_RETRANSLATE_WIDGET( m_widget, - if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() ) - m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance() - ->slideshowPath() ) ); - ) + if ( !m_qmlShowLoaded && !Calamares::Branding::instance()->slideshowPath().isEmpty() ) + { + m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ) ); + m_qmlShowLoaded = true; + } JobQueue* queue = JobQueue::instance(); foreach ( const QString& instanceKey, m_jobInstanceKeys ) diff --git a/src/libcalamaresui/ExecutionViewStep.h b/src/libcalamaresui/ExecutionViewStep.h index c6e2897c9..6d5b90705 100644 --- a/src/libcalamaresui/ExecutionViewStep.h +++ b/src/libcalamaresui/ExecutionViewStep.h @@ -61,6 +61,7 @@ private: QProgressBar* m_progressBar; QLabel* m_label; QQuickWidget* m_qmlShow; + bool m_qmlShowLoaded; QStringList m_jobInstanceKeys; From ff03235e33c3c3e98365f2367aad52f87d1c1e67 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 2 Jun 2019 13:19:16 +0200 Subject: [PATCH 03/15] [libcalamaresui] Load QML on startup --- src/libcalamaresui/ExecutionViewStep.cpp | 10 ++++++++-- src/libcalamaresui/ExecutionViewStep.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index 4ce9eb8ed..a1f7bcd27 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -69,6 +69,7 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent ) innerLayout->addWidget( m_label ); cDebug() << "QML import paths:" << Logger::DebugList( m_qmlShow->engine()->importPathList() ); + loadQml(); connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue ); @@ -134,15 +135,20 @@ ExecutionViewStep::isAtEnd() const return true; } - void -ExecutionViewStep::onActivate() +ExecutionViewStep::loadQml() { if ( !m_qmlShowLoaded && !Calamares::Branding::instance()->slideshowPath().isEmpty() ) { m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ) ); m_qmlShowLoaded = true; } +} + +void +ExecutionViewStep::onActivate() +{ + loadQml(); JobQueue* queue = JobQueue::instance(); foreach ( const QString& instanceKey, m_jobInstanceKeys ) diff --git a/src/libcalamaresui/ExecutionViewStep.h b/src/libcalamaresui/ExecutionViewStep.h index 6d5b90705..12eb6736c 100644 --- a/src/libcalamaresui/ExecutionViewStep.h +++ b/src/libcalamaresui/ExecutionViewStep.h @@ -65,6 +65,7 @@ private: QStringList m_jobInstanceKeys; + void loadQml(); //< Loads the slideshow QML (from branding) void updateFromJobQueue( qreal percent, const QString& message ); }; From daf2e552464a3f85d2009bf055040654b6eebb40 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 2 Jun 2019 13:22:18 +0200 Subject: [PATCH 04/15] [branding] Be more chatty in example slideshow - Log when the timer fires and the slide advances - Add a start() function (unused at this moment, will be called from C++ at the right time) --- src/branding/default/show.qml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/branding/default/show.qml b/src/branding/default/show.qml index b724a4832..7e04970ea 100644 --- a/src/branding/default/show.qml +++ b/src/branding/default/show.qml @@ -24,12 +24,17 @@ Presentation { id: presentation + function nextSlide() { + console.log("Next slide"); + presentation.goToNextSlide(); + } + Timer { id: advanceTimer interval: 5000 running: false repeat: true - onTriggered: presentation.goToNextSlide() + onTriggered: nextSlide() } Slide { From 103decab68cd0a54e3b1d26069fb1b8e23982ecc Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 2 Jun 2019 13:40:53 +0200 Subject: [PATCH 05/15] [libcalamaresui] Create the slideshow on activation - Load QML on startup, compile async - Create QML component when the page is reached. - On leave, stop the slideshow (otherwise, e.g. timers will keep running) This should move some of the delay from loading a large slideshow forward as the engine is already initialized when we reach the install / slideshow page. --- src/libcalamaresui/ExecutionViewStep.cpp | 30 +++++++++++++++++------- src/libcalamaresui/ExecutionViewStep.h | 6 ++++- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index a1f7bcd27..f41068237 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -49,7 +50,8 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent ) , m_progressBar( new QProgressBar ) , m_label( new QLabel ) , m_qmlShow( new QQuickWidget ) - , m_qmlShowLoaded( false ) + , m_qmlComponent( nullptr ) + , m_qmlObject( nullptr ) { QVBoxLayout* layout = new QVBoxLayout( m_widget ); QVBoxLayout* innerLayout = new QVBoxLayout; @@ -72,11 +74,6 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent ) loadQml(); connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue ); - - CALAMARES_RETRANSLATE_WIDGET( m_widget, - if ( m_qmlShowLoaded ) - m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ) ); - ) } @@ -138,10 +135,12 @@ ExecutionViewStep::isAtEnd() const void ExecutionViewStep::loadQml() { - if ( !m_qmlShowLoaded && !Calamares::Branding::instance()->slideshowPath().isEmpty() ) + if ( !m_qmlComponent && !Calamares::Branding::instance()->slideshowPath().isEmpty() ) { - m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ) ); - m_qmlShowLoaded = true; + m_qmlComponent = new QQmlComponent( m_qmlShow->engine(), + QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ), + QQmlComponent::CompilationMode::Asynchronous + ); } } @@ -149,6 +148,12 @@ void ExecutionViewStep::onActivate() { loadQml(); + if ( m_qmlComponent ) + { + m_qmlObject = m_qmlComponent->create(); + cDebug() << "Created QML object" << (void *)m_qmlObject << m_qmlObject->objectName(); + cDebug() << "Show root" << m_qmlShow->rootObject() << "context" << m_qmlShow->rootContext(); + } JobQueue* queue = JobQueue::instance(); foreach ( const QString& instanceKey, m_jobInstanceKeys ) @@ -191,4 +196,11 @@ ExecutionViewStep::updateFromJobQueue( qreal percent, const QString& message ) m_label->setText( message ); } +void +ExecutionViewStep::onLeave() +{ + delete m_qmlObject; + m_qmlObject = nullptr; +} + } // namespace diff --git a/src/libcalamaresui/ExecutionViewStep.h b/src/libcalamaresui/ExecutionViewStep.h index 12eb6736c..a968f22e4 100644 --- a/src/libcalamaresui/ExecutionViewStep.h +++ b/src/libcalamaresui/ExecutionViewStep.h @@ -25,8 +25,10 @@ #include class QLabel; +class QObject; class QProgressBar; class QQuickWidget; +class QQmlComponent; namespace Calamares { @@ -51,6 +53,7 @@ public: bool isAtEnd() const override; void onActivate() override; + void onLeave() override; JobList jobs() const override; @@ -61,7 +64,8 @@ private: QProgressBar* m_progressBar; QLabel* m_label; QQuickWidget* m_qmlShow; - bool m_qmlShowLoaded; + QQmlComponent* m_qmlComponent; + QObject* m_qmlObject; //< The actual show QStringList m_jobInstanceKeys; From f52d62034b605c29a3a82018f1c5680b21bc3fb3 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 2 Jun 2019 14:27:12 +0200 Subject: [PATCH 06/15] [libcalamaresui] Manual QML loading trickery - The slideshow item needs a parent to be visible, - QML gets size 0,0 unless explicitly sized to the surrounding widget. --- src/libcalamaresui/ExecutionViewStep.cpp | 16 +++++++++++++--- src/libcalamaresui/ExecutionViewStep.h | 5 +++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index f41068237..fd675313c 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -150,9 +151,18 @@ ExecutionViewStep::onActivate() loadQml(); if ( m_qmlComponent ) { - m_qmlObject = m_qmlComponent->create(); - cDebug() << "Created QML object" << (void *)m_qmlObject << m_qmlObject->objectName(); - cDebug() << "Show root" << m_qmlShow->rootObject() << "context" << m_qmlShow->rootContext(); + auto* rootItem = m_qmlShow->quickWindow()->contentItem(); + rootItem->setSize( m_qmlShow->size() ); + + QObject* o = m_qmlComponent->create(); + m_qmlObject = qobject_cast< QQuickItem* >( o ); + if ( !m_qmlObject ) + delete o; + else + { + m_qmlObject->setParentItem( rootItem ); + m_qmlObject->setSize( m_qmlShow->size() ); + } } JobQueue* queue = JobQueue::instance(); diff --git a/src/libcalamaresui/ExecutionViewStep.h b/src/libcalamaresui/ExecutionViewStep.h index a968f22e4..c8a0a59d6 100644 --- a/src/libcalamaresui/ExecutionViewStep.h +++ b/src/libcalamaresui/ExecutionViewStep.h @@ -27,8 +27,9 @@ class QLabel; class QObject; class QProgressBar; -class QQuickWidget; class QQmlComponent; +class QQuickItem; +class QQuickWidget; namespace Calamares { @@ -65,7 +66,7 @@ private: QLabel* m_label; QQuickWidget* m_qmlShow; QQmlComponent* m_qmlComponent; - QObject* m_qmlObject; //< The actual show + QQuickItem* m_qmlObject; //< The actual show QStringList m_jobInstanceKeys; From 2b5cf9e613828b3cd71b0c236deec6e287607b72 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 3 Jun 2019 10:38:29 +0200 Subject: [PATCH 07/15] [libcalamaresui] There is code in Qt for setting up QML widgets - The not-publicly documented setContent() method does all the parenting and resizing needed; some of this isn't available from outside of the widget either. The QML slideshow now sizes and re-sizes correctly. --- src/libcalamaresui/ExecutionViewStep.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index fd675313c..2fb18ff84 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -151,17 +151,17 @@ ExecutionViewStep::onActivate() loadQml(); if ( m_qmlComponent ) { - auto* rootItem = m_qmlShow->quickWindow()->contentItem(); - rootItem->setSize( m_qmlShow->size() ); - QObject* o = m_qmlComponent->create(); m_qmlObject = qobject_cast< QQuickItem* >( o ); if ( !m_qmlObject ) delete o; else { - m_qmlObject->setParentItem( rootItem ); - m_qmlObject->setSize( m_qmlShow->size() ); + // 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 ); } } From 68e6bd676e2c1daa9f8e3fa4aa85235bc6b8cb39 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 16 Jun 2019 12:15:41 +0200 Subject: [PATCH 08/15] [libcalamaresui] Instantiate QML at load time - By instantiating only on activation, an ugly "white" gap appears where there is no widget at all. So instantiate earlier so that the widget already exists and is painting by the time the slideshow part is visible. - This makes the net effect of this branch so far zero: the slideshow is still loaded and started when Calamares starts. --- src/libcalamaresui/ExecutionViewStep.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index 2fb18ff84..f8f9ea03b 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -143,12 +143,6 @@ ExecutionViewStep::loadQml() QQmlComponent::CompilationMode::Asynchronous ); } -} - -void -ExecutionViewStep::onActivate() -{ - loadQml(); if ( m_qmlComponent ) { QObject* o = m_qmlComponent->create(); @@ -164,6 +158,12 @@ ExecutionViewStep::onActivate() m_qmlShow->setContent( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ), m_qmlComponent, m_qmlObject ); } } +} + +void +ExecutionViewStep::onActivate() +{ + loadQml(); JobQueue* queue = JobQueue::instance(); foreach ( const QString& instanceKey, m_jobInstanceKeys ) From 71209b323ad0e0a31bc242e6c94feda146842d02 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 16 Jun 2019 13:06:34 +0200 Subject: [PATCH 09/15] [libcalamaresui] Call QML methods on start and stop - Use onActivate() and onLeave() in QML as well, to start and stop the slideshow. --- src/libcalamaresui/ExecutionViewStep.cpp | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index f8f9ea03b..047fcede0 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -160,10 +160,40 @@ ExecutionViewStep::loadQml() } } +/** @brief Calls the QML method @p method() + * + * Pass in only the name of the method (e.g. onActivate). This function + * checks if the method exists (with no arguments) before trying to + * call it, so that no warnings are printed due to missing methods. + * + * If there is a return value from the QML method, it is logged (but not otherwise used). + */ +void +callQMLFunction( QQuickItem* qmlObject, const char* method ) +{ + QByteArray methodSignature( method ); + methodSignature.append( "()" ); + + if ( qmlObject && qmlObject->metaObject()->indexOfMethod( methodSignature ) >= 0 ) + { + QVariant returnValue; + QMetaObject::invokeMethod( qmlObject, method, Q_RETURN_ARG( QVariant, returnValue ) ); + if ( !returnValue.isNull() ) + { + cDebug() << "QML" << methodSignature << "returned" << returnValue; + } + } + else if ( qmlObject ) + { + cDebug() << "QML" << methodSignature << "is missing."; + } +} + void ExecutionViewStep::onActivate() { loadQml(); + callQMLFunction( m_qmlObject, "onActivate" ); JobQueue* queue = JobQueue::instance(); foreach ( const QString& instanceKey, m_jobInstanceKeys ) @@ -209,6 +239,7 @@ ExecutionViewStep::updateFromJobQueue( qreal percent, const QString& message ) void ExecutionViewStep::onLeave() { + callQMLFunction( m_qmlObject, "onLeave" ); delete m_qmlObject; m_qmlObject = nullptr; } From 9188eab66f01b4ea313c8f21ca1ff9bab51205a5 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Sun, 16 Jun 2019 13:33:20 +0200 Subject: [PATCH 10/15] Changes: document new things in slideshow --- CHANGES | 12 ++++++++++++ src/branding/default/show.qml | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 9f72f515c..7e9fc22be 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,10 @@ website will have to do for older versions. This release contains contributions from (alphabetically by first name): +Distributions are **advised** to check the slideshow they use for the +installation step; changes in loading and translation mechanisms may +require changes in the slideshow. + ## Core ## - With this release, option *WITH_PYTHONQT* changes default to **off**. @@ -18,6 +22,14 @@ This release contains contributions from (alphabetically by first name): configured after the last *exec* section of the sequence has been solved. The *finished* page can be left out (but then you don't get the restart-now functionality). #1168 + - The *slideshow* which is run during installation is now loaded on + startup (while requirements checking is being done). This should + improve responsiveness when the slideshow starts. If the slideshow + has methods `onActivate()` and `onLeave()` those will be called + when the installation step is activated (e.g. the installation + starts and the slideshow becomes visible) or is finished (and the + slideshow becomes hidden). + - The example slideshow now starts its timers when it becomes visible. ## Modules ## diff --git a/src/branding/default/show.qml b/src/branding/default/show.qml index 7e04970ea..c1db046c2 100644 --- a/src/branding/default/show.qml +++ b/src/branding/default/show.qml @@ -68,5 +68,8 @@ Presentation centeredText: "This is a third Slide element." } - Component.onCompleted: advanceTimer.running = true + function onActivate() { + presentation.currentSlide = 0; + advanceTimer.running = true + } } From 148b829591e9af7f281b159ddfe3f6ae27c58fcc Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 17 Jun 2019 10:58:14 +0200 Subject: [PATCH 11/15] [libcalamares] Introduce slideshowAPI setting --- src/branding/default/branding.desc | 11 +++++++++++ src/libcalamaresui/Branding.cpp | 9 +++++++++ src/libcalamaresui/Branding.h | 2 ++ 3 files changed, 22 insertions(+) diff --git a/src/branding/default/branding.desc b/src/branding/default/branding.desc index 1dd4de03a..1bd76cd29 100644 --- a/src/branding/default/branding.desc +++ b/src/branding/default/branding.desc @@ -93,6 +93,17 @@ images: # The slideshow is displayed during execution steps (e.g. when the # installer is actually writing to disk and doing other slow things). slideshow: "show.qml" +# There are two available APIs for the slideshow: +# - 1 (the default) loads the entire slideshow when the installation- +# slideshow page is shown and starts the QML then. The QML +# is never stopped (after installation is done, times etc. +# continue to fire). +# - 2 loads the slideshow on startup and calls onActivate() and +# onLeave() in the root object. After the installation is done, +# the show is stopped (first by calling onLeave(), then destroying +# the QML components). +slideshowAPI: 2 + # Colors for text and background components. # diff --git a/src/libcalamaresui/Branding.cpp b/src/libcalamaresui/Branding.cpp index 48917f1ba..876fdfa80 100644 --- a/src/libcalamaresui/Branding.cpp +++ b/src/libcalamaresui/Branding.cpp @@ -127,6 +127,7 @@ Branding::Branding( const QString& brandingFilePath, , m_descriptorPath( brandingFilePath ) , m_welcomeStyleCalamares( false ) , m_welcomeExpandingLogo( true ) + , m_slideshowAPI( 1 ) { cDebug() << "Using Calamares branding file at" << brandingFilePath; @@ -234,6 +235,14 @@ Branding::Branding( const QString& brandingFilePath, } else bail( "Syntax error in slideshow sequence." ); + + int api = doc[ "slideshowAPI" ].IsScalar() ? doc[ "slideshowAPI" ].as() : -1; + if ( ( api < 1 ) || ( api > 2 ) ) + { + cWarning() << "Invalid or missing *slideshowAPI* in branding file."; + api = 1; + } + m_slideshowAPI = api; } catch ( YAML::Exception& e ) { diff --git a/src/libcalamaresui/Branding.h b/src/libcalamaresui/Branding.h index 23a7a7a49..a3909bc00 100644 --- a/src/libcalamaresui/Branding.h +++ b/src/libcalamaresui/Branding.h @@ -118,6 +118,7 @@ public: /** @brief Path to the slideshow QML file, if any. */ QString slideshowPath() const { return m_slideshowPath; } + int slideshowAPI() const { return m_slideshowAPI; } QString string( Branding::StringEntry stringEntry ) const; QString styleString( Branding::StyleEntry styleEntry ) const; @@ -172,6 +173,7 @@ private: QMap< QString, QString > m_images; QMap< QString, QString > m_style; QString m_slideshowPath; + int m_slideshowAPI; QString m_translationsPathPrefix; /** @brief Initialize the simple settings below */ From 15ab98cb266b94d27356a1093c4a0042a97bcd84 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 17 Jun 2019 11:05:56 +0200 Subject: [PATCH 12/15] [libcalamaresui] Use API version to load slideshow differently --- src/libcalamaresui/ExecutionViewStep.cpp | 30 ++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index 047fcede0..f31b7273b 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -72,7 +72,11 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent ) innerLayout->addWidget( m_label ); cDebug() << "QML import paths:" << Logger::DebugList( m_qmlShow->engine()->importPathList() ); - loadQml(); + if ( Branding::instance()->slideshowAPI() == 2 ) + { + cDebug() << "QML load on startup."; + loadQml(); + } connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue ); } @@ -143,7 +147,7 @@ ExecutionViewStep::loadQml() QQmlComponent::CompilationMode::Asynchronous ); } - if ( m_qmlComponent ) + if ( m_qmlComponent && !m_qmlObject ) { QObject* o = m_qmlComponent->create(); m_qmlObject = qobject_cast< QQuickItem* >( o ); @@ -192,8 +196,16 @@ callQMLFunction( QQuickItem* qmlObject, const char* method ) void ExecutionViewStep::onActivate() { - loadQml(); - callQMLFunction( m_qmlObject, "onActivate" ); + if ( Branding::instance()->slideshowAPI() == 2 ) + { + // The QML was already loaded in the constructor, need to start it + callQMLFunction( m_qmlObject, "onActivate" ); + } + else + { + // API version 1 assumes onCompleted is the trigger + loadQml(); + } JobQueue* queue = JobQueue::instance(); foreach ( const QString& instanceKey, m_jobInstanceKeys ) @@ -239,9 +251,13 @@ ExecutionViewStep::updateFromJobQueue( qreal percent, const QString& message ) void ExecutionViewStep::onLeave() { - callQMLFunction( m_qmlObject, "onLeave" ); - delete m_qmlObject; - m_qmlObject = nullptr; + // API version 2 is explicitly stopped; version 1 keeps running + if ( Branding::instance()->slideshowAPI() == 2 ) + { + callQMLFunction( m_qmlObject, "onLeave" ); + delete m_qmlObject; + m_qmlObject = nullptr; + } } } // namespace From 193bcbde7113ea83ad91ec8deeedf93cecee347d Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 17 Jun 2019 11:17:06 +0200 Subject: [PATCH 13/15] [libcalamaresui] Use setSource() for API version 1 - Just avoid all the componentized loading and do the synchronous load-compile-setContent thing. --- src/libcalamaresui/ExecutionViewStep.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index f31b7273b..62e270dee 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -201,10 +201,10 @@ ExecutionViewStep::onActivate() // The QML was already loaded in the constructor, need to start it callQMLFunction( m_qmlObject, "onActivate" ); } - else + else if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() ) { // API version 1 assumes onCompleted is the trigger - loadQml(); + m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ) ); } JobQueue* queue = JobQueue::instance(); From f9bd0fba1000fb240095902b8188de2097e73f4e Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 17 Jun 2019 11:47:25 +0200 Subject: [PATCH 14/15] [libcalamares] Handle async QML loading - The component isn't ready immediately, so instatiate once it is fully loaded and ready - Edge case if the execution view step is already visible, then start the show (because a previous call to onActivate() will have missed it). --- src/libcalamaresui/ExecutionViewStep.cpp | 82 ++++++++++++++---------- src/libcalamaresui/ExecutionViewStep.h | 5 +- 2 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index 62e270dee..fbc239a03 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -42,6 +42,35 @@ #include #include +/** @brief Calls the QML method @p method() + * + * Pass in only the name of the method (e.g. onActivate). This function + * checks if the method exists (with no arguments) before trying to + * call it, so that no warnings are printed due to missing methods. + * + * If there is a return value from the QML method, it is logged (but not otherwise used). + */ +static void +callQMLFunction( QQuickItem* qmlObject, const char* method ) +{ + QByteArray methodSignature( method ); + methodSignature.append( "()" ); + + if ( qmlObject && qmlObject->metaObject()->indexOfMethod( methodSignature ) >= 0 ) + { + QVariant returnValue; + QMetaObject::invokeMethod( qmlObject, method, Q_RETURN_ARG( QVariant, returnValue ) ); + if ( !returnValue.isNull() ) + { + cDebug() << "QML" << methodSignature << "returned" << returnValue; + } + } + else if ( qmlObject ) + { + cDebug() << "QML" << methodSignature << "is missing."; + } +} + namespace Calamares { @@ -74,8 +103,8 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent ) cDebug() << "QML import paths:" << Logger::DebugList( m_qmlShow->engine()->importPathList() ); if ( Branding::instance()->slideshowAPI() == 2 ) { - cDebug() << "QML load on startup."; - loadQml(); + cDebug() << "QML load on startup, API 2."; + loadQmlV2(); } connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue ); @@ -138,7 +167,7 @@ ExecutionViewStep::isAtEnd() const } void -ExecutionViewStep::loadQml() +ExecutionViewStep::loadQmlV2() { if ( !m_qmlComponent && !Calamares::Branding::instance()->slideshowPath().isEmpty() ) { @@ -146,9 +175,19 @@ ExecutionViewStep::loadQml() QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ), QQmlComponent::CompilationMode::Asynchronous ); + connect( m_qmlComponent, &QQmlComponent::statusChanged, this, &ExecutionViewStep::loadQmlV2Complete ); } - if ( m_qmlComponent && !m_qmlObject ) +} + +void +ExecutionViewStep::loadQmlV2Complete() +{ + if ( m_qmlComponent && m_qmlComponent->isReady() && !m_qmlObject ) { + cDebug() << "QML loading 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 ) @@ -160,39 +199,16 @@ ExecutionViewStep::loadQml() // 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. + callQMLFunction( m_qmlObject, "onActivate" ); + } } } } -/** @brief Calls the QML method @p method() - * - * Pass in only the name of the method (e.g. onActivate). This function - * checks if the method exists (with no arguments) before trying to - * call it, so that no warnings are printed due to missing methods. - * - * If there is a return value from the QML method, it is logged (but not otherwise used). - */ -void -callQMLFunction( QQuickItem* qmlObject, const char* method ) -{ - QByteArray methodSignature( method ); - methodSignature.append( "()" ); - - if ( qmlObject && qmlObject->metaObject()->indexOfMethod( methodSignature ) >= 0 ) - { - QVariant returnValue; - QMetaObject::invokeMethod( qmlObject, method, Q_RETURN_ARG( QVariant, returnValue ) ); - if ( !returnValue.isNull() ) - { - cDebug() << "QML" << methodSignature << "returned" << returnValue; - } - } - else if ( qmlObject ) - { - cDebug() << "QML" << methodSignature << "is missing."; - } -} - void ExecutionViewStep::onActivate() { diff --git a/src/libcalamaresui/ExecutionViewStep.h b/src/libcalamaresui/ExecutionViewStep.h index c8a0a59d6..c1183e110 100644 --- a/src/libcalamaresui/ExecutionViewStep.h +++ b/src/libcalamaresui/ExecutionViewStep.h @@ -60,6 +60,9 @@ public: void appendJobModuleInstanceKey( const QString& instanceKey ); +public slots: + void loadQmlV2Complete(); + private: QWidget* m_widget; QProgressBar* m_progressBar; @@ -70,7 +73,7 @@ private: QStringList m_jobInstanceKeys; - void loadQml(); //< Loads the slideshow QML (from branding) + void loadQmlV2(); //< Loads the slideshow QML (from branding) for API version 2 void updateFromJobQueue( qreal percent, const QString& message ); }; From 58f6635ca074bf934a69059463220e8c1dd7aa8f Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 17 Jun 2019 11:52:20 +0200 Subject: [PATCH 15/15] [libcalamaresui] Force retranslation on language change --- src/libcalamaresui/ExecutionViewStep.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcalamaresui/ExecutionViewStep.cpp b/src/libcalamaresui/ExecutionViewStep.cpp index fbc239a03..4d28a24b2 100644 --- a/src/libcalamaresui/ExecutionViewStep.cpp +++ b/src/libcalamaresui/ExecutionViewStep.cpp @@ -108,6 +108,7 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent ) } connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue ); + CALAMARES_RETRANSLATE( m_qmlShow->engine()->retranslate(); ) }