qt/dialogmodel: Update error handling before the GUI display

Signed-off-by: Pierre Lamot <pierre@videolabs.io>
This commit is contained in:
Benjamin Arnaud 2021-03-18 10:36:27 +01:00 committed by Pierre Lamot
parent fa26844047
commit 7695e065e8
3 changed files with 300 additions and 106 deletions

View File

@ -1,5 +1,7 @@
/*****************************************************************************
* Copyright (C) 2019 VLC authors and VideoLAN
* Copyright (C) 2021 VLC authors and VideoLAN
*
* Authors: Benjamin Arnaud <bunjee@omega.gg>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -15,99 +17,195 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#include "dialogmodel.hpp"
static void displayErrorCb(void *p_data, const char *psz_title, const char *psz_text)
// VLC includes
#include <vlc_dialog.h>
#include <qt.hpp>
//=================================================================================================
// DialogErrorModel
//=================================================================================================
/* explicit */ DialogErrorModel::DialogErrorModel(QObject * parent) : QAbstractListModel(parent) {}
//-------------------------------------------------------------------------------------------------
// QAbstractItemModel implementation
//-------------------------------------------------------------------------------------------------
QVariant DialogErrorModel::data(const QModelIndex & index, int role) const /* override */
{
DialogModel* that = static_cast<DialogModel*>(p_data);
emit that->errorDisplayed(psz_title, psz_text);
int row = index.row();
if (row < 0 || row >= m_data.count())
return QVariant();
switch (role)
{
case DIALOG_TITLE:
return QVariant::fromValue(m_data.at(row).title);
case DIALOG_TEXT:
return QVariant::fromValue(m_data.at(row).text);
default:
return QVariant();
}
}
static void displayLoginCb(void *p_data, vlc_dialog_id *dialogId,
const char *psz_title, const char *psz_text,
const char *psz_default_username,
bool b_ask_store)
int DialogErrorModel::rowCount(const QModelIndex &) const /* override */
{
DialogModel* that = static_cast<DialogModel*>(p_data);
emit that->loginDisplayed( dialogId, psz_title, psz_text, psz_default_username, b_ask_store );
return count();
}
static void displayQuestionCb(void *p_data, vlc_dialog_id *dialogId,
const char *psz_title, const char *psz_text,
vlc_dialog_question_type i_type,
const char *psz_cancel, const char *psz_action1,
const char *psz_action2)
//-------------------------------------------------------------------------------------------------
// QAbstractItemModel reimplementation
//-------------------------------------------------------------------------------------------------
QHash<int, QByteArray> DialogErrorModel::roleNames() const /* override */
{
DialogModel* that = static_cast<DialogModel*>(p_data);
emit that->questionDisplayed( dialogId, psz_title, psz_text, static_cast<int>(i_type), psz_cancel, psz_action1, psz_action2 );
return
{
{ DialogErrorModel::DIALOG_TITLE, "title" },
{ DialogErrorModel::DIALOG_TEXT, "text" }
};
}
static void displayProgressCb(void *p_data, vlc_dialog_id *dialogId,
const char *psz_title, const char *psz_text,
bool b_indeterminate, float f_position,
const char *psz_cancel)
//-------------------------------------------------------------------------------------------------
// Private functions
//-------------------------------------------------------------------------------------------------
void DialogErrorModel::pushError(const DialogError & error)
{
DialogModel* that = static_cast<DialogModel*>(p_data);
emit that->progressDisplayed( dialogId, psz_title, psz_text, b_indeterminate, f_position, psz_cancel);
int row = m_data.count();
beginInsertRows(QModelIndex(), row, row);
m_data.append(error);
endInsertRows();
emit countChanged();
}
static void cancelCb(void *p_data, vlc_dialog_id *dialogId)
//-------------------------------------------------------------------------------------------------
// Properties
//-------------------------------------------------------------------------------------------------
int DialogErrorModel::count() const
{
DialogModel* that = static_cast<DialogModel*>(p_data);
emit that->cancelled(dialogId);
return m_data.count();
}
static void updateProgressCb(void *p_data, vlc_dialog_id *dialogId, float f_value, const char *psz_text)
//=================================================================================================
// DialogModel
//=================================================================================================
/* explicit */ DialogModel::DialogModel(intf_thread_t * intf, QObject * parent)
: QObject(parent), m_intf(intf)
{
DialogModel* that = static_cast<DialogModel*>(p_data);
emit that->progressUpdated( dialogId, f_value, psz_text );
m_model = new DialogErrorModel(this);
const vlc_dialog_cbs cbs =
{
onError, onLogin, onQuestion, onProgress, onCancelled, onProgressUpdated
};
vlc_dialog_provider_set_callbacks(intf, &cbs, this);
}
const vlc_dialog_cbs cbs = {
displayErrorCb,
displayLoginCb,
displayQuestionCb,
displayProgressCb,
cancelCb,
updateProgressCb
};
//-------------------------------------------------------------------------------------------------
// Interface
//-------------------------------------------------------------------------------------------------
DialogModel::DialogModel(QObject *parent)
: QObject(parent)
{
}
DialogModel::~DialogModel()
{
if (m_mainCtx)
vlc_dialog_provider_set_callbacks(m_mainCtx->getIntf(), nullptr, nullptr);
}
void DialogModel::dismiss(DialogId dialogId)
{
vlc_dialog_id_dismiss(dialogId.m_id);
}
void DialogModel::post_login(DialogId dialogId, const QString& username, const QString& password, bool store)
/* Q_INVOKABLE */ void DialogModel::post_login(DialogId dialogId, const QString & username,
const QString & password, bool store)
{
vlc_dialog_id_post_login(dialogId.m_id, qtu(username), qtu(password), store);
}
void DialogModel::post_action1(DialogId dialogId)
/* Q_INVOKABLE */ void DialogModel::post_action1(DialogId dialogId)
{
vlc_dialog_id_post_action(dialogId.m_id, 1);
}
void DialogModel::post_action2(DialogId dialogId)
/* Q_INVOKABLE */ void DialogModel::post_action2(DialogId dialogId)
{
vlc_dialog_id_post_action(dialogId.m_id, 2);
}
void DialogModel::setMainCtx(QmlMainContext* ctx)
/* Q_INVOKABLE */ void DialogModel::dismiss(DialogId dialogId)
{
if (ctx)
vlc_dialog_provider_set_callbacks(ctx->getIntf(), &cbs, this);
else if (m_mainCtx)
vlc_dialog_provider_set_callbacks(m_mainCtx->getIntf(), nullptr, nullptr);
m_mainCtx = ctx;
vlc_dialog_id_dismiss(dialogId.m_id);
}
//-------------------------------------------------------------------------------------------------
// Private static functions
//-------------------------------------------------------------------------------------------------
/* static */ void DialogModel::onError(void * p_data,
const char * psz_title, const char * psz_text)
{
DialogModel * model = static_cast<DialogModel *>(p_data);
DialogErrorModel::DialogError error { psz_title, psz_text };
QMetaObject::invokeMethod(model, [model, error = std::move(error)]()
{
model->m_model->pushError(error);
});
}
/* static */ void DialogModel::onLogin(void * p_data, vlc_dialog_id * dialogId,
const char * psz_title, const char * psz_text,
const char * psz_default_username, bool b_ask_store)
{
DialogModel * model = static_cast<DialogModel *>(p_data);
emit model->login(dialogId, psz_title, psz_text, psz_default_username, b_ask_store);
}
/* static */ void DialogModel::onQuestion(void * p_data, vlc_dialog_id * dialogId,
const char * psz_title, const char * psz_text,
vlc_dialog_question_type i_type,
const char * psz_cancel, const char * psz_action1,
const char * psz_action2)
{
DialogModel * model = static_cast<DialogModel *>(p_data);
emit model->question(dialogId, psz_title, psz_text, static_cast<int>(i_type), psz_cancel,
psz_action1, psz_action2);
}
/* static */ void DialogModel::onProgress(void * p_data, vlc_dialog_id * dialogId,
const char * psz_title, const char * psz_text,
bool b_indeterminate, float f_position,
const char * psz_cancel)
{
DialogModel * model = static_cast<DialogModel *>(p_data);
emit model->progress(dialogId, psz_title, psz_text, b_indeterminate, f_position, psz_cancel);
}
/* static */ void DialogModel::onProgressUpdated(void * p_data, vlc_dialog_id * dialogId,
float f_value, const char * psz_text)
{
DialogModel * model = static_cast<DialogModel *>(p_data);
emit model->progressUpdated(dialogId, f_value, psz_text);
}
/* static */ void DialogModel::onCancelled(void * p_data, vlc_dialog_id * dialogId)
{
DialogModel * model = static_cast<DialogModel *>(p_data);
emit model->cancelled(dialogId);
}
//-------------------------------------------------------------------------------------------------
// Properties
//-------------------------------------------------------------------------------------------------
DialogErrorModel * DialogModel::model() const
{
return m_model;
}

View File

@ -1,5 +1,7 @@
/*****************************************************************************
* Copyright (C) 2019 VLC authors and VideoLAN
* Copyright (C) 2021 VLC authors and VideoLAN
*
* Authors: Benjamin Arnaud <bunjee@omega.gg>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -15,6 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef DIALOGMODEL_HPP
#define DIALOGMODEL_HPP
@ -22,79 +25,169 @@
# include "config.h"
#endif
// VLC includes
#include <vlc_common.h>
#include <vlc_dialog.h>
#include <QObject>
// Qt includes
#include <QAbstractListModel>
#include "util/qml_main_context.hpp"
// Forward declarations
class DialogModel;
//-------------------------------------------------------------------------------------------------
// DialogId
//-------------------------------------------------------------------------------------------------
class DialogId {
class DialogId
{
Q_GADGET
public:
DialogId(vlc_dialog_id * id = nullptr)
: m_id(id)
{}
bool operator ==(const DialogId& other) const {
public:
DialogId(vlc_dialog_id * id = nullptr) : m_id(id) {}
public: // Operators
bool operator ==(const DialogId & other) const
{
return m_id == other.m_id;
}
vlc_dialog_id *m_id;
public: // Variables
vlc_dialog_id * m_id;
};
Q_DECLARE_METATYPE(DialogId)
//-------------------------------------------------------------------------------------------------
// DialogErrorModel
//-------------------------------------------------------------------------------------------------
class DialogErrorModel : public QAbstractListModel
{
Q_OBJECT
Q_ENUMS(DialogRoles)
Q_PROPERTY(int count READ count NOTIFY countChanged)
public: // Enums
enum DialogRoles
{
DIALOG_TITLE = Qt::UserRole + 1,
DIALOG_TEXT
};
private:
struct DialogError
{
QString title;
QString text;
};
public:
explicit DialogErrorModel(QObject * parent = nullptr);
public: // QAbstractItemModel implementation
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex & parent = QModelIndex()) const override;
public: // QAbstractItemModel reimplementation
QHash<int, QByteArray> roleNames() const override;
private: // Functions
void pushError(const DialogError & error);
signals:
void modelChanged();
void countChanged();
public: // Properties
int count() const;
private: // Variables
QList<DialogError> m_data;
private:
friend class DialogModel;
};
//-------------------------------------------------------------------------------------------------
// DialogModel
//-------------------------------------------------------------------------------------------------
class DialogModel : public QObject
{
Q_OBJECT
public:
Q_PROPERTY(QmlMainContext* mainCtx READ getMainCtx WRITE setMainCtx NOTIFY mainCtxChanged)
Q_ENUMS(QuestionType)
enum QuestionType {
QUESTION_NORMAL,
QUESTION_WARNING,
QUESTION_CRITICAL
};
Q_ENUM(QuestionType)
Q_PROPERTY(DialogErrorModel * model READ model CONSTANT)
public: // Enums
// NOTE: Is it really useful to have this declared here ?
enum QuestionType { QUESTION_NORMAL, QUESTION_WARNING, QUESTION_CRITICAL };
public:
explicit DialogModel(QObject *parent = nullptr);
~DialogModel();
explicit DialogModel(intf_thread_t * intf, QObject * parent = nullptr);
inline QmlMainContext* getMainCtx() const { return m_mainCtx; }
void setMainCtx(QmlMainContext*);
public: // Interface
Q_INVOKABLE void post_login(DialogId dialogId, const QString & username,
const QString & password, bool store = false);
signals:
void errorDisplayed(const QString &title, const QString &text);
void loginDisplayed(DialogId dialogId, const QString &title,
const QString &text, const QString &defaultUsername,
Q_INVOKABLE void post_action1(DialogId dialogId);
Q_INVOKABLE void post_action2(DialogId dialogId);
Q_INVOKABLE void dismiss(DialogId dialogId);
private: // Static functions
static void onError(void * p_data, const char * psz_title, const char * psz_text);
static void onLogin(void * p_data, vlc_dialog_id * dialogId, const char * psz_title,
const char * psz_text, const char * psz_default_username,
bool b_ask_store);
void questionDisplayed(DialogId dialogId, const QString &title,
const QString &text, int type,
const QString &cancel, const QString &action1,
const QString &action2);
static void onQuestion(void * p_data, vlc_dialog_id * dialogId, const char * psz_title,
const char * psz_text, vlc_dialog_question_type i_type,
const char * psz_cancel, const char * psz_action1,
const char * psz_action2);
void progressDisplayed(DialogId dialogId, const QString &title,
const QString &text, bool b_indeterminate,
float f_position, const QString &cancel);
static void onProgress(void * p_data, vlc_dialog_id * dialogId, const char * psz_title,
const char * psz_text, bool b_indeterminate, float f_position,
const char *psz_cancel);
static void onProgressUpdated(void * p_data, vlc_dialog_id * dialogId, float f_value,
const char * psz_text);
static void onCancelled(void * p_data, vlc_dialog_id * dialogId);
signals:
void errorBegin();
void errorEnd ();
void login(DialogId dialogId, const QString & title,
const QString & text, const QString & defaultUsername,
bool b_ask_store);
void question(DialogId dialogId, const QString & title, const QString & text, int type,
const QString & cancel, const QString & action1, const QString & action2);
void progress(DialogId dialogId, const QString & title, const QString & text,
bool b_indeterminate, float f_position, const QString & cancel);
void progressUpdated(DialogId dialogId, float f_value, const QString & text);
void cancelled(DialogId dialogId);
void progressUpdated(DialogId dialogId, float f_value, const QString &text);
public: // Properties
DialogErrorModel * model() const;
void mainCtxChanged();
private: // Variables
DialogErrorModel * m_model;
public slots:
void dismiss(DialogId dialogId);
void post_login(DialogId dialogId, const QString& username, const QString& password, bool store = false);
void post_action1(DialogId dialogId);
void post_action2(DialogId dialogId);
private:
QmlMainContext* m_mainCtx;
intf_thread_t * m_intf;
};
#endif // DIALOGMODEL_HPP

View File

@ -103,6 +103,7 @@ bool MainUI::setup(QQmlEngine* engine)
rootCtx->setContextProperty( "topWindow", m_interfaceWindow);
rootCtx->setContextProperty( "dialogProvider", DialogsProvider::getInstance());
rootCtx->setContextProperty( "systemPalette", new SystemPalette(this));
rootCtx->setContextProperty( "dialogModel", new DialogModel(m_intf, this));
if (m_mainInterface->hasMediaLibrary())
rootCtx->setContextProperty( "medialib", m_mainInterface->getMediaLibrary() );
@ -227,8 +228,10 @@ void MainUI::registerQMLTypes()
qmlRegisterType<PlaylistControllerModel>( "org.videolan.vlc", 0, 1, "PlaylistControllerModel" );
qmlRegisterType<AboutModel>( "org.videolan.vlc", 0, 1, "AboutModel" );
qmlRegisterUncreatableType<DialogModel>("org.videolan.vlc", 0, 1, "DialogModel", "");
qmlRegisterUncreatableType<DialogErrorModel>( "org.videolan.vlc", 0, 1, "DialogErrorModel", "");
qRegisterMetaType<DialogId>();
qmlRegisterType<DialogModel>("org.videolan.vlc", 0, 1, "DialogModel");
qmlRegisterType<QmlEventFilter>( "org.videolan.vlc", 0, 1, "EventFilter" );