Browse Source

added input dialog and url edit

pull/2/head
Skycoder42 7 years ago
parent
commit
0f670f94ec
  1. 30
      src/imports/mvvmquick/DialogPresenter.qml
  2. 59
      src/imports/mvvmquick/InputDialog.qml
  3. 132
      src/imports/mvvmquick/MsgBox.qml
  4. 110
      src/imports/mvvmquick/MsgBoxBase.qml
  5. 4
      src/imports/mvvmquick/mvvmquick.pro
  6. 11
      src/imports/mvvmquick/plugins.qmltypes
  7. 2
      src/imports/mvvmquick/qmldir
  8. 14
      src/mvvmquick/UrlField.qml
  9. 22
      src/mvvmquick/inputviewfactory.cpp
  10. 14
      src/mvvmquick/mvvmquick.pro
  11. 8
      src/mvvmquick/qpmx.json
  12. 1
      src/mvvmquick/qtmvvmquick_module.qrc
  13. 1
      src/mvvmwidgets/widgetspresenter.cpp

30
src/imports/mvvmquick/DialogPresenter.qml

@ -11,6 +11,9 @@ QtObject {
if(config.type == "msgbox") { if(config.type == "msgbox") {
createMsgBox(config, result) createMsgBox(config, result)
return true; return true;
} else if(config.type == "input") {
createInput(config, result)
return true;
} else } else
return false; return false;
} }
@ -43,6 +46,25 @@ QtObject {
} }
} }
property Component _inputComponent: Component {
InputDialog {
id: __input
onClosed: {
var index = _popups.indexOf(__input);
if(index > -1) {
__input.destroy();
_dialogPresenter._popups.splice(index, 1);
}
}
Component.onCompleted: {
_popups.push(__input)
__input.open()
}
}
}
function createMsgBox(config, result) { function createMsgBox(config, result) {
var props = config.viewProperties; var props = config.viewProperties;
props["msgConfig"] = config; props["msgConfig"] = config;
@ -50,4 +72,12 @@ QtObject {
var incubator = _msgBoxComponent.incubateObject(rootItem, props); var incubator = _msgBoxComponent.incubateObject(rootItem, props);
return incubator.status !== Component.Error; return incubator.status !== Component.Error;
} }
function createInput(config, result) {
var props = config.viewProperties;
props["msgConfig"] = config;
props["msgResult"] = result;
var incubator = _inputComponent.incubateObject(rootItem, props);
return incubator.status !== Component.Error;
}
} }

59
src/imports/mvvmquick/InputDialog.qml

@ -0,0 +1,59 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.3
import de.skycoder42.QtMvvm.Quick 1.0
MsgBoxBase {
id: _inputDialog
readonly property url inputUrl: QuickPresenter.inputViewFactory.getInputUrl(msgConfig.subType, msgConfig.viewProperties)
ColumnLayout {
anchors.fill: parent
spacing: 14
Label {
id: _contentLabel
text: msgConfig.text.replace(/<\/p>/g, "</p><br/>") //needed because qml does not put space between paragraphs...
visible: text != ""
Layout.fillWidth: true
wrapMode: Text.Wrap
onLinkActivated: Qt.openUrlExternally(link)
}
ProgressBar {
id: _loadProgress
visible: _inputViewLoad.status == Loader.Loading
Layout.fillWidth: true
value: _inputViewLoad.progress
}
Label {
id: _errorLabel
visible: _inputViewLoad.status == Loader.Error
Layout.fillWidth: true
text: qsTr("<i>Failed to load input view for type: <b>%1</b></i>").arg(msgConfig.subType)
}
Loader {
id: _inputViewLoad
asynchronous: true
clip: true
visible: _inputViewLoad.item
Layout.preferredWidth: _inputViewLoad.item ? _inputViewLoad.item.implicitWidth : 0
Layout.fillHeight: true
Layout.fillWidth: true
onLoaded: msgResult.result = Qt.binding(function() {
return item.inputValue;
})
}
}
Component.onCompleted: {
var props = msgConfig.viewProperties;
props["inputValue"] = msgConfig.defaultValue;
_inputViewLoad.setSource(inputUrl, props);
}
}

132
src/imports/mvvmquick/MsgBox.qml

@ -1,79 +1,30 @@
import QtQuick 2.10 import QtQuick 2.10
import QtQuick.Controls 2.3 import QtQuick.Controls 2.3
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import de.skycoder42.QtMvvm.Core 1.0
Dialog { MsgBoxBase {
id: _msgBox id: _msgBox
property var msgConfig iconVisible: msgConfig.subType != "about"
property MessageResult msgResult iconSource: {
var base = "image://svg/de/skycoder42/qtmvvm/quick/icons/ic_%1";
property real extraHeight: 0 switch(String(msgConfig.subType)) {
property real baseWidth: 300 case "information":
base = base.arg("info");
x: parent ? (parent.width - width) / 2 : 0 break;
y: parent ? deltaY() : 0 case "question":
width: parent ? Math.min(Math.max(implicitWidth, baseWidth), parent.width - 28) : implicitWidth base = base.arg("help");
height: parent ? Math.min(implicitHeight, parent.height - 28) : implicitWidth break;
modal: true case "warning":
focus: true base = base.arg("warning");
break;
function deltaY() { case "critical":
var unscaled = Qt.inputMethod.keyboardRectangle.height / Screen.devicePixelRatio; base = base.arg("error");
var availHeight = (parent.height + extraHeight) - unscaled - 28;//spacing break;
var rawDelta = (Math.max(0, availHeight - height) / 2); case "about":
return rawDelta + 14 - extraHeight;//spacing default:
} return "";
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(String(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
} }
return base;
} }
Label { Label {
@ -84,45 +35,4 @@ Dialog {
wrapMode: Text.Wrap wrapMode: Text.Wrap
onLinkActivated: Qt.openUrlExternally(link) 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)
})
}
}
}
} }

110
src/imports/mvvmquick/MsgBoxBase.qml

@ -0,0 +1,110 @@
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: _msgBoxBase
property var msgConfig
property MessageResult msgResult
property real extraHeight: 0
property real baseWidth: 300
property alias iconVisible: _icon.visible
property alias iconSource: _icon.source
x: parent ? (parent.width - width) / 2 : 0
y: parent ? deltaY() : 0
width: parent ? Math.min(Math.max(implicitWidth, baseWidth), parent.width - 28) : implicitWidth
height: parent ? Math.min(implicitHeight, parent.height - 28) : implicitWidth
modal: true
focus: true
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
visible: false
Layout.preferredWidth: 24
Layout.preferredHeight: 24
Layout.margins: 24
Layout.bottomMargin: 0
Layout.rightMargin: 0
}
Label {
id: _title
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
}
}
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);
msgResult = null;
}
})
}
}
}
onClosed: {
if(msgResult) {
msgResult.complete(MessageConfig.NoButton);
msgResult = null;
}
}
}

4
src/imports/mvvmquick/mvvmquick.pro

@ -23,7 +23,9 @@ QML_FILES += \
PopupPresenter.qml \ PopupPresenter.qml \
DialogPresenter.qml \ DialogPresenter.qml \
TintIcon.qml \ TintIcon.qml \
MsgBox.qml MsgBoxBase.qml \
MsgBox.qml \
InputDialog.qml
OTHER_FILES += qmldir OTHER_FILES += qmldir

11
src/imports/mvvmquick/plugins.qmltypes

@ -8,6 +8,17 @@ import QtQuick.tooling 1.2
Module { Module {
dependencies: ["QtQuick 2.8"] dependencies: ["QtQuick 2.8"]
Component {
name: "QUrlValidator"
prototype: "QValidator"
exports: ["de.skycoder42.QtMvvm.Quick.Private/UrlValidator 1.0"]
exportMetaObjectRevisions: [0]
Property { name: "allowedSchemes"; type: "QStringList" }
Method {
name: "setAllowedSchemes"
Parameter { name: "allowedSchemes"; type: "QStringList" }
}
}
Component { Component {
name: "QtMvvm::InputViewFactory" name: "QtMvvm::InputViewFactory"
prototype: "QObject" prototype: "QObject"

2
src/imports/mvvmquick/qmldir

@ -4,7 +4,9 @@ classname QtMvvmQuickDeclarativeModule
typeinfo plugins.qmltypes typeinfo plugins.qmltypes
internal TintIcon TintIcon.qml internal TintIcon TintIcon.qml
internal MsgBoxBase MsgBoxBase.qml
internal MsgBox MsgBox.qml internal MsgBox MsgBox.qml
internal InputDialog InputDialog.qml
PresenterProgress 1.0 PresenterProgress.qml PresenterProgress 1.0 PresenterProgress.qml
PresentingStackView 1.0 PresentingStackView.qml PresentingStackView 1.0 PresentingStackView.qml

14
src/mvvmquick/UrlField.qml

@ -0,0 +1,14 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import de.skycoder42.QtMvvm.Quick.Private 1.0
TextField {
id: _edit
property alias inputValue: _edit.text
property alias allowedSchemes: _validator.allowedSchemes
selectByMouse: true
validator: UrlValidator {
id: _validator
}
}

22
src/mvvmquick/inputviewfactory.cpp

@ -1,18 +1,34 @@
#include "inputviewfactory.h" #include "inputviewfactory.h"
#include "inputviewfactory_p.h" #include "inputviewfactory_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QMetaType> #include <QtCore/QMetaType>
#include <QtQml/qqml.h>
#include <QtMvvmCore/private/qtmvvm_logging_p.h> #include <QtMvvmCore/private/qtmvvm_logging_p.h>
#include <qurlvalidator.h>
using namespace QtMvvm; using namespace QtMvvm;
static void initResources() namespace {
void initPrivateQml()
{
qmlRegisterType<QUrlValidator>("de.skycoder42.QtMvvm.Quick.Private", 1, 0, "UrlValidator");
}
void initResources()
{ {
#ifdef QT_STATIC #ifdef QT_STATIC
initPrivateQml();
Q_INIT_RESOURCE(qtmvvmquick_module); Q_INIT_RESOURCE(qtmvvmquick_module);
#endif #endif
} }
}
Q_COREAPP_STARTUP_FUNCTION(initPrivateQml)
InputViewFactory::InputViewFactory() : InputViewFactory::InputViewFactory() :
QObject(nullptr), QObject(nullptr),
d(new InputViewFactoryPrivate()) d(new InputViewFactoryPrivate())
@ -53,8 +69,8 @@ QUrl InputViewFactory::getInputUrl(const QByteArray &type, const QVariantMap &vi
// return QUrl(); // return QUrl();
else if(type == QMetaType::typeName(QMetaType::QFont)) else if(type == QMetaType::typeName(QMetaType::QFont))
return QStringLiteral("qrc:/de/skycoder42/qtmvvm/quick/inputs/FontEdit.qml"); return QStringLiteral("qrc:/de/skycoder42/qtmvvm/quick/inputs/FontEdit.qml");
// else if(type == QMetaType::typeName(QMetaType::QUrl) || type == "url") else if(type == QMetaType::typeName(QMetaType::QUrl) || type == "url")
// return QStringLiteral("qrc:/de/skycoder42/qtmvvm/quick/inputs/UrlField.qml"); return QStringLiteral("qrc:/de/skycoder42/qtmvvm/quick/inputs/UrlField.qml");
else if(type == "selection" || type == "list") else if(type == "selection" || type == "list")
return QStringLiteral("qrc:/de/skycoder42/qtmvvm/quick/inputs/ListEdit.qml"); return QStringLiteral("qrc:/de/skycoder42/qtmvvm/quick/inputs/ListEdit.qml");
else { else {

14
src/mvvmquick/mvvmquick.pro

@ -1,17 +1,20 @@
TARGET = QtMvvmQuick TARGET = QtMvvmQuick
QT = core gui widgets mvvmcore mvvmcore-private QT = core gui qml quick mvvmcore mvvmcore-private
HEADERS += \ HEADERS += \
qtmvvmquick_global.h \ qtmvvmquick_global.h \
quickpresenter.h \ quickpresenter.h \
quickpresenter_p.h \ quickpresenter_p.h \
inputviewfactory.h \ inputviewfactory.h \
inputviewfactory_p.h inputviewfactory_p.h
SOURCES += \ SOURCES += \
quickpresenter.cpp \ quickpresenter.cpp \
inputviewfactory.cpp inputviewfactory.cpp
RESOURCES += \
qtmvvmquick_module.qrc
TRANSLATIONS += \ TRANSLATIONS += \
translations/qtmvvmquick_de.ts \ translations/qtmvvmquick_de.ts \
@ -39,5 +42,4 @@ else: include($$OUT_PWD/qpmx_generated.pri)
qpmx_ts_target.files -= $$OUT_PWD/$$QPMX_WORKINGDIR/qtmvvmquick_template.qm qpmx_ts_target.files -= $$OUT_PWD/$$QPMX_WORKINGDIR/qtmvvmquick_template.qm
qpmx_ts_target.files += translations/qtmvvmquick_template.ts qpmx_ts_target.files += translations/qtmvvmquick_template.ts
RESOURCES += \ mingw: LIBS_PRIVATE += -lQt5Gui -lQt5Core
qtmvvmquick_module.qrc

8
src/mvvmquick/qpmx.json

@ -1,5 +1,11 @@
{ {
"dependencies": [], "dependencies": [
{
"package": "de.skycoder42.qurlvalidator",
"provider": "qpm",
"version": "1.1.0"
}
],
"license": { "license": {
"file": "", "file": "",
"name": "" "name": ""

1
src/mvvmquick/qtmvvmquick_module.qrc

@ -6,5 +6,6 @@
<file>CheckBox.qml</file> <file>CheckBox.qml</file>
<file>DoubleSpinBox.qml</file> <file>DoubleSpinBox.qml</file>
<file>FontEdit.qml</file> <file>FontEdit.qml</file>
<file>UrlField.qml</file>
</qresource> </qresource>
</RCC> </RCC>

1
src/mvvmwidgets/widgetspresenter.cpp

@ -221,6 +221,7 @@ void WidgetsPresenter::presentMessageBox(const MessageConfig &config, QPointer<M
qtHelp = config.viewProperties().value(QStringLiteral("showQtHelp"), qtHelp).toBool();//TODO document too qtHelp = config.viewProperties().value(QStringLiteral("showQtHelp"), qtHelp).toBool();//TODO document too
} }
info.escapeButton = QMessageBox::NoButton; //use no button for non button closes
info.title = config.title(); info.title = config.title();
info.text = config.text(); info.text = config.text();
info.buttons = static_cast<QMessageBox::StandardButtons>(static_cast<int>(config.buttons())); //is ok, as the buttons are the same info.buttons = static_cast<QMessageBox::StandardButtons>(static_cast<int>(config.buttons())); //is ok, as the buttons are the same

Loading…
Cancel
Save