Merge branch 'fix-slideshow'
This commit is contained in:
commit
c3c4b79147
4
CHANGES
4
CHANGES
@ -9,7 +9,9 @@ This release contains contributions from (alphabetically by first name):
|
|||||||
- No external contributors yet
|
- No external contributors yet
|
||||||
|
|
||||||
## Core ##
|
## 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).
|
||||||
|
|
||||||
## Modules ##
|
## Modules ##
|
||||||
- No module changes yet
|
- No module changes yet
|
||||||
|
@ -141,8 +141,23 @@ 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).
|
||||||
|
#
|
||||||
|
# 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"
|
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-
|
# - 1 (the default) loads the entire slideshow when the installation-
|
||||||
# slideshow page is shown and starts the QML then. The QML
|
# slideshow page is shown and starts the QML then. The QML
|
||||||
# is never stopped (after installation is done, times etc.
|
# 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,
|
# onLeave() in the root object. After the installation is done,
|
||||||
# the show is stopped (first by calling onLeave(), then destroying
|
# the show is stopped (first by calling onLeave(), then destroying
|
||||||
# the QML components).
|
# the QML components).
|
||||||
|
#
|
||||||
|
# An image slideshow does not need to have the API defined.
|
||||||
slideshowAPI: 2
|
slideshowAPI: 2
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,6 +41,13 @@
|
|||||||
#include <KOSRelease>
|
#include <KOSRelease>
|
||||||
#endif
|
#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
|
namespace Calamares
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -153,7 +160,7 @@ Branding::Branding( const QString& brandingFilePath, QObject* parent )
|
|||||||
QDir componentDir( componentDirectory() );
|
QDir componentDir( componentDirectory() );
|
||||||
if ( !componentDir.exists() )
|
if ( !componentDir.exists() )
|
||||||
{
|
{
|
||||||
bail( "Bad component directory path." );
|
bail( m_descriptorPath, "Bad component directory path." );
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile file( brandingFilePath );
|
QFile file( brandingFilePath );
|
||||||
@ -168,7 +175,8 @@ Branding::Branding( const QString& brandingFilePath, QObject* parent )
|
|||||||
|
|
||||||
m_componentName = QString::fromStdString( doc[ "componentName" ].as< std::string >() );
|
m_componentName = QString::fromStdString( doc[ "componentName" ].as< std::string >() );
|
||||||
if ( m_componentName != componentDir.dirName() )
|
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." );
|
"component directory." );
|
||||||
|
|
||||||
initSimpleSettings( doc );
|
initSimpleSettings( doc );
|
||||||
@ -214,7 +222,8 @@ Branding::Branding( const QString& brandingFilePath, QObject* parent )
|
|||||||
// Not found, bail out with the filename used
|
// Not found, bail out with the filename used
|
||||||
if ( icon.isNull() )
|
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 imageName; // Not turned into a path
|
||||||
}
|
}
|
||||||
@ -232,40 +241,44 @@ Branding::Branding( const QString& brandingFilePath, QObject* parent )
|
|||||||
QFileInfo imageFi( componentDir.absoluteFilePath( pathString ) );
|
QFileInfo imageFi( componentDir.absoluteFilePath( pathString ) );
|
||||||
if ( !imageFi.exists() )
|
if ( !imageFi.exists() )
|
||||||
{
|
{
|
||||||
bail( QString( "Slideshow file %1 does not exist." ).arg( imageFi.absoluteFilePath() ) );
|
bail( m_descriptorPath,
|
||||||
|
QString( "Slideshow file %1 does not exist." ).arg( imageFi.absoluteFilePath() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
slideShowPictures[ i ] = imageFi.absoluteFilePath();
|
slideShowPictures[ i ] = imageFi.absoluteFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
//FIXME: implement a GenericSlideShow.qml that uses these slideShowPictures
|
m_slideshowFilenames = slideShowPictures;
|
||||||
|
m_slideshowAPI = -1;
|
||||||
}
|
}
|
||||||
else if ( doc[ "slideshow" ].IsScalar() )
|
else if ( doc[ "slideshow" ].IsScalar() )
|
||||||
{
|
{
|
||||||
QString slideshowPath = QString::fromStdString( doc[ "slideshow" ].as< std::string >() );
|
QString slideshowPath = QString::fromStdString( doc[ "slideshow" ].as< std::string >() );
|
||||||
QFileInfo slideshowFi( componentDir.absoluteFilePath( slideshowPath ) );
|
QFileInfo slideshowFi( componentDir.absoluteFilePath( slideshowPath ) );
|
||||||
if ( !slideshowFi.exists() || !slideshowFi.fileName().toLower().endsWith( ".qml" ) )
|
if ( !slideshowFi.exists() || !slideshowFi.fileName().toLower().endsWith( ".qml" ) )
|
||||||
bail( QString( "Slideshow file %1 does not exist or is not a valid QML file." )
|
bail( m_descriptorPath,
|
||||||
|
QString( "Slideshow file %1 does not exist or is not a valid QML file." )
|
||||||
.arg( slideshowFi.absoluteFilePath() ) );
|
.arg( slideshowFi.absoluteFilePath() ) );
|
||||||
m_slideshowPath = 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
|
||||||
{
|
{
|
||||||
bail( "Syntax error in slideshow sequence." );
|
bail( m_descriptorPath, "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 )
|
||||||
{
|
{
|
||||||
CalamaresUtils::explainYamlException( e, ba, file.fileName() );
|
CalamaresUtils::explainYamlException( e, ba, file.fileName() );
|
||||||
bail( e.what() );
|
bail( m_descriptorPath, e.what() );
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir translationsDir( componentDir.filePath( "lang" ) );
|
QDir translationsDir( componentDir.filePath( "lang" ) );
|
||||||
@ -540,12 +553,4 @@ Branding::initSimpleSettings( const YAML::Node& doc )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[[noreturn]] void
|
|
||||||
Branding::bail( const QString& message )
|
|
||||||
{
|
|
||||||
cError() << "FATAL in" << m_descriptorPath << Logger::Continuation << Logger::NoQuote {} << message;
|
|
||||||
::exit( EXIT_FAILURE );
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Calamares
|
} // namespace Calamares
|
||||||
|
@ -165,8 +165,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
QString translationsDirectory() const { return m_translationsPathPrefix; }
|
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; }
|
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; }
|
int slideshowAPI() const { return m_slideshowAPI; }
|
||||||
|
|
||||||
QPixmap image( Branding::ImageEntry imageEntry, const QSize& size ) const;
|
QPixmap image( Branding::ImageEntry imageEntry, const QSize& size ) const;
|
||||||
@ -230,13 +238,21 @@ private:
|
|||||||
static const QStringList s_imageEntryStrings;
|
static const QStringList s_imageEntryStrings;
|
||||||
static const QStringList s_styleEntryStrings;
|
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_descriptorPath; // Path to descriptor (e.g. "/etc/calamares/default/branding.desc")
|
||||||
QString m_componentName; // Matches last part of full path to containing directory
|
QString m_componentName; // Matches last part of full path to containing directory
|
||||||
QMap< QString, QString > m_strings;
|
QMap< QString, QString > m_strings;
|
||||||
QMap< QString, QString > m_images;
|
QMap< QString, QString > m_images;
|
||||||
QMap< QString, QString > m_style;
|
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;
|
QString m_slideshowPath;
|
||||||
int m_slideshowAPI;
|
int m_slideshowAPI;
|
||||||
QString m_translationsPathPrefix;
|
QString m_translationsPathPrefix;
|
||||||
|
@ -19,6 +19,7 @@ set( calamaresui_SOURCES
|
|||||||
viewpages/BlankViewStep.cpp
|
viewpages/BlankViewStep.cpp
|
||||||
viewpages/ExecutionViewStep.cpp
|
viewpages/ExecutionViewStep.cpp
|
||||||
viewpages/QmlViewStep.cpp
|
viewpages/QmlViewStep.cpp
|
||||||
|
viewpages/Slideshow.cpp
|
||||||
viewpages/ViewStep.cpp
|
viewpages/ViewStep.cpp
|
||||||
|
|
||||||
widgets/ClickableLabel.cpp
|
widgets/ClickableLabel.cpp
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include "ExecutionViewStep.h"
|
#include "ExecutionViewStep.h"
|
||||||
|
|
||||||
|
#include "Slideshow.h"
|
||||||
|
|
||||||
#include "Branding.h"
|
#include "Branding.h"
|
||||||
#include "Job.h"
|
#include "Job.h"
|
||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
@ -37,12 +39,26 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QProgressBar>
|
#include <QProgressBar>
|
||||||
#include <QQmlComponent>
|
|
||||||
#include <QQmlEngine>
|
|
||||||
#include <QQuickItem>
|
|
||||||
#include <QQuickWidget>
|
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
|
static Calamares::Slideshow*
|
||||||
|
makeSlideshow( QWidget* parent )
|
||||||
|
{
|
||||||
|
const int api = Calamares::Branding::instance()->slideshowAPI();
|
||||||
|
switch ( api )
|
||||||
|
{
|
||||||
|
case -1:
|
||||||
|
return new Calamares::SlideshowPictures( parent );
|
||||||
|
case 1:
|
||||||
|
FALLTHRU;
|
||||||
|
case 2:
|
||||||
|
return new Calamares::SlideshowQML( parent );
|
||||||
|
default:
|
||||||
|
cWarning() << "Unknown Branding slideshow API" << api;
|
||||||
|
return new Calamares::SlideshowPictures( parent );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace Calamares
|
namespace Calamares
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -51,20 +67,14 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent )
|
|||||||
, m_widget( new QWidget )
|
, m_widget( new QWidget )
|
||||||
, m_progressBar( new QProgressBar )
|
, m_progressBar( new QProgressBar )
|
||||||
, m_label( new QLabel )
|
, m_label( new QLabel )
|
||||||
, m_qmlShow( new QQuickWidget )
|
, m_slideshow( makeSlideshow( m_widget ) )
|
||||||
, m_qmlComponent( nullptr )
|
|
||||||
, m_qmlObject( nullptr )
|
|
||||||
{
|
{
|
||||||
QVBoxLayout* layout = new QVBoxLayout( m_widget );
|
QVBoxLayout* layout = new QVBoxLayout( m_widget );
|
||||||
QVBoxLayout* innerLayout = new QVBoxLayout;
|
QVBoxLayout* innerLayout = new QVBoxLayout;
|
||||||
|
|
||||||
m_progressBar->setMaximum( 10000 );
|
m_progressBar->setMaximum( 10000 );
|
||||||
|
|
||||||
m_qmlShow->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
|
layout->addWidget( m_slideshow->widget() );
|
||||||
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 );
|
||||||
|
|
||||||
@ -72,17 +82,7 @@ ExecutionViewStep::ExecutionViewStep( QObject* parent )
|
|||||||
innerLayout->addWidget( m_progressBar );
|
innerLayout->addWidget( m_progressBar );
|
||||||
innerLayout->addWidget( m_label );
|
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 );
|
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 +139,10 @@ ExecutionViewStep::isAtEnd() const
|
|||||||
return !JobQueue::instance()->isRunning();
|
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
|
void
|
||||||
ExecutionViewStep::onActivate()
|
ExecutionViewStep::onActivate()
|
||||||
{
|
{
|
||||||
changeSlideShowState( Slideshow::Start, m_qmlObject, m_qmlShow );
|
m_slideshow->changeSlideShowState( Slideshow::Start );
|
||||||
|
|
||||||
JobQueue* queue = JobQueue::instance();
|
JobQueue* queue = JobQueue::instance();
|
||||||
foreach ( const QString& instanceKey, m_jobInstanceKeys )
|
foreach ( const QString& instanceKey, m_jobInstanceKeys )
|
||||||
@ -288,13 +190,7 @@ ExecutionViewStep::updateFromJobQueue( qreal percent, const QString& message )
|
|||||||
void
|
void
|
||||||
ExecutionViewStep::onLeave()
|
ExecutionViewStep::onLeave()
|
||||||
{
|
{
|
||||||
changeSlideShowState( Slideshow::Stop, m_qmlObject, m_qmlShow );
|
m_slideshow->changeSlideShowState( Slideshow::Stop );
|
||||||
// API version 2 is explicitly stopped; version 1 keeps running
|
|
||||||
if ( Branding::instance()->slideshowAPI() == 2 )
|
|
||||||
{
|
|
||||||
delete m_qmlObject;
|
|
||||||
m_qmlObject = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Calamares
|
} // namespace Calamares
|
||||||
|
@ -27,13 +27,12 @@
|
|||||||
class QLabel;
|
class QLabel;
|
||||||
class QObject;
|
class QObject;
|
||||||
class QProgressBar;
|
class QProgressBar;
|
||||||
class QQmlComponent;
|
|
||||||
class QQuickItem;
|
|
||||||
class QQuickWidget;
|
|
||||||
|
|
||||||
namespace Calamares
|
namespace Calamares
|
||||||
{
|
{
|
||||||
|
|
||||||
|
class Slideshow;
|
||||||
|
|
||||||
class ExecutionViewStep : public ViewStep
|
class ExecutionViewStep : public ViewStep
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -60,20 +59,14 @@ public:
|
|||||||
|
|
||||||
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_qmlShow;
|
Slideshow* m_slideshow;
|
||||||
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 );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
258
src/libcalamaresui/viewpages/Slideshow.cpp
Normal file
258
src/libcalamaresui/viewpages/Slideshow.cpp
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
|
*
|
||||||
|
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
|
||||||
|
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
|
||||||
|
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||||
|
*
|
||||||
|
* Calamares is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Calamares is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Slideshow.h"
|
||||||
|
|
||||||
|
#include "Branding.h"
|
||||||
|
#include "utils/Dirs.h"
|
||||||
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/Qml.h"
|
||||||
|
#include "utils/Retranslator.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMutexLocker>
|
||||||
|
#include <QQmlComponent>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
#include <QQuickItem>
|
||||||
|
#include <QQuickWidget>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace Calamares
|
||||||
|
{
|
||||||
|
|
||||||
|
Slideshow::~Slideshow() {}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
142
src/libcalamaresui/viewpages/Slideshow.h
Normal file
142
src/libcalamaresui/viewpages/Slideshow.h
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
|
*
|
||||||
|
* Copyright 2014, Aurélien Gâteau <agateau@kde.org>
|
||||||
|
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
|
||||||
|
* Copyright 2018, Adriaan de Groot <groot@kde.org>
|
||||||
|
*
|
||||||
|
* Calamares is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Calamares is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBCALAMARESUI_SLIDESHOW_H
|
||||||
|
#define LIBCALAMARESUI_SLIDESHOW_H
|
||||||
|
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
class QTimer;
|
||||||
|
class QQmlComponent;
|
||||||
|
class QQuickItem;
|
||||||
|
class QQuickWidget;
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @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
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @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
|
Loading…
Reference in New Issue
Block a user