Merge branch 'issue-1152'
This commit is contained in:
commit
79bd7b6b89
12
CHANGES
12
CHANGES
@ -7,6 +7,10 @@ website will have to do for older versions.
|
|||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
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 ##
|
## Core ##
|
||||||
|
|
||||||
- With this release, option *WITH_PYTHONQT* changes default to **off**.
|
- 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
|
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
|
solved. The *finished* page can be left out (but then you don't get
|
||||||
the restart-now functionality). #1168
|
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 ##
|
## Modules ##
|
||||||
|
|
||||||
|
@ -93,6 +93,17 @@ images:
|
|||||||
# The slideshow is displayed during execution steps (e.g. when the
|
# The slideshow is displayed during execution steps (e.g. when the
|
||||||
# installer is actually writing to disk and doing other slow things).
|
# installer is actually writing to disk and doing other slow things).
|
||||||
slideshow: "show.qml"
|
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.
|
# Colors for text and background components.
|
||||||
#
|
#
|
||||||
|
@ -68,8 +68,9 @@ Presentation
|
|||||||
centeredText: qsTr("This is a third Slide element.")
|
centeredText: qsTr("This is a third Slide element.")
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
function onActivate() {
|
||||||
advanceTimer.running = true;
|
presentation.currentSlide = 0;
|
||||||
console.log("Component complete");
|
advanceTimer.running = true
|
||||||
|
console.log("Component activated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,6 +127,7 @@ Branding::Branding( const QString& brandingFilePath,
|
|||||||
, m_descriptorPath( brandingFilePath )
|
, m_descriptorPath( brandingFilePath )
|
||||||
, m_welcomeStyleCalamares( false )
|
, m_welcomeStyleCalamares( false )
|
||||||
, m_welcomeExpandingLogo( true )
|
, m_welcomeExpandingLogo( true )
|
||||||
|
, m_slideshowAPI( 1 )
|
||||||
{
|
{
|
||||||
cDebug() << "Using Calamares branding file at" << brandingFilePath;
|
cDebug() << "Using Calamares branding file at" << brandingFilePath;
|
||||||
|
|
||||||
@ -234,6 +235,14 @@ Branding::Branding( const QString& brandingFilePath,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
bail( "Syntax error in slideshow sequence." );
|
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 )
|
catch ( YAML::Exception& e )
|
||||||
{
|
{
|
||||||
|
@ -118,6 +118,7 @@ public:
|
|||||||
|
|
||||||
/** @brief Path to the slideshow QML file, if any. */
|
/** @brief Path to the slideshow QML file, if any. */
|
||||||
QString slideshowPath() const { return m_slideshowPath; }
|
QString slideshowPath() const { return m_slideshowPath; }
|
||||||
|
int slideshowAPI() const { return m_slideshowAPI; }
|
||||||
|
|
||||||
QString string( Branding::StringEntry stringEntry ) const;
|
QString string( Branding::StringEntry stringEntry ) const;
|
||||||
QString styleString( Branding::StyleEntry styleEntry ) const;
|
QString styleString( Branding::StyleEntry styleEntry ) const;
|
||||||
@ -172,6 +173,7 @@ private:
|
|||||||
QMap< QString, QString > m_images;
|
QMap< QString, QString > m_images;
|
||||||
QMap< QString, QString > m_style;
|
QMap< QString, QString > m_style;
|
||||||
QString m_slideshowPath;
|
QString m_slideshowPath;
|
||||||
|
int m_slideshowAPI;
|
||||||
QString m_translationsPathPrefix;
|
QString m_translationsPathPrefix;
|
||||||
|
|
||||||
/** @brief Initialize the simple settings below */
|
/** @brief Initialize the simple settings below */
|
||||||
|
@ -36,10 +36,40 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QProgressBar>
|
#include <QProgressBar>
|
||||||
#include <QVBoxLayout>
|
#include <QQmlComponent>
|
||||||
#include <QtQuickWidgets/QQuickWidget>
|
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
#include <QQuickItem>
|
||||||
|
#include <QQuickWidget>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
/** @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
|
namespace Calamares
|
||||||
{
|
{
|
||||||
@ -47,31 +77,38 @@ namespace Calamares
|
|||||||
ExecutionViewStep::ExecutionViewStep( QObject* parent )
|
ExecutionViewStep::ExecutionViewStep( QObject* parent )
|
||||||
: ViewStep( parent )
|
: ViewStep( parent )
|
||||||
, m_widget( new QWidget )
|
, m_widget( new QWidget )
|
||||||
|
, m_progressBar( new QProgressBar )
|
||||||
|
, m_label( new QLabel )
|
||||||
|
, m_qmlShow( new QQuickWidget )
|
||||||
|
, m_qmlComponent( nullptr )
|
||||||
|
, m_qmlObject( nullptr )
|
||||||
{
|
{
|
||||||
m_progressBar = new QProgressBar;
|
|
||||||
m_progressBar->setMaximum( 10000 );
|
|
||||||
m_label = new QLabel;
|
|
||||||
QVBoxLayout* layout = new QVBoxLayout( m_widget );
|
QVBoxLayout* layout = new QVBoxLayout( m_widget );
|
||||||
QVBoxLayout* innerLayout = new QVBoxLayout;
|
QVBoxLayout* innerLayout = new QVBoxLayout;
|
||||||
|
|
||||||
m_slideShow = new QQuickWidget;
|
m_progressBar->setMaximum( 10000 );
|
||||||
layout->addWidget( m_slideShow );
|
|
||||||
|
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 );
|
CalamaresUtils::unmarginLayout( layout );
|
||||||
|
|
||||||
layout->addLayout( innerLayout );
|
layout->addLayout( innerLayout );
|
||||||
m_slideShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
|
||||||
m_slideShow->setResizeMode( QQuickWidget::SizeRootObjectToView );
|
|
||||||
|
|
||||||
m_slideShow->engine()->addImportPath( CalamaresUtils::qmlModulesDir().absolutePath() );
|
|
||||||
|
|
||||||
innerLayout->addSpacing( CalamaresUtils::defaultFontHeight() / 2 );
|
innerLayout->addSpacing( CalamaresUtils::defaultFontHeight() / 2 );
|
||||||
innerLayout->addWidget( m_progressBar );
|
innerLayout->addWidget( m_progressBar );
|
||||||
innerLayout->addWidget( m_label );
|
innerLayout->addWidget( m_label );
|
||||||
|
|
||||||
cDebug() << "QML import paths:" << Logger::DebugList( m_slideShow->engine()->importPathList() );
|
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,
|
connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue );
|
||||||
this, &ExecutionViewStep::updateFromJobQueue );
|
CALAMARES_RETRANSLATE( m_qmlShow->engine()->retranslate(); )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -130,22 +167,67 @@ ExecutionViewStep::isAtEnd() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 )
|
||||||
|
delete o;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 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.
|
||||||
|
callQMLFunction( m_qmlObject, "onActivate" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ExecutionViewStep::onActivate()
|
ExecutionViewStep::onActivate()
|
||||||
{
|
{
|
||||||
CALAMARES_RETRANSLATE_WIDGET( m_widget,
|
if ( Branding::instance()->slideshowAPI() == 2 )
|
||||||
if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() )
|
{
|
||||||
m_slideShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()
|
// The QML was already loaded in the constructor, need to start it
|
||||||
->slideshowPath() ) );
|
callQMLFunction( m_qmlObject, "onActivate" );
|
||||||
)
|
}
|
||||||
|
else if ( !Calamares::Branding::instance()->slideshowPath().isEmpty() )
|
||||||
|
{
|
||||||
|
// API version 1 assumes onCompleted is the trigger
|
||||||
|
m_qmlShow->setSource( QUrl::fromLocalFile( Calamares::Branding::instance()->slideshowPath() ) );
|
||||||
|
}
|
||||||
|
|
||||||
JobQueue* queue = JobQueue::instance();
|
JobQueue* queue = JobQueue::instance();
|
||||||
foreach ( const QString& instanceKey, m_jobInstanceKeys )
|
foreach ( const QString& instanceKey, m_jobInstanceKeys )
|
||||||
{
|
{
|
||||||
Calamares::Module* module = Calamares::ModuleManager::instance()
|
Calamares::Module* module = Calamares::ModuleManager::instance()->moduleInstance( instanceKey );
|
||||||
->moduleInstance( instanceKey );
|
|
||||||
if ( module )
|
if ( module )
|
||||||
{
|
{
|
||||||
auto jl = module->jobs();
|
auto jl = module->jobs();
|
||||||
@ -183,4 +265,16 @@ ExecutionViewStep::updateFromJobQueue( qreal percent, const QString& message )
|
|||||||
m_label->setText( message );
|
m_label->setText( message );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExecutionViewStep::onLeave()
|
||||||
|
{
|
||||||
|
// 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
|
} // namespace
|
||||||
|
@ -25,7 +25,10 @@
|
|||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
class QObject;
|
||||||
class QProgressBar;
|
class QProgressBar;
|
||||||
|
class QQmlComponent;
|
||||||
|
class QQuickItem;
|
||||||
class QQuickWidget;
|
class QQuickWidget;
|
||||||
|
|
||||||
namespace Calamares
|
namespace Calamares
|
||||||
@ -51,19 +54,26 @@ public:
|
|||||||
bool isAtEnd() const override;
|
bool isAtEnd() const override;
|
||||||
|
|
||||||
void onActivate() override;
|
void onActivate() override;
|
||||||
|
void onLeave() override;
|
||||||
|
|
||||||
JobList jobs() const override;
|
JobList jobs() const override;
|
||||||
|
|
||||||
void appendJobModuleInstanceKey( const QString& instanceKey );
|
void appendJobModuleInstanceKey( const QString& instanceKey );
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void loadQmlV2Complete();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget* m_widget;
|
QWidget* m_widget;
|
||||||
QProgressBar* m_progressBar;
|
QProgressBar* m_progressBar;
|
||||||
QLabel* m_label;
|
QLabel* m_label;
|
||||||
QQuickWidget* m_slideShow;
|
QQuickWidget* m_qmlShow;
|
||||||
|
QQmlComponent* m_qmlComponent;
|
||||||
|
QQuickItem* m_qmlObject; //< The actual show
|
||||||
|
|
||||||
QStringList m_jobInstanceKeys;
|
QStringList m_jobInstanceKeys;
|
||||||
|
|
||||||
|
void loadQmlV2(); //< Loads the slideshow QML (from branding) for API version 2
|
||||||
void updateFromJobQueue( qreal percent, const QString& message );
|
void updateFromJobQueue( qreal percent, const QString& message );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user