Commit e7f4479d authored by Adriaan de Groot's avatar Adriaan de Groot

[libcalamaresui] Move all the slideshow code out of ExecutionViewStep

- The SlideshowQML now handles all the bits that were in
  the viewstep.
- The viewstep uses the abstract Slideshow API.
parent df1f9f1b
......@@ -19,6 +19,7 @@ set( calamaresui_SOURCES
viewpages/BlankViewStep.cpp
viewpages/ExecutionViewStep.cpp
viewpages/QmlViewStep.cpp
viewpages/Slideshow.cpp
viewpages/ViewStep.cpp
widgets/ClickableLabel.cpp
......
......@@ -49,7 +49,7 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent )
, m_widget( new QWidget )
, m_progressBar( new QProgressBar )
, m_label( new QLabel )
, m_slideshow( nullptr )
, m_slideshow( new SlideshowQML( m_widget ) )
{
QVBoxLayout* layout = new QVBoxLayout( m_widget );
QVBoxLayout* innerLayout = new QVBoxLayout;
......@@ -64,12 +64,6 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent )
innerLayout->addWidget( m_progressBar );
innerLayout->addWidget( m_label );
if ( Branding::instance()->slideshowAPI() == 2 )
{
cDebug() << "QML load on startup, API 2.";
loadQmlV2();
}
connect( JobQueue::instance(), &JobQueue::progress, this, &ExecutionViewStep::updateFromJobQueue );
}
......@@ -127,108 +121,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 )
......@@ -276,13 +172,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
......@@ -59,9 +59,6 @@ public:
void appendJobModuleInstanceKey( const QString& instanceKey );
public slots:
void loadQmlV2Complete();
private:
QWidget* m_widget;
QProgressBar* m_progressBar;
......@@ -70,7 +67,6 @@ private:
QStringList m_jobInstanceKeys;
void loadQmlV2(); ///< Loads the slideshow QML (from branding) for API version 2
void updateFromJobQueue( qreal percent, const QString& message );
};
......
......@@ -20,22 +20,24 @@
#include "Slideshow.h"
#include "Branding.h"
#include "utils/Dirs.h"
#include "utils/Logger.h"
#include "utils/Qml.h"
#include "utils/Retranslator.h"
#include <QQuickWidget>
#include <QMutexLocker>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QQuickItem>
#include <QQuickWidget>
namespace Calamares
{
Slideshow::~Slideshow()
{
}
Slideshow::~Slideshow() {}
SlideshowQML::SlideshowQML(QWidget* parent)
SlideshowQML::SlideshowQML( QWidget* parent )
: Slideshow( parent )
, m_qmlShow( new QQuickWidget )
, m_qmlComponent( nullptr )
......@@ -47,9 +49,121 @@ SlideshowQML::SlideshowQML(QWidget* parent)
cDebug() << "QML import paths:" << Logger::DebugList( m_qmlShow->engine()->importPathList() );
#if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
CALAMARES_RETRANSLATE( m_qmlShow->engine()->retranslate(); )
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()
{
}
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;
}
} // namespace
......@@ -21,6 +21,7 @@
#ifndef LIBCALAMARESUI_SLIDESHOW_H
#define LIBCALAMARESUI_SLIDESHOW_H
#include <QMutex>
#include <QWidget>
class QQmlComponent;
......@@ -30,22 +31,58 @@ class QQuickWidget;
namespace Calamares
{
class Slideshow
class Slideshow : public QObject
{
Q_OBJECT
public:
Slideshow( QWidget* parent ) {};
/// @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;
};
class SlideshowQML : public Slideshow
{
Q_OBJECT
public:
SlideshowQML( QWidget* parent );
virtual ~SlideshowQML();
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;
......@@ -57,10 +94,10 @@ class SlideshowPictures : public Slideshow
{
public:
SlideshowPictures( QWidget* parent );
virtual ~SlideshowPictures();
virtual ~SlideshowPictures() override;
QWidget* widget() override;
};
}
} // namespace Calamares
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment