Browse Source

added basic message box

pull/2/head
Skycoder42 7 years ago
parent
commit
52ac17864b
  1. 78
      src/imports/mvvmcore/plugins.qmltypes
  2. 7
      src/imports/mvvmcore/qtmvvmcore_plugin.cpp
  3. 32
      src/imports/mvvmquick/DialogPresenter.qml
  4. 128
      src/imports/mvvmquick/MsgBox.qml
  5. 15
      src/imports/mvvmquick/QtMvvmApp.qml
  6. 39
      src/imports/mvvmquick/TintIcon.qml
  7. 5
      src/imports/mvvmquick/mvvmquick.pro
  8. 4
      src/imports/mvvmquick/qmldir
  9. 25
      src/imports/mvvmquick/qqmlquickpresenter.cpp
  10. 2
      src/imports/mvvmquick/qqmlquickpresenter.h
  11. 16
      src/mvvmcore/message.cpp
  12. 5
      src/mvvmcore/message.h
  13. 7
      src/mvvmquick/quickpresenter.cpp

78
src/imports/mvvmcore/plugins.qmltypes

@ -8,6 +8,84 @@ import QtQuick.tooling 1.2
Module { Module {
dependencies: ["QtQuick 2.8"] dependencies: ["QtQuick 2.8"]
Component {
name: "QtMvvm::MessageConfig"
exports: ["de.skycoder42.QtMvvm.Core/MessageConfig 1.0"]
isCreatable: false
exportMetaObjectRevisions: [0]
Enum {
name: "StandardButtons"
values: {
"NoButton": 0,
"Ok": 1024,
"Save": 2048,
"SaveAll": 4096,
"Open": 8192,
"Yes": 16384,
"YesToAll": 32768,
"No": 65536,
"NoToAll": 131072,
"Abort": 262144,
"Retry": 524288,
"Ignore": 1048576,
"Close": 2097152,
"Cancel": 4194304,
"Discard": 8388608,
"Help": 16777216,
"Apply": 33554432,
"Reset": 67108864,
"RestoreDefaults": 134217728
}
}
Property { name: "type"; type: "QByteArray" }
Property { name: "subType"; type: "QByteArray" }
Property { name: "title"; type: "string" }
Property { name: "text"; type: "string" }
Property { name: "buttons"; type: "StandardButtons" }
Property { name: "buttonTexts"; type: "QVariantMap" }
Property { name: "defaultValue"; type: "QVariant" }
Property { name: "viewProperties"; type: "QVariantMap" }
}
Component {
name: "QtMvvm::MessageResult"
prototype: "QObject"
exports: ["de.skycoder42.QtMvvm.Core/MessageResult 1.0"]
isCreatable: false
exportMetaObjectRevisions: [0]
Property { name: "result"; type: "QVariant" }
Property { name: "autoDelete"; type: "bool" }
Signal {
name: "dialogDone"
Parameter { name: "result"; type: "QtMvvm::MessageConfig::StandardButton" }
}
Signal {
name: "autoDeleteChanged"
Parameter { name: "autoDelete"; type: "bool" }
}
Method { name: "discardMessage" }
Method {
name: "setResult"
Parameter { name: "result"; type: "QVariant" }
}
Method {
name: "setAutoDelete"
Parameter { name: "autoDelete"; type: "bool" }
}
Method {
name: "setCloseTarget"
Parameter { name: "closeObject"; type: "QObject"; isPointer: true }
Parameter { name: "closeMethod"; type: "QMetaMethod" }
}
Method {
name: "complete"
Parameter { name: "result"; type: "QtMvvm::MessageConfig::StandardButton" }
}
Method {
name: "complete"
Parameter { name: "result"; type: "QtMvvm::MessageConfig::StandardButton" }
Parameter { name: "resultValue"; type: "QVariant" }
}
}
Component { Component {
name: "QtMvvm::QQmlMvvmBinding" name: "QtMvvm::QQmlMvvmBinding"
prototype: "QObject" prototype: "QObject"

7
src/imports/mvvmcore/qtmvvmcore_plugin.cpp

@ -3,6 +3,7 @@
#include <QtQml> #include <QtQml>
#include <QtMvvmCore/ViewModel> #include <QtMvvmCore/ViewModel>
#include <QtMvvmCore/Messages>
#include "qqmlmvvmbinding.h" #include "qqmlmvvmbinding.h"
#include "qqmlmvvmmessage.h" #include "qqmlmvvmmessage.h"
@ -21,8 +22,12 @@ void QtMvvmCoreDeclarativeModule::registerTypes(const char *uri)
Q_ASSERT(qstrcmp(uri, "de.skycoder42.QtMvvm.Core") == 0); Q_ASSERT(qstrcmp(uri, "de.skycoder42.QtMvvm.Core") == 0);
//Version 1.0 //Version 1.0
qmlRegisterUncreatableType<QtMvvm::ViewModel>(uri, 1, 0, "ViewModel", tr("ViewModels cannot be created from QML")); qmlRegisterUncreatableType<QtMvvm::MessageConfig>(uri, 1, 0, "MessageConfig", QStringLiteral("Q_GADGETS cannot be created from QML"));
qmlRegisterUncreatableType<QtMvvm::MessageResult>(uri, 1, 0, "MessageResult", QStringLiteral("Message results must be passed from C++"));
qmlRegisterUncreatableType<QtMvvm::ViewModel>(uri, 1, 0, "ViewModel", QStringLiteral("ViewModels cannot be created from QML"));
qmlRegisterType<QtMvvm::QQmlMvvmBinding>(uri, 1, 0, "MvvmBinding"); qmlRegisterType<QtMvvm::QQmlMvvmBinding>(uri, 1, 0, "MvvmBinding");
qmlRegisterSingletonType<QtMvvm::QQmlMvvmMessage>(uri, 1, 0, "Message", createMessageSingleton); qmlRegisterSingletonType<QtMvvm::QQmlMvvmMessage>(uri, 1, 0, "Message", createMessageSingleton);
// Check to make shure no module update is forgotten // Check to make shure no module update is forgotten

32
src/imports/mvvmquick/DialogPresenter.qml

@ -0,0 +1,32 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import de.skycoder42.QtMvvm.Core 1.0
QtObject {
id: _dialogPresenter
property Item rootItem: null
function showDialog(config, result) {
if(config.type == "msgbox") {
createMsgBox(config, result)
return true;
} else
return false;
}
property Component _msgBoxComponent: Component {
MsgBox {
id: __msgBox
Component.onCompleted: __msgBox.open()
}
}
function createMsgBox(config, result) {
var props = config.viewProperties;
props["msgConfig"] = config;
props["msgResult"] = result;
var incubator = _msgBoxComponent.incubateObject(rootItem, props);
return incubator.status !== Component.Error;
}
}

128
src/imports/mvvmquick/MsgBox.qml

@ -0,0 +1,128 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import de.skycoder42.QtMvvm.Core 1.0
Dialog {
id: _msgBox
property var msgConfig
property MessageResult msgResult
property real extraHeight: 0
x: parent ? (parent.width - width) / 2 : 0
y: parent ? deltaY() : 0
width: parent ? Math.min(Math.max(implicitWidth, 300), parent.width - 28) : implicitWidth
height: parent ? Math.min(implicitHeight, parent.height - 28) : implicitWidth
modal: true
focus: true
closePolicy: Popup.CloseOnEscape
function deltaY() {
var unscaled = Qt.inputMethod.keyboardRectangle.height / Screen.devicePixelRatio;
var availHeight = (parent.height + extraHeight) - unscaled - 28;//spacing
var rawDelta = (Math.max(0, availHeight - height) / 2);
return rawDelta + 14 - extraHeight;//spacing
}
header: RowLayout {
spacing: 14
TintIcon {
id: icon
property int iconType
Layout.preferredWidth: 24
Layout.preferredHeight: 24
Layout.margins: 24
Layout.bottomMargin: 0
Layout.rightMargin: 0
visible: msgConfig.subType != "about"
source: {
var base = "image://svg/de/skycoder42/qtmvvm/quick/icons/ic_%1";
switch(msgConfig.subType) {
case "information":
base = base.arg("info");
break;
case "question":
base = base.arg("help");
break;
case "warning":
base = base.arg("warning");
break;
case "critical":
base = base.arg("error");
break;
case "about":
default:
return "";
}
return base;
}
}
Label {
text: msgConfig.title
visible: msgConfig.title
elide: Label.ElideRight
font.bold: true
font.pixelSize: 16
Layout.fillWidth: true
Layout.margins: 24
Layout.bottomMargin: 0
Layout.leftMargin: icon.visible ? 0 : 24
}
}
Label {
id: _contentLabel
text: msgConfig.text.replace(/<\/p>/g, "</p><br/>") //needed because qml does not put space between paragraphs...
visible: text != ""
anchors.fill: parent
wrapMode: Text.Wrap
onLinkActivated: Qt.openUrlExternally(link)
}
footer: DialogButtonBox {
id: _btnBox
readonly property var _allBtns: [
DialogButtonBox.NoButton,
DialogButtonBox.Ok,
DialogButtonBox.Save,
DialogButtonBox.SaveAll,
DialogButtonBox.Open,
DialogButtonBox.Yes,
DialogButtonBox.YesToAll,
DialogButtonBox.No,
DialogButtonBox.NoToAll,
DialogButtonBox.Abort,
DialogButtonBox.Retry,
DialogButtonBox.Ignore,
DialogButtonBox.Close,
DialogButtonBox.Cancel,
DialogButtonBox.Discard,
DialogButtonBox.Help,
DialogButtonBox.Apply,
DialogButtonBox.Reset,
DialogButtonBox.RestoreDefaults,
]
standardButtons: msgConfig.buttons
onStandardButtonsChanged: {
for(var key in msgConfig.buttonTexts)
standardButton(DialogButtonBox.Ok).text = msgConfig.buttonTexts[key]
}
onClicked: {
if(msgResult) {
_allBtns.forEach(function(sBtn) {
if(button === standardButton(sBtn))
msgResult.complete(sBtn)
})
}
}
}
}

15
src/imports/mvvmquick/QtMvvmApp.qml

@ -13,13 +13,18 @@ ApplicationWindow {
z: _rootStack.empty ? 10 : -10 z: _rootStack.empty ? 10 : -10
} }
PresentingStackView {
id: _rootStack
anchors.fill: parent
}
PopupPresenter { PopupPresenter {
id: _rootPopup id: _rootPopup
} }
PresentingStackView { DialogPresenter {
id: _rootStack id: _dialogs
anchors.fill: parent rootItem: _root.contentItem
} }
function presentDrawerContent(item) { function presentDrawerContent(item) {
@ -34,6 +39,10 @@ ApplicationWindow {
return _rootPopup.presentPopup(contentItem, popup); return _rootPopup.presentPopup(contentItem, popup);
} }
function showDialog(config, result) {
return _dialogs.showDialog(config, result);
}
Component.onCompleted: QuickPresenter.qmlPresenter = _root Component.onCompleted: QuickPresenter.qmlPresenter = _root
onClosing: { onClosing: {

39
src/imports/mvvmquick/TintIcon.qml

@ -0,0 +1,39 @@
import QtQuick 2.10
import QtQuick.Controls.Material 2.3
import QtQuick.Controls.Universal 2.3
import QtGraphicalEffects 1.0
import de.skycoder42.QtMvvm.Quick 1.0
Item {
id: _tintIcon
property size iconSize: Qt.size(24, 24)
property alias tintColor: _overlay.color
property alias source: _image.source
Image {
id: _image
anchors.centerIn: parent
fillMode: Image.PreserveAspectFit
horizontalAlignment: Image.AlignHCenter
verticalAlignment: Image.AlignVCenter
width: iconSize.width
height: iconSize.height
sourceSize: iconSize
visible: false
}
ColorOverlay {
id: _overlay
anchors.fill: _image
source: _image
color: {
if(QuickPresenter.currentStyle === "Material")
return Material.foreground;
else if(QuickPresenter.currentStyle === "Universal")
return Universal.foreground;
else
return "black";
}
}
}

5
src/imports/mvvmquick/mvvmquick.pro

@ -18,7 +18,10 @@ QML_FILES += \
QtMvvmApp.qml \ QtMvvmApp.qml \
PresentingStackView.qml \ PresentingStackView.qml \
PresenterProgress.qml \ PresenterProgress.qml \
PopupPresenter.qml PopupPresenter.qml \
DialogPresenter.qml \
TintIcon.qml \
MsgBox.qml
OTHER_FILES += qmldir OTHER_FILES += qmldir

4
src/imports/mvvmquick/qmldir

@ -3,8 +3,12 @@ plugin declarative_mvvmquick
classname QtMvvmQuickDeclarativeModule classname QtMvvmQuickDeclarativeModule
typeinfo plugins.qmltypes typeinfo plugins.qmltypes
internal TintIcon TintIcon.qml
internal MsgBox MsgBox.qml
PresenterProgress 1.0 PresenterProgress.qml PresenterProgress 1.0 PresenterProgress.qml
PresentingStackView 1.0 PresentingStackView.qml PresentingStackView 1.0 PresentingStackView.qml
PopupPresenter 1.0 PopupPresenter.qml PopupPresenter 1.0 PopupPresenter.qml
DialogPresenter 1.0 DialogPresenter.qml
QtMvvmApp 1.0 QtMvvmApp.qml QtMvvmApp 1.0 QtMvvmApp.qml

25
src/imports/mvvmquick/qqmlquickpresenter.cpp

@ -60,6 +60,25 @@ void QQmlQuickPresenter::present(ViewModel *viewModel, const QVariantHash &param
} }
} }
void QQmlQuickPresenter::showDialog(const MessageConfig &config, MessageResult *result)
{
if(!_qmlPresenter) {
qmlWarning(this).space() << "No QML-Presenter registered! Unable to present dialog of type" //TODO use via define EVERYWHERE!!!
<< config.type();
return;
}
QVariant res = false;
QMetaObject::invokeMethod(_qmlPresenter, "showDialog", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, res),
Q_ARG(QVariant, QVariant::fromValue(config)),
Q_ARG(QVariant, QVariant::fromValue(result)));
if(!res.toBool()) {
qmlWarning(this).space() << "Failed to present dialog of type"
<< config.type();
}
}
void QQmlQuickPresenter::statusChanged(QQmlComponent::Status status) void QQmlQuickPresenter::statusChanged(QQmlComponent::Status status)
{ {
auto component = qobject_cast<QQmlComponent*>(sender()); auto component = qobject_cast<QQmlComponent*>(sender());
@ -94,7 +113,7 @@ void QQmlQuickPresenter::statusChanged(QQmlComponent::Status status)
void QQmlQuickPresenter::addObject(QQmlComponent *component, ViewModel *viewModel, const QVariantHash &params, QPointer<ViewModel> parent) void QQmlQuickPresenter::addObject(QQmlComponent *component, ViewModel *viewModel, const QVariantHash &params, QPointer<ViewModel> parent)
{ {
if(!_qmlPresenter) { if(!_qmlPresenter) {
qCritical() << "No QML-Presenter registered! Unable to present control of type" qmlWarning(this).space() << "No QML-Presenter registered! Unable to present viewModel of type"
<< viewModel->metaObject()->className(); << viewModel->metaObject()->className();
return; return;
} }
@ -102,7 +121,7 @@ void QQmlQuickPresenter::addObject(QQmlComponent *component, ViewModel *viewMode
//create the view item, set initial stuff and them complete creation //create the view item, set initial stuff and them complete creation
auto item = component->beginCreate(_engine->rootContext()); auto item = component->beginCreate(_engine->rootContext());
if(!item) { if(!item) {
qmlWarning(this) << "Unable to create quick view from the loaded component" qmlWarning(this).space() << "Unable to create quick view from the loaded component"
<< component->url(); << component->url();
return; return;
} }
@ -122,7 +141,7 @@ void QQmlQuickPresenter::addObject(QQmlComponent *component, ViewModel *viewMode
if(!item->parent()) if(!item->parent())
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership); QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);
} else { } else {
qmlWarning(this) << "Failed to present item for viewModel of type" qmlWarning(this).space() << "Failed to present item for viewModel of type"
<< viewModel->metaObject()->className(); << viewModel->metaObject()->className();
item->deleteLater(); item->deleteLater();
} }

2
src/imports/mvvmquick/qqmlquickpresenter.h

@ -12,6 +12,7 @@
#include <QtQml/QQmlComponent> #include <QtQml/QQmlComponent>
#include <QtMvvmCore/ViewModel> #include <QtMvvmCore/ViewModel>
#include <QtMvvmCore/Messages>
namespace QtMvvm { namespace QtMvvm {
@ -40,6 +41,7 @@ Q_SIGNALS:
private Q_SLOTS: private Q_SLOTS:
void present(QtMvvm::ViewModel *viewModel, const QVariantHash &params, const QUrl &viewUrl, QPointer<QtMvvm::ViewModel> parent); void present(QtMvvm::ViewModel *viewModel, const QVariantHash &params, const QUrl &viewUrl, QPointer<QtMvvm::ViewModel> parent);
void showDialog(const QtMvvm::MessageConfig &config, QtMvvm::MessageResult *result);
void statusChanged(QQmlComponent::Status status); void statusChanged(QQmlComponent::Status status);
private: private:

16
src/mvvmcore/message.cpp

@ -158,6 +158,22 @@ void MessageConfig::resetButtons()
d->buttonTexts.clear(); d->buttonTexts.clear();
} }
QVariantMap MessageConfig::buttonTextsMap() const
{
QVariantMap map;
for(auto it = d->buttonTexts.constBegin(); it != d->buttonTexts.constEnd(); it++)
map.insert(QString::number(it.key()), it.value());
return map;
}
void MessageConfig::setButtonTextsMap(const QVariantMap &buttonTexts)
{
QHash<StandardButton, QString> map;
for(auto it = buttonTexts.constBegin(); it != buttonTexts.constEnd(); it++)
map.insert(static_cast<StandardButton>(it.key().toInt()), it.value().toString());
d->buttonTexts = map;
}
MessageResult::MessageResult() : MessageResult::MessageResult() :

5
src/mvvmcore/message.h

@ -25,7 +25,7 @@ class Q_MVVMCORE_EXPORT MessageConfig
Q_PROPERTY(QString title READ title WRITE setTitle) Q_PROPERTY(QString title READ title WRITE setTitle)
Q_PROPERTY(QString text READ text WRITE setText) Q_PROPERTY(QString text READ text WRITE setText)
Q_PROPERTY(StandardButtons buttons READ buttons WRITE setButtons RESET resetButtons) Q_PROPERTY(StandardButtons buttons READ buttons WRITE setButtons RESET resetButtons)
Q_PROPERTY(QHash<StandardButton, QString> buttonTexts READ buttonTexts WRITE setButtonTexts RESET resetButtons) Q_PROPERTY(QVariantMap buttonTexts READ buttonTextsMap WRITE setButtonTextsMap RESET resetButtons)
Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue) Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue)
Q_PROPERTY(QVariantMap viewProperties READ viewProperties WRITE setViewProperties) Q_PROPERTY(QVariantMap viewProperties READ viewProperties WRITE setViewProperties)
@ -103,6 +103,9 @@ public:
private: private:
QSharedDataPointer<MessageConfigPrivate> d; QSharedDataPointer<MessageConfigPrivate> d;
QVariantMap buttonTextsMap() const;
void setButtonTextsMap(const QVariantMap &buttonTexts);
}; };
class MessageResultPrivate; class MessageResultPrivate;

7
src/mvvmquick/quickpresenter.cpp

@ -46,7 +46,12 @@ void QuickPresenter::present(QtMvvm::ViewModel *viewModel, const QVariantHash &p
void QuickPresenter::showDialog(const QtMvvm::MessageConfig &config, QtMvvm::MessageResult *result) void QuickPresenter::showDialog(const QtMvvm::MessageConfig &config, QtMvvm::MessageResult *result)
{ {
qDebug(Q_FUNC_INFO); if(d->qmlPresenter) {
QMetaObject::invokeMethod(d->qmlPresenter, "showDialog",
Q_ARG(QtMvvm::MessageConfig, config),
Q_ARG(QtMvvm::MessageResult*, result));
} else
throw PresenterException("QML presenter not ready - cannot present yet");
} }
bool QuickPresenter::presentToQml(QObject *qmlPresenter, QObject *viewObject) bool QuickPresenter::presentToQml(QObject *qmlPresenter, QObject *viewObject)

Loading…
Cancel
Save