Browse Source

completed core doc update

pull/2/head
Skycoder42 6 years ago
parent
commit
872a44af58
No known key found for this signature in database GPG Key ID: 8E01AD9EF0578D2B
  1. 3
      doc/Doxyfile
  2. 45
      doc/isettingsaccessor.dox
  3. 457
      doc/message.dox
  4. 127
      doc/serviceregistry.dox
  5. 81
      doc/settingsviewmodel.dox
  6. 36
      doc/viewmodel.dox
  7. 16
      src/imports/mvvmcore/plugins.qmltypes
  8. 32
      src/imports/mvvmcore/qqmlmvvmmessage.h
  9. 10
      src/imports/mvvmcore/qqmlserviceregistry.cpp
  10. 8
      src/imports/mvvmquick/ProgressDialog.qml
  11. 2
      src/imports/mvvmquick/qqmlquickpresenter.h
  12. 16
      src/mvvmcore/androidsettingsaccessor.h
  13. 31
      src/mvvmcore/coreapp.cpp
  14. 21
      src/mvvmcore/isettingsaccessor.cpp
  15. 21
      src/mvvmcore/isettingsaccessor.h
  16. 1
      src/mvvmcore/message.cpp
  17. 96
      src/mvvmcore/message.h
  18. 8
      src/mvvmcore/qsettingsaccessor.cpp
  19. 7
      src/mvvmcore/qsettingsaccessor.h
  20. 4
      src/mvvmcore/qtmvvmcore_global.h
  21. 2
      src/mvvmcore/serviceregistry.cpp
  22. 23
      src/mvvmcore/serviceregistry.h
  23. 78
      src/mvvmcore/settingsentry.h
  24. 19
      src/mvvmcore/settingsviewmodel.h
  25. 19
      src/mvvmcore/viewmodel.h
  26. 2
      src/mvvmdatasynccore/datasyncsettingsaccessor.h
  27. 11
      src/mvvmquick/inputviewfactory.h
  28. 12
      tests/auto/mvvmcore/coreapp/tst_coreapp.cpp
  29. 44
      tools/settingsgenerator/cppsettingsgenerator.cpp

3
doc/Doxyfile

@ -2169,7 +2169,8 @@ INCLUDE_FILE_PATTERNS = *.h \
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = __cplusplus=201402L \
DOXYGEN_RUN
DOXYGEN_RUN \
QTMVVM_REVISION_1
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The

45
doc/isettingsaccessor.dox

@ -53,6 +53,51 @@ Currently, the following backends are supported:
AndroidSettingsAccessor, SettingsViewModel, DataSyncSettingsViewModel, @ref settings_generator
*/
/*!
@fn QtMvvm::ISettingsAccessor::setDefaultAccessor()
@tparam T The type to be registered as the default type. Must implement ISettingsAccessor
After setting the type via this method, createDefaultAccessor() will create instances of that
type when called.
@note In order for this to work, the passed type must have an invokable constructor, i.e.
@code{.cpp}
Q_INVOKABLE MySettingsAccessor(QObject *parent = nullptr);
@endcode
@sa ISettingsAccessor::createDefaultAccessor
*/
/*!
@fn QtMvvm::ISettingsAccessor::setDefaultAccessor(int)
@param typeId The typeId to be registered as the default type. Must implement ISettingsAccessor
After setting the type via this method, createDefaultAccessor() will create instances of that
type when called.
@note In order for this to work, the passed type must have an invokable constructor, i.e.
@code{.cpp}
Q_INVOKABLE MySettingsAccessor(QObject *parent = nullptr);
@endcode
@sa ISettingsAccessor::createDefaultAccessor
*/
/*!
@fn QtMvvm::ISettingsAccessor::createDefaultAccessor
@param parent The parent object to be passed to to accessor constructor
@returns A newly created instance of the default accessor type, or nullptr
Constructs and returns a new instance of the default accessor type. The default type is
QSettingsAccessor, but can be overwritten via setDefaultAccessor(). If the type set like that
is invalid or cannot be dynamically constructor, nullptr can be returned.
@sa ISettingsAccessor::setDefaultAccessor
*/
/*!
@fn QtMvvm::ISettingsAccessor::contains

457
doc/message.dox

@ -35,6 +35,8 @@ The types supported by default are:
- MessageConfig::TypeMessageBox
- MessageConfig::TypeInputDialog
- MessageConfig::TypeFileDialog
- MessageConfig::TypeColorDialog
- MessageConfig::TypeProgressDialog
@accessors{
@readAc{type()}
@ -42,7 +44,7 @@ The types supported by default are:
}
@sa MessageConfig::subType, MessageConfig::TypeMessageBox, MessageConfig::TypeInputDialog,
MessageConfig::TypeFileDialog
MessageConfig::TypeFileDialog, MessageConfig::TypeColorDialog, MessageConfig::TypeProgressDialog
*/
/*!
@ -72,6 +74,12 @@ The subtypes supported by default are:
- MessageConfig::SubTypeOpenFile
- MessageConfig::SubTypeOpenFiles
- MessageConfig::SubTypeSaveFile
- For MessageConfig::TypeColorDialog:
- MessageConfig::SubTypeRgb
- MessageConfig::SubTypeArgb
- For MessageConfig::TypeProgressDialog:
- MessageConfig::SubTypeProgress
- MessageConfig::SubTypeBusy
@accessors{
@readAc{subType()}
@ -131,6 +139,7 @@ the MessageResult::dialogDone signal.
@accessors{
@readAc{buttons()}
@writeAc{setButtons()}
@writeAc{addButton()}
@resetAc{resetButtons()}
}
@ -295,6 +304,40 @@ show a native dialog the user can use to select files or directories
MessageConfig::TypeMessageBox
*/
/*!
@var QtMvvm::MessageConfig::TypeColorDialog
<b>Value:</b> `"color"`
Shows a generic color dialog. If possible, this will use the systems default, otherwise a
simple color picker gui.
Dialog Type | subType value
--------------------------------|---------------
Select a color without alpha | MessageConfig::SubTypeRgb
Select a color with alpha | MessageConfig::SubTypeArgb
@sa MessageConfig::type, MessageConfig::subType, MessageConfig::TypeInputDialog
*/
/*!
@var QtMvvm::MessageConfig::TypeProgressDialog
<b>Value:</b> `"progress"`
Shows a generic progress dialog. The dialog can by dynamically and asynchronously controlled
from the core app via the ProgressControl class. You must pass an instance of a ProgressControl
via the MessageConfig::defaultValue property when creating one yourself. The passed control
will automatically be connected to the corresponding dialog.
Dialog Type | subType value
----------------------------|---------------
Display a progress bar | MessageConfig::SubTypeProgress
Display a busy indicator | MessageConfig::SubTypeBusy
@sa MessageConfig::type, MessageConfig::subType, ProgressControl
*/
/*!
@var QtMvvm::MessageConfig::SubTypeInformation
@ -391,6 +434,54 @@ to save content to it.
@sa MessageConfig::type, MessageConfig::subType, MessageConfig::TypeFileDialog
*/
/*!
@var QtMvvm::MessageConfig::SubTypeRgb
<b>Value:</b> `"rgb"`
A color dialog that lets the user select a color, without allowing editing of the alpha channel.
The alpha channel will always be set to `0xFF`, i.e. non transparent.
@sa MessageConfig::type, MessageConfig::subType, MessageConfig::TypeColorDialog
*/
/*!
@var QtMvvm::MessageConfig::SubTypeArgb
<b>Value:</b> `"argb"`
A color dialog that lets the user select a color, including the alpha channel. Please note that
not all native dialogs support alpha channel editing.
@sa MessageConfig::type, MessageConfig::subType, MessageConfig::TypeColorDialog
*/
/*!
@var QtMvvm::MessageConfig::SubTypeProgress
<b>Value:</b> `"progress"`
A dialog with a standard progess bar. This bar can either display a classical progress with min,
max and value, or be shown as indeterminate progress (can be switched dynamically via the
ProgressControl)
@sa MessageConfig::type, MessageConfig::subType, MessageConfig::TypeProgressDialog,
ProgressControl
*/
/*!
@var QtMvvm::MessageConfig::SubTypeBusy
<b>Value:</b> `"busy"`
A dialog with a busy indicator shown. This indicator can and will always only show an
indeterminate progress, other values of the ProgressControl are ignored. On platforms that do
not have a seperate busy indicator, an indeterminate progress bar can be shown.
@sa MessageConfig::type, MessageConfig::subType, MessageConfig::TypeProgressDialog,
ProgressControl
*/
/*!
@ -399,6 +490,20 @@ to save content to it.
This class is used to keep track of an active dialog an get the result once it has been
completed. You should not create it yourself, is is returned from the core app.
The class is semi threadsafe, as it is designed to be used in parallel from the core app and
the GUI code. From the core app, you can use:
- all properties (read, write, notify)
- hasResult() method
- discardMessage() slot
- dialogDone() signal
From the GUI, if you intend to create your own presenter frontend, you can use:
- result property (read, write)
- setCloseTarget() method
- complete() method
@sa CoreApp::showDialog, MessageConfig
*/
@ -510,6 +615,218 @@ considered invalid.
/*!
@class QtMvvm::ProgressControl
This class is used together with dialogs of the MessageConfig::TypeProgressDialog type to
control the currently displayed progress from the core code. The class is semi thread safe,
as it is designed to be used from the core an the gui in parallel.
From the core code, i.e. wherever you created the progress instance (directly or indirectly),
you can access:
- all properties (read, write, notify)
- close() slot
- updateLabel() slot
- canceled() signal
- closed() signal
From the GUI, if you intend to create your own presenter frontend, you can use:
- all properties (read, notify, **not** write)
- requestCancel() method
- notifyClosed() method
- changeLabel() signal
- closeRequested() signal
@sa MessageConfig::TypeProgressDialog, QtMvvm::showProgress,
QtMvvm::showIndeterminateProgress, QtMvvm::showBusy
*/
/*!
@property QtMvvm::ProgressControl::autoDelete
@default{`true`}
If set to true, the progress control will delete itself automatically right after closed()
has been emitted.
@accessors{
@readAc{autoDelete()}
@writeAc{setAutoDelete()}
@notifyAc{autoDeleteChanged()}
}
@sa ProgressControl::closed
*/
/*!
@property QtMvvm::ProgressControl::indeterminate
@default{`false`}
If set to true, the dialog will ignore the minimum, maximum and progress properties and simply
show an indeterminate progress. Setting it back to false restores a normal progress bar using
these 3.
@accessors{
@readAc{isIndeterminate()}
@writeAc{setIndeterminate()}
@notifyAc{indeterminateChanged()}
}
@sa ProgressControl::minimum, ProgressControl::maximum, ProgressControl::progress
*/
/*!
@property QtMvvm::ProgressControl::minimum
@default{`0`}
The progress percentage (as number in [0,1]) is calculated as
`(progress - minimum)/(maximum - minimum)` and that value is used to display a progress.
Chaning this property affects the result accordingly.
@accessors{
@readAc{minimum()}
@writeAc{setMinimum()}
@notifyAc{minimumChanged()}
}
@sa ProgressControl::maximum, ProgressControl::progress, ProgressControl::indeterminate
*/
/*!
@property QtMvvm::ProgressControl::maximum
@default{`100`}
The progress percentage (as number in [0,1]) is calculated as
`(progress - minimum)/(maximum - minimum)` and that value is used to display a progress.
Chaning this property affects the result accordingly.
@accessors{
@readAc{maximum()}
@writeAc{setMaximum()}
@notifyAc{maximumChanged()}
}
@sa ProgressControl::minimum, ProgressControl::progress, ProgressControl::indeterminate
*/
/*!
@property QtMvvm::ProgressControl::progress
@default{`-1`}
The progress percentage (as number in [0,1]) is calculated as
`(progress - minimum)/(maximum - minimum)` and that value is used to display a progress.
Chaning this property affects the result accordingly.
Setting it to `-1` is a "special value", that means no progress has been set yet, and may
or may not lead to a different presentation of that state from the simple minimum.
@accessors{
@readAc{progress()}
@writeAc{setProgress()}
@notifyAc{progressChanged()}
}
@sa ProgressControl::minimum, ProgressControl::maximum, ProgressControl::indeterminate
*/
/*!
@fn QtMvvm::ProgressControl::requestCancel
@param btn The button that was pressed by the user
Call this method when the user either presses the cancel button (then pass
MessageConfig::Cancel) or tried to close the window (pass MessageConfig::NoButton). Your GUI
implementation should react to that with disabling the cancel button, but still show the
progress, as the core app is to decide whether to accept that cancel request and if yes will
eventually close the dialog. Internally, this method will emit canceled() in a thread-safe
manner.
@note Your dialog should only allow cancelling when the MessageConfig has the
MessageConfig::Cancel set as a button.
@sa ProgressControl::canceled
*/
/*!
@fn QtMvvm::ProgressControl::notifyClosed
You must call this method as soon as you received a closeRequested() and have actually closed
the dialog. You must call both, this method and MessageResult::complete.
@sa ProgressControl::closeRequested, ProgressControl::closed, MessageResult::complete
*/
/*!
@fn QtMvvm::ProgressControl::close
You must use this method from the core code to close the dialog, either after successfully
completing your long running operation, or as the result of a canceled operation, in case
the user did cancel.
@sa ProgressControl::canceled, ProgressControl::closeRequested
*/
/*!
@fn QtMvvm::ProgressControl::updateLabel
The label text refers to the text initially set via MessageConfig::text. With this method,
you can easily update this text as your operation commences.
@sa MessageConfig::text, ProgressControl::changeLabel
*/
/*!
@fn QtMvvm::ProgressControl::canceled
@param btn The button that was pressed by the user
Cancelling in this case means the user pressed the cancel button (MessageConfig::Cancel) or
tried to close the dialog (MessageConfig::NoButton). In both cases, the dialog
*stays visible*! Your core code must react to the request by connecting this signal and
ideally gracefully cancel the operation and then close() the dialog.
You can ignore the signal in case you showed a non cancelable dialog.
@note For cancel-operations that take a while, it is recommended to tell the user that
cancelling is in progress, as after pressing cancel he can't do anything until the dialog
is closed.
@sa ProgressControl::close, ProgressControl::requestCancel
*/
/*!
@fn QtMvvm::ProgressControl::closed
@sa ProgressControl::close, ProgressControl::closeRequested, ProgressControl::notifyClosed
*/
/*!
@fn QtMvvm::ProgressControl::changeLabel
@param text The new label text
You should use this text and replace the default descriptive text set by MessageConfig::text
@sa ProgressControl::updateLabel, MessageConfig::text
*/
/*!
@fn QtMvvm::ProgressControl::closeRequested
When the close() method is called from the core app, this signal eventually gets emitted.
You must close the dialog immediatly and report that via the notifyClosed() method.
@sa ProgressControl::close, ProgressControl::notifyClosed, ProgressControl::closed
*/
/*!
@fn QtMvvm::information(const QString &, const QString &, const QString &)
@ -718,7 +1035,7 @@ input has been canceled
/*!
@fn QtMvvm::getExistingDirectory(const QString &, const QUrl &)
@param title The input dialog title (MessageConfig::title)
@param title The file dialog title (MessageConfig::title)
@param dir The directory URL to start the file dialog from (MessageConfig::defaultValue)
Shows a folder dialog to let the user select an existing directory.
@ -744,7 +1061,7 @@ selected directory URL or an invalid URL in case the input has been canceled.
/*!
@fn QtMvvm::getOpenFile(const QString &, const QStringList &, const QUrl &)
@param title The input dialog title (MessageConfig::title)
@param title The file dialog title (MessageConfig::title)
@param supportedMimeTypes A list of all allowed mimetypes (MessageConfig::viewProperties, extra property named `mimeTypes`)
@param dir The directory URL to start the file dialog from (MessageConfig::defaultValue)
@ -772,7 +1089,7 @@ selected file URL or an invalid URL in case the input has been canceled.
/*!
@fn QtMvvm::getOpenFiles(const QString &, const QStringList &, const QUrl &)
@param title The input dialog title (MessageConfig::title)
@param title The file dialog title (MessageConfig::title)
@param supportedMimeTypes A list of all allowed mimetypes (MessageConfig::viewProperties, extra property named `mimeTypes`)
@param dir The directory URL to start the file dialog from (MessageConfig::defaultValue)
@ -800,7 +1117,7 @@ selected file URLs in a list or an empty list in case the input has been cancele
/*!
@fn QtMvvm::getSaveFile(const QString &, const QStringList &, const QUrl &)
@param title The input dialog title (MessageConfig::title)
@param title The file dialog title (MessageConfig::title)
@param supportedMimeTypes A list of all allowed mimetypes (MessageConfig::viewProperties, extra property named `mimeTypes`)
@param dir The directory URL to start the file dialog from (MessageConfig::defaultValue)
@ -824,3 +1141,133 @@ selected file URL or an invalid URL in case the input has been canceled.
@param scope A scope to limit to. `onResult` is only called as long as scope has not been deleted
@copydetails QtMvvm::getSaveFile(const std::function<void(QUrl)> &, const QString &, const QStringList &, const QUrl &)
*/
/*!
@fn QtMvvm::getColor(const QString &, const QColor &, bool)
@param title The color dialog title (MessageConfig::title)
@param color The color to initially show in the dialog (MessageConfig::defaultValue)
@param argb Specify whether the dialog should allow editing of the alpha channel (MessageConfig::subType)
Shows a color dialog to let the user select a color. Depending on the argb parameter the
alpha channel may or may not be editable.
@sa MessageConfig, CoreApp::showDialog
*/
/*!
@fn QtMvvm::getColor(const std::function<void(QColor)> &, const QString &, const QColor &, bool)
@param onResult A handler to be called when the color dialog has been closed. Reports the
selected color or an invalid color in case the input has been canceled.
@copydetails QtMvvm::getColor(const QString &, const QColor &, bool)
*/
/*!
@fn QtMvvm::getColor(QObject *, const std::function<void(QColor)> &, const QString &, const QColor &, bool)
@param scope A scope to limit to. `onResult` is only called as long as scope has not been deleted
@copydetails QtMvvm::getColor(const std::function<void(QColor)> &, const QString &, const QColor &, bool)
*/
/*!
@fn QtMvvm::showProgress(const QString &, const QString &, ProgressControl*, bool, bool, const QString &)
@param title The progress dialog title (MessageConfig::title)
@param label The progress dialog label (MessageConfig::text)
@param control The progress control to be used to control the progress dialog (MessageConfig::defaultValue)
@param allowCancel Specify, whether the user can cancel the dialog (MessageConfig::buttons,
set to `MessageConfig::Cancel` if enabled, `MessageConfig::NoButton` otherwise)
@param isBusy Specify whether a busy dialog or a progress dialog should be shown (MessageConfig::subType)
@param cancelText The text for the cancel button, if enabled (MessageConfig::buttonTexts)
Shows a progress dialog to let the user know a long running operation is going on. Unlike
other dialogs, this one can be "controlled" from within the core code to update the progress
etc. via the control passed to the method.
@sa ProgressControl, MessageConfig, CoreApp::showDialog
*/
/*!
@fn QtMvvm::showProgress(const QString &, const QString &, int, int, bool, int, const QString &)
@param title The progress dialog title (MessageConfig::title)
@param label The progress dialog label (MessageConfig::text)
@param maximum The initial maxmium value of the progress (ProgressControl::maximum)
@param minimum The initial minimum value of the progress (ProgressControl::minimum)
@param allowCancel Specify, whether the user can cancel the dialog (MessageConfig::buttons,
set to `MessageConfig::Cancel` if enabled, `MessageConfig::NoButton` otherwise)
@param value The initial progress value of the progress (ProgressControl::progress)
@param cancelText The text for the cancel button, if enabled (MessageConfig::buttonTexts)
@returns A newly created progress control to be used to control the progress dialog (MessageConfig::defaultValue)
Shows a normal progress dialog to let the user know a long running operation is going on. Unlike
other dialogs, this one can be "controlled" from within the core code to update the progress
etc. via the returned control. The control is initialized with the parameters passed to this
method.
@note It is possible to conver the dialog to a indeterminate progress and back by setting the
ProgressControl::indeterminate property.
@sa ProgressControl, MessageConfig, CoreApp::showDialog
*/
/*!
@fn QtMvvm::showProgress(QObject*, const QString &, const QString &, int, int, bool, int, const QString &)
@param scope A scope to limit to. `onResult` is only called as long as scope has not been deleted
@copydetails QtMvvm::showProgress(const QString &, const QString &, int, int, bool, int, const QString &)
*/
/*!
@fn QtMvvm::showIndeterminateProgress(const QString &, const QString &, bool, const QString &)
@param title The progress dialog title (MessageConfig::title)
@param label The progress dialog label (MessageConfig::text)
@param allowCancel Specify, whether the user can cancel the dialog (MessageConfig::buttons,
set to `MessageConfig::Cancel` if enabled, `MessageConfig::NoButton` otherwise)
@param cancelText The text for the cancel button, if enabled (MessageConfig::buttonTexts)
@returns A newly created progress control to be used to control the progress dialog (MessageConfig::defaultValue)
Shows an indeterminate progress dialog to let the user know a long running operation is going on.
Unlike other dialogs, this one can be "controlled" from within the core code to update the
label etc. via the returned control. The control is initialized with the parameters
passed to this method.
@note It is possible to conver the dialog to a normal progress and back by setting the
ProgressControl::indeterminate property.
@sa ProgressControl, MessageConfig, CoreApp::showDialog
*/
/*!
@fn QtMvvm::showIndeterminateProgress(QObject*, const QString &, const QString &, bool, const QString &)
@param scope A scope to limit to. `onResult` is only called as long as scope has not been deleted
@copydetails QtMvvm::showIndeterminateProgress(const QString &, const QString &, bool, const QString &)
*/
/*!
@fn QtMvvm::showBusy(const QString &, const QString &, bool, const QString &)
@param title The progress dialog title (MessageConfig::title)
@param label The progress dialog label (MessageConfig::text)
@param allowCancel Specify, whether the user can cancel the dialog (MessageConfig::buttons,
set to `MessageConfig::Cancel` if enabled, `MessageConfig::NoButton` otherwise)
@param cancelText The text for the cancel button, if enabled (MessageConfig::buttonTexts)
@returns A newly created progress control to be used to control the progress dialog (MessageConfig::defaultValue)
Shows an busy indicator dialog to let the user know a long running operation is going on.
Unlike other dialogs, this one can be "controlled" from within the core code to update the
label etc. via the returned control. The control is initialized with the parameters
passed to this method.
@sa ProgressControl, MessageConfig, CoreApp::showDialog
*/
/*!
@fn QtMvvm::showBusy(QObject*, const QString &, const QString &, bool, const QString &)
@param scope A scope to limit to. `onResult` is only called as long as scope has not been deleted
@copydetails QtMvvm::showBusy(const QString &, const QString &, bool, const QString &)
*/

127
doc/serviceregistry.dox

@ -116,11 +116,12 @@ int main(int argc, char *argv[])
*/
/*!
@fn QtMvvm::ServiceRegistry::registerInterface(bool)
@fn QtMvvm::ServiceRegistry::registerInterface(DestructionScope, bool)
@tparam TInterface The interface type to register the service for
@tparam TService The service to be registered for that interface. Must extend QObject and
implement TInterface
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TInterface
@ -138,18 +139,19 @@ injection for the interface is not possible. In addition to this, TService must
invokable constructor with the following signature:
`Q_INVOKABLE explicit TService(QObject *parent = nullptr);`
@sa ServiceRegistry::registerObject, QtMvvm::registerInterfaceConverter,
ServiceRegistry::registerService, ServiceRegistry::service
@sa ServiceRegistry::registerPlugin, ServiceRegistry::registerObject,
QtMvvm::registerInterfaceConverter, ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerInterface(const TFunc &, bool)
@fn QtMvvm::ServiceRegistry::registerInterface(TFunc, DestructionScope, bool)
@tparam TInterface The interface type to register the service for
@tparam TService The service to be registered for that interface. Must extend QObject and
implement TInterface
@tparam TFunc The function type of the `fn` parameter.
@param fn The function to be called to construct the service
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TInterface
@ -173,17 +175,18 @@ not throw an exception but instead discard (and delete) this one.
@attention Make shure to register TInterface via QtMvvm::registerInterfaceConverter, otherwise
injection for the interface is not possible.
@sa ServiceRegistry::registerObject, QtMvvm::registerInterfaceConverter,
ServiceRegistry::registerService, ServiceRegistry::service
@sa ServiceRegistry::registerPlugin, ServiceRegistry::registerObject,
QtMvvm::registerInterfaceConverter, ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerInterface(TService *, bool)
@fn QtMvvm::ServiceRegistry::registerInterface(TService *, DestructionScope, bool)
@tparam TInterface The interface type to register the service for
@tparam TService The service to be registered for that interface. Must extend QObject and
implement TInterface
@param service The service instance to be registered as service
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TInterface
@ -198,14 +201,15 @@ not throw an exception but instead discard (and delete) this one.
@attention Make shure to register TInterface via QtMvvm::registerInterfaceConverter, otherwise
injection for the interface is not possible.
@sa ServiceRegistry::registerObject, QtMvvm::registerInterfaceConverter,
ServiceRegistry::registerService, ServiceRegistry::service
@sa ServiceRegistry::registerPlugin, ServiceRegistry::registerObject,
QtMvvm::registerInterfaceConverter, ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerObject(bool)
@fn QtMvvm::ServiceRegistry::registerObject(DestructionScope, bool)
@tparam TService The service to be registered by its own type. Must extend QObject
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TService
@ -222,16 +226,17 @@ not throw an exception but instead discard (and delete) this one.
constructor with the following signature:
`Q_INVOKABLE explicit TService(QObject *parent = nullptr);`
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerService,
ServiceRegistry::service
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerPlugin,
ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerObject(const TFunc &, bool)
@fn QtMvvm::ServiceRegistry::registerObject(TFunc, DestructionScope, bool)
@tparam TService The service to be registered by its own type. Must extend QObject
@tparam TFunc The function type of the `fn` parameter.
@param fn The function to be called to construct the service
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for TService
@ -251,15 +256,16 @@ of this function.
If the service is registered as weak, registering another service for the same TService will
not throw an exception but instead discard (and delete) this one.
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerService,
ServiceRegistry::service
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerPlugin,
ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerObject(TService *, bool)
@fn QtMvvm::ServiceRegistry::registerObject(TService *, DestructionScope, bool)
@tparam TService The service to be registered by its own type. Must extend QObject
@param service The service instance to be registered as service
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for TService
@ -273,16 +279,56 @@ not throw an exception but instead discard (and delete) this one.
@attention Make shure to register TInterface via QtMvvm::registerInterfaceConverter, otherwise
injection for the interface is not possible.
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerService,
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerPlugin,
ServiceRegistry::registerService, ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerPlugin(QString, QString, DestructionScope, bool)
@tparam TInterface The interface type to register the service for
@param pluginType The kind of plugin to be loaded. Corresponds to the subdirectoy to find the
plugin in
@param pluginKey The key to select the plugin by, if multiple are available
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for
TInterface
If the function returns successfully, from now on a service of the given type can be accessed
via the registry for the interface. The service is lazy initialized an will be created as soon
as it is requested for the first time. If it has any injectable properties, they will be
automatically injected on construction.
If the service is registered as weak, registering another service for the same interface will
not throw an exception but instead discard (and delete) this one.
To actually create the instance, the registry will try to find a matching plugin to load and
instanciate it. The two parameters, pluginType and pluginKey are used to select a plugin.
pluginType referes to the kind of plugin, i.e. "imageformats", "platforms", ... The value can
either be a relative path, which means it is resolved relative to the standard plugin
directories the application uses to find Qt plugins (pluginType can be empty to directly look
in the root folders). If the path is absolute, only that absolute folder is searched. For both
cases, the search is non-recursive.
pluginKey is a key to select the actual plugin files from all the plugins available in the
folder identified by pluginType. For that, the "Key" property of the metadata of each plugin
is checked to find one that has the given key in the list. If not specified, one of the
available plugins is randomly choosen.
@sa ServiceRegistry::registerInterface, ServiceRegistry::registerObject,
QtMvvm::registerInterfaceConverter, ServiceRegistry::registerService,
ServiceRegistry::service
*/
/*!
@fn QtMvvm::ServiceRegistry::registerService(const QByteArray &, const QMetaObject *, bool)
@fn QtMvvm::ServiceRegistry::registerService(const QByteArray &, const QMetaObject *, DestructionScope, bool)
@param iid The interface id of the type to register the service for
@param metaObject The metaobject of the service to be registered for that interface. Must
extend QObject and implement the interface of `iid`, unless it is the id of the service itself
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for the iid
@ -298,15 +344,17 @@ throw an exception but instead discard (and delete) this one.
have an invokable constructor with the following signature:
`Q_INVOKABLE explicit Service(QObject *parent = nullptr);`
@sa ServiceRegistry::registerObject, QtMvvm::registerInterface, ServiceRegistry::serviceObj
@sa QtMvvm::registerInterface, ServiceRegistry::registerObject,
ServiceRegistry::registerPlugin, ServiceRegistry::serviceObj
*/
/*!
@fn QtMvvm::ServiceRegistry::registerService(const QByteArray &, const std::function<QObject*(const QObjectList &)> &, QByteArrayList, bool)
@fn QtMvvm::ServiceRegistry::registerService(const QByteArray &, const std::function<QObject*(const QObjectList &)> &, QByteArrayList, DestructionScope, bool)
@param iid The interface id of the type to register the service for
@param fn The function to be called to construct the service
@param injectables The iids of the parameters to be passed to `fn`
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for the iid
@ -323,7 +371,44 @@ to a list of objects.
If the service is registered as weak, registering another service for the same iid will not
throw an exception but instead discard (and delete) this one.
@sa ServiceRegistry::registerObject, QtMvvm::registerInterface, ServiceRegistry::serviceObj
@sa QtMvvm::registerInterface, ServiceRegistry::registerObject,
ServiceRegistry::registerPlugin, ServiceRegistry::serviceObj*/
/*!
@fn QtMvvm::ServiceRegistry::registerService(QByteArray, QString, QString, DestructionScope, bool)
@param iid The interface id of the type to register the service for
@param pluginType The kind of plugin to be loaded. Corresponds to the subdirectoy to find the
plugin in
@param pluginKey The key to select the plugin by, if multiple are available
@param scope The scope at which the service instance should be destroyed
@param weak Specifies if the registration should be a weak one or a normal one
@throws ServiceExistsException If a non-weak service has already been registered for the iid
If the function returns successfully, from now on a service of the given type can be accessed
via the registry for the interface. The service is lazy initialized an will be created as soon
as it is requested for the first time. If it has any injectable properties, they will be
automatically injected on construction.
If the service is registered as weak, registering another service for the same interface will
not throw an exception but instead discard (and delete) this one.
To actually create the instance, the registry will try to find a matching plugin to load and
instanciate it. The two parameters, pluginType and pluginKey are used to select a plugin.
pluginType referes to the kind of plugin, i.e. "imageformats", "platforms", ... The value can
either be a relative path, which means it is resolved relative to the standard plugin
directories the application uses to find Qt plugins (pluginType can be empty to directly look
in the root folders). If the path is absolute, only that absolute folder is searched. For both
cases, the search is non-recursive.
pluginKey is a key to select the actual plugin files from all the plugins available in the
folder identified by pluginType. For that, the "Key" property of the metadata of each plugin
is checked to find one that has the given key in the list. If not specified, one of the
available plugins is randomly choosen.
@sa QtMvvm::registerInterface, ServiceRegistry::registerObject,
ServiceRegistry::registerPlugin, ServiceRegistry::serviceObj
*/
/*!

81
doc/settingsviewmodel.dox

@ -11,6 +11,25 @@ show<QtMvvm::SettingsViewModel>();
@sa @ref images_page
*/
/*!
@property QtMvvm::SettingsViewModel::accessor
@default{`nullptr` (Initialized by onInit())}
This acccessor is used by all the methods that access settings. This makes it possible to
simply change the backend that the viewmodel should operate on without reimplementing it, and
also makes it possible for change signals to be used to dynamically update the gui if the
settings values change.
@accessors{
@readAc{accessor()}
@writeAc{setAccessor()}
@notifyAc{accessorChanged()}
}
@sa ISettingsAccessor, SettingsViewModel::showParams
*/
/*!
@property QtMvvm::SettingsViewModel::canRestoreDefaults
@ -58,6 +77,14 @@ the default one.
@sa #QTMVVM_INJECT
*/
/*!
@var QtMvvm::SettingsViewModel::paramAccessor
<b>Value:</b> `"accessor"`
@sa SettingsViewModel::showParams
*/
/*!
@var QtMvvm::SettingsViewModel::paramSettings
@ -75,13 +102,38 @@ the default one.
*/
/*!
@fn QtMvvm::SettingsViewModel::showParams
@fn QtMvvm::SettingsViewModel::showParams(ISettingsAccessor*, const QString &)
@param accessor The ISettingsAccessor to operate on. Can be null to use the default accessor
(QSettingsAccessor)
@param setupFile The path to a file to be used to create the settings. Can be empty to use the
default path
@return A paramater hash to be passed to ViewModel::show
It's a shortcut to generate parameters for the show methods to show a settings viewmodel. Use
them as:
@code{.cpp}
show<QtMvvm::SettingsViewModel>(QtMvvm::SettingsViewModel::showParams(...));
@endcode
@note Unless you need to explicitly set the settings or setup file a normal show without any
parameters will just do fine.
@sa ViewModel::show, SettingsViewModel::paramAccessor, SettingsViewModel::paramSetupFile
*/
/*!
@fn QtMvvm::SettingsViewModel::showParams(QSettings*, const QString &)
@param settings The QSettings to operate on. Can be null to use the default settings
@param setupFile The path to a file to be used to create the settings. Can be empty to use the
default path
@return A paramater hash to be passed to ViewModel::show
This internally creates a QSettingsAccessor that operates on the given settings and sets it
as the SettingsViewModel::accessor.
It's a shortcut to generate parameters for the show methods to show a settings viewmodel. Use
them as:
@ -141,6 +193,23 @@ different source then the normally used QSettings
@sa SettingsViewModel::loadValue, SettingsViewModel::saveValue
*/
/*!
@fn QtMvvm::SettingsViewModel::resetAll
@param setup The setup to search for keys to be resetted
You can call this method from your gui to perform a complete reset of all the settings that
are visible in the gui. Internally, the method will use SettingsViewModel::restoreConfig to
create a dialog that asks the user for confirmation, and if he accepts, remove the value of
all SettingsElements::Entry elements that can be found in the setup by calling resetValue().
If the user accepted the dialog and data was successfully reset, the resetAccepted() signal
is emitted so the gui can close itself.
@sa SettingsViewModel::restoreConfig, SettingsViewModel::resetAccepted,
SettingsViewModel::resetValue
*/
/*!
@fn QtMvvm::SettingsViewModel::callAction
@ -154,3 +223,13 @@ the type documentation for more details.
@sa @ref settings_xml_types_action
*/
/*!
@fn QtMvvm::SettingsViewModel::resetAccepted
This signal is emitted as the result of a resetAll() that was accepted by the user. As a
reaction, the settings gui implementation should close itself.
@sa SettingsViewModel::resetAll
*/

36
doc/viewmodel.dox

@ -12,7 +12,29 @@ with a single QObject* parameter for the parent. It basically should look like t
Q_INVOKABLE explicit MyViewModel(QObject *parent = nullptr);
@endcode
@sa CoreApp::show, #QTMVVM_INJECT
@section qtmvvm_viewmodel_singleton "Singleton Viewmodels"
Normally, showing a viewmodel will always create a new instance of it, and thus show a new
gui. However, by adding the #QTMVVM_SINGLETON macro to the class definition, your viewmodel
becomes a single instance. This means, it will only be created once, and subsequent show
requests will instead only trigger the instanceInvoked() signal on the existing instance.
If the existing instance gets destroyed at some point, show requests will show a new instance.
@section qtmvvm_viewmodel_container "Container Viewmodels"
Some viewmodel require a special viewmodel as their parent to be show in. To simplify the
handling of those viewmodel, you can specify a parent container for a viewmodel via the
#QTMVVM_CONTAINER_VM macro. If added, everytime you try to show a viewmodel of this kind, the
presenter will first create a new viewmodel of the type specified by the macro, and then
show the original viewmodel immediatly after as child of the newly created parent. (The parent
and the child can both be singletons)
You can specify parameters to be passed to the parent that is to be created via a special
parameter named `"qtmvvm_container_params"`. The value of that property must be a variant hash
as well. In addition, a special parameter is added to the parent parameter, the
`"qtmvvm_container_for"` parameter, which contains the name of the viewmodel that triggered
its creation.
@sa CoreApp::show, #QTMVVM_INJECT, #QTMVVM_SINGLETON, #QTMVVM_CONTAINER_VM
*/
/*!
@ -59,6 +81,18 @@ the viewmodel gets destroy leads to the onResult() beeing called with an invalid
@sa ViewModel::showForResult, ViewModel::onResult
*/
/*!
@fn QtMvvm::ViewModel::instanceInvoked
@param params The show parameters that were passed to the show method
If this viewmodel is a single instance viewmodel (#QTMVVM_SINGLETON), then only the first show
will actually create a viewmodel. All subsequent shows for that type will instead trigger this
signal on the existing instance.
@sa #QTMVVM_SINGLETON, @ref qtmvvm_viewmodel_singleton
*/
/*!
@fn QtMvvm::ViewModel::show(const QVariantHash &) const

16
src/imports/mvvmcore/plugins.qmltypes

@ -121,16 +121,16 @@ Module {
name: "progressChanged"
Parameter { name: "progress"; type: "int" }
}
Signal {
name: "changeLabel"
Parameter { name: "text"; type: "string" }
}
Signal { name: "closeRequested" }
Signal {
name: "canceled"
Parameter { name: "btn"; type: "QtMvvm::MessageConfig::StandardButton" }
}
Signal { name: "closed" }
Signal {
name: "changeLabel"
Parameter { name: "text"; type: "string" }
}
Signal { name: "closeRequested" }
Method { name: "close" }
Method {
name: "updateLabel"
@ -831,7 +831,11 @@ Module {
name: "resultReady"
Parameter { name: "result"; type: "QVariant" }
}
Signal { name: "instanceInvoked"; revision: 1 }
Signal {
name: "instanceInvoked"
revision: 1
Parameter { name: "params"; type: "QVariantHash" }
}
Method {
name: "onInit"
Parameter { name: "params"; type: "QVariantHash" }

32
src/imports/mvvmcore/qqmlmvvmmessage.h

@ -110,23 +110,23 @@ public Q_SLOTS:
const QStringList &supportedMimeTypes = {},
const QUrl &dir = {});
Q_REVISION(1) static void getColor(const QJSValue &onResult = {},
const QString &title = {},
const QColor &color = {},
bool argb = false);
Q_REVISION(1) static QtMvvm::ProgressControl *showProgress(const QString &title = {},
QTMVVM_REVISION_1 static void getColor(const QJSValue &onResult = {},
const QString &title = {},
const QColor &color = {},
bool argb = false);
QTMVVM_REVISION_1 static QtMvvm::ProgressControl *showProgress(const QString &title = {},
const QString &label = {},
int maximum = 100,
int minimum = 0,
bool allowCancel = true,
int value = 0);
QTMVVM_REVISION_1 static QtMvvm::ProgressControl *showIndeterminateProgress(const QString &title = {},
const QString &label = {},
bool allowCancel = true);
QTMVVM_REVISION_1 static QtMvvm::ProgressControl *showBusy(const QString &title = {},
const QString &label = {},
int maximum = 100,
int minimum = 0,
bool allowCancel = true,
int value = 0);
Q_REVISION(1) static QtMvvm::ProgressControl *showIndeterminateProgress(const QString &title = {},
const QString &label = {},
bool allowCancel = true);
Q_REVISION(1) static QtMvvm::ProgressControl *showBusy(const QString &title = {},
const QString &label = {},
bool allowCancel = true);
bool allowCancel = true);
#ifndef DOXYGEN_RUN
#undef static

10
src/imports/mvvmcore/qqmlserviceregistry.cpp

@ -62,11 +62,11 @@ void QQmlServiceRegistry::registerObject(const QUrl &componentUrl, bool weak)
void QQmlServiceRegistry::registerPlugin(const QString &iid, QString pluginType, QString pluginKey, QQmlServiceRegistry::DestructionScope scope, bool weak)
{
ServiceRegistry::instance()->registerPlugin(iid.toUtf8(),
std::move(pluginType),
std::move(pluginKey),
static_cast<ServiceRegistry::DestructionScope>(scope),
weak);
ServiceRegistry::instance()->registerService(iid.toUtf8(),
std::move(pluginType),
std::move(pluginKey),
static_cast<ServiceRegistry::DestructionScope>(scope),
weak);
}
QObject *QQmlServiceRegistry::service(const QString &iid)

8
src/imports/mvvmquick/ProgressDialog.qml

@ -24,8 +24,12 @@ MsgBoxBase {
}
function finish() {
msgResult.complete(_cancelAction);
msgResult = null;
if(progressControl)
notifyClosed.notifyClosed();
if(msgResult) {
msgResult.complete(_cancelAction);
msgResult = null;
}
close();
}

2
src/imports/mvvmquick/qqmlquickpresenter.h

@ -141,7 +141,7 @@ public:
* the color value is checked, too. If baseColor is easily readable, it is simply returned
* as result. Otherwise the method proceeds as usual.
*/
Q_REVISION(1) Q_INVOKABLE static QColor accentTextColor(const QColor &accentColor, const QColor &baseColor) const;
QTMVVM_REVISION_1 Q_INVOKABLE static QColor accentTextColor(const QColor &accentColor, const QColor &baseColor) const;
#ifdef DOXYGEN_RUN
public:

16
src/mvvmcore/androidsettingsaccessor.h

@ -9,23 +9,27 @@
namespace QtMvvm {
class AndroidSettingsAccessorPrivate;
//! A wrapper around the android SharedPreferences API
class Q_MVVMCORE_EXPORT AndroidSettingsAccessor : public ISettingsAccessor
{
Q_OBJECT
Q_INTERFACES(QtMvvm::ISettingsAccessor)
public:
//! Flags to specify how the shared preferences should be created
enum ModeFlag {
Private = 0x00000000,
WorldReadable = 0x00000001,
WorldWritable = 0x00000002,
MultiProcess = 0x00000004
Private = 0x00000000, //!< The default. Only the application itself can access settings
WorldReadable = 0x00000001, //!< Deprecated. Everyone canwrite the settings
MultiProcess = 0x00000004 //!< Deprecated. Multiple process can use an instance in parallel
};
Q_DECLARE_FLAGS(Mode, ModeFlag)
Q_FLAG(Mode)
explicit AndroidSettingsAccessor(QObject *parent = nullptr);
//! Default constructor
Q_INVOKABLE explicit AndroidSettingsAccessor(QObject *parent = nullptr);
//! Constructor with the name of the shared preferences to be opened
explicit AndroidSettingsAccessor(const QString &file, QObject *parent = nullptr);
//! Constructor with the name of the shared preferences to be opened and the mode to open them
explicit AndroidSettingsAccessor(const QString &file, Mode mode, QObject *parent = nullptr);
~AndroidSettingsAccessor() override;
@ -35,6 +39,7 @@ public:
void remove(const QString &key) override;
public Q_SLOTS:
//! @copydoc ISettingsAccessor::sync
void sync() override;
private Q_SLOTS:
@ -46,6 +51,7 @@ private:
}
Q_DECLARE_METATYPE(QtMvvm::AndroidSettingsAccessor*)
Q_DECLARE_OPERATORS_FOR_FLAGS(QtMvvm::AndroidSettingsAccessor::Mode)
#endif // QTMVVM_ANDROIDSETTINGSACCESSOR_H

31
src/mvvmcore/coreapp.cpp

@ -315,16 +315,26 @@ const QMetaObject *CoreAppPrivate::getContainer(const QMetaObject *metaObject) c
QPointer<ViewModel> CoreAppPrivate::showViewModelWithReturn(const QMetaObject *metaObject, const QVariantHash &params, QPointer<ViewModel> parent, quint32 requestCode)
{
if(presenter) {
// first: check if it has a container, and if yes: show the container
// first: handle a singleton
auto isSingle = isSingleton(metaObject);
if(isSingle) {
auto viewModel = singleInstances.value(metaObject);
if(viewModel) {
logDebug() << "Found existing single instance for" << metaObject->className();
emit viewModel->instanceInvoked(params, ViewModel::QPrivateSignal{});
return viewModel;
}
}
// next: check if it has a container, and if yes: show the container
try {
auto container = getContainer(metaObject);
if(container) {
logDebug() << "Found container type for" << metaObject->className()
<< "as" << container->className();
parent = showViewModelWithReturn(container, { //TODO document special parameters
{QStringLiteral("qtmvvm_container_for"), QByteArray{metaObject->className()}},
{QStringLiteral("qtmvvm_child_params"), params}
}, std::move(parent), 0);
auto containerParams = params.value(QStringLiteral("qtmvvm_container_params")).toHash();
containerParams.insert(QStringLiteral("qtmvvm_container_for"), QByteArray{metaObject->className()});
parent = showViewModelWithReturn(container, containerParams, std::move(parent), 0);
if(!parent)
throw PresenterException{"Failed to present parent container"};
}
@ -336,17 +346,6 @@ QPointer<ViewModel> CoreAppPrivate::showViewModelWithReturn(const QMetaObject *m
return nullptr;
}
// next: handle a singleton
auto isSingle = isSingleton(metaObject);
if(isSingle) {
auto viewModel = singleInstances.value(metaObject);
if(viewModel) {
logDebug() << "Found existing single instance for" << metaObject->className();
emit viewModel->instanceInvoked(ViewModel::QPrivateSignal{});
return viewModel;
}
}
QPointer<ViewModel> vm;
try {
auto obj = ServiceRegistry::instance()->constructInjected(metaObject);

21
src/mvvmcore/isettingsaccessor.cpp

@ -1,6 +1,27 @@
#include "isettingsaccessor.h"
#include "qsettingsaccessor.h"
using namespace QtMvvm;
int ISettingsAccessor::_DefaultAccessorType = qMetaTypeId<QSettingsAccessor*>();
void ISettingsAccessor::setDefaultAccessor(int typeId)
{
auto metaObject = QMetaType::metaObjectForType(typeId);
Q_ASSERT_X(metaObject && metaObject->inherits(&ISettingsAccessor::staticMetaObject),
Q_FUNC_INFO,
"Invalid type ID. Must be a pointer to a class that implements QtMvvm::ISettingsAccessor");
_DefaultAccessorType = typeId;
}
ISettingsAccessor *ISettingsAccessor::createDefaultAccessor(QObject *parent)
{
auto metaObject = QMetaType::metaObjectForType(_DefaultAccessorType);
if(metaObject)
return qobject_cast<ISettingsAccessor*>(metaObject->newInstance(Q_ARG(QObject*, parent)));
else
return nullptr;
}
ISettingsAccessor::ISettingsAccessor(QObject *parent) :
QObject{parent}
{}

21
src/mvvmcore/isettingsaccessor.h

@ -1,6 +1,8 @@
#ifndef QTMVVM_ISETTINGSACCESSOR_H
#define QTMVVM_ISETTINGSACCESSOR_H
#include <type_traits>
#include <QtCore/qobject.h>
#include <QtCore/qstring.h>
#include <QtCore/qvariant.h>
@ -16,6 +18,15 @@ class Q_MVVMCORE_EXPORT ISettingsAccessor : public QObject
Q_DISABLE_COPY(ISettingsAccessor)
public:
// Set the default accessor type to be used by generated settings if none was specified
template <typename T>
static void setDefaultAccessor();
//! @copybrief ISettingsAccessor::setDefaultAccessor
static void setDefaultAccessor(int typeId);
//! Create a new instance of the default accessor type
static ISettingsAccessor *createDefaultAccessor(QObject *parent = nullptr);
//! Constructor
ISettingsAccessor(QObject *parent = nullptr);
@ -37,8 +48,18 @@ Q_SIGNALS:
void entryChanged(const QString &key, const QVariant &value);
//! Is emitted whenever a settings value was removed, at least via this instance
void entryRemoved(const QString &key);
private:
static int _DefaultAccessorType;
};
template<typename T>
void ISettingsAccessor::setDefaultAccessor()
{
static_assert(std::is_base_of<T, ISettingsAccessor>::value, "T must implement the QtMvvm::ISettingsAccessor interface");
setDefaultAccessor(qMetaTypeId<T*>());
}
}
//! The IID of the QtMvvm::IPresenter class

1
src/mvvmcore/message.cpp

@ -737,6 +737,7 @@ void QtMvvm::getColor(const std::function<void (QColor)> &onResult, const QStrin
MessageResult *QtMvvm::showProgress(const QString &title, const QString &label, ProgressControl *control, bool allowCancel, bool isBusy, const QString &cancelText)
{
Q_ASSERT_X(control, Q_FUNC_INFO, "control parameter must not be null");
MessageConfig config(MessageConfig::TypeProgressDialog, isBusy ? MessageConfig::SubTypeBusy : MessageConfig::SubTypeProgress);
config.setTitle(title);
config.setText(label);

96
src/mvvmcore/message.h

@ -78,9 +78,11 @@ public:
static const QByteArray TypeInputDialog;
//! A type to show a generic file dialog
static const QByteArray TypeFileDialog;
//! @}
//! A type to show a generic color dialog
static const QByteArray TypeColorDialog;
//! A type to show a generic progress dialog
static const QByteArray TypeProgressDialog;
//! @}
/**
* @name Possible values for MessageConfig::subType when using the type MessageConfig::TypeMessageBox
@ -112,22 +114,37 @@ public:
static const QByteArray SubTypeSaveFile;
//! @}
/**
* @name Possible values for MessageConfig::subType when using the type MessageConfig::TypeColorDialog
* @{
*/
//! @brief A subType to show a color dialog without an alpha channel
static const QByteArray SubTypeRgb;
//! A subType to show a color dialog with an alpha channel
static const QByteArray SubTypeArgb;
//! @}
/**
* @name Possible values for MessageConfig::subType when using the type MessageConfig::TypeProgressDialog
* @{
*/
//! @brief A subType to show a dialog with a progress bar
static const QByteArray SubTypeProgress;
//! A subType to show a dialog with a busy indicator
static const QByteArray SubTypeBusy;
//! @}
//! Default constructor, can take a type and a subtype
MessageConfig(const QByteArray &type = TypeMessageBox, const QByteArray &subType = {});
//! Copy constructor
MessageConfig(const MessageConfig &other);
//! Move constructor
MessageConfig(MessageConfig &&other) noexcept;
~MessageConfig();
//! Assignment operator
//! Copy assignment operator
MessageConfig &operator=(const MessageConfig &other);
//! Move assignment operator
MessageConfig &operator=(MessageConfig &&other) noexcept;
//! @readAcFn{MessageConfig::type}
@ -157,6 +174,7 @@ public:
MessageConfig &setText(const QString &text);
//! @writeAcFn{MessageConfig::buttons}
MessageConfig &setButtons(StandardButtons buttons);
//! @writeAcFn{MessageConfig::buttons}
MessageConfig &addButton(StandardButton button);
//! @writeAcFn{MessageConfig::buttonTexts}
MessageConfig &setButtonTexts(const QHash<StandardButton, QString> &buttonTexts);
@ -242,54 +260,97 @@ private:
};
class ProgressControlPrivate;
//! A Helper class to control a generic progress dialog
class Q_MVVMCORE_EXPORT ProgressControl : public QObject
{
Q_OBJECT
//! Specifies whether the object should delete itself after completition
Q_PROPERTY(bool autoDelete READ autoDelete WRITE setAutoDelete NOTIFY autoDeleteChanged)
//! Specifies whether the dialog should show an indeterminate or a normal progress
Q_PROPERTY(bool indeterminate READ isIndeterminate WRITE setIndeterminate NOTIFY indeterminateChanged)
//! The minimum value of the progress bar
Q_PROPERTY(int minimum READ minimum WRITE setMinimum NOTIFY minimumChanged)
//! The maximum value of the progress bar
Q_PROPERTY(int maximum READ maximum WRITE setMaximum NOTIFY maximumChanged)
//! The current value of the progress bar
Q_PROPERTY(int progress READ progress WRITE setProgress NOTIFY progressChanged)
public:
//! Constructor
explicit ProgressControl(QObject *parent = nullptr);
~ProgressControl() override;
//! @readAcFn{ProgressControl::autoDelete}
bool autoDelete() const;
//! @readAcFn{ProgressControl::indeterminate}
bool isIndeterminate() const;
//! @readAcFn{ProgressControl::minimum}
int minimum() const;
//! @readAcFn{ProgressControl::maximum}
int maximum() const;
//! @readAcFn{ProgressControl::progress}
int progress() const;
/**
* @name Presenter-Only methods
* @details The following methods should be used by the presenter only, not from the core
* @{
*/
//! @brief Signals the core app that the user tried to cancel the progress
Q_INVOKABLE void requestCancel(QtMvvm::MessageConfig::StandardButton btn);
//! Signals the core app that the dialog was closed
Q_INVOKABLE void notifyClosed();
//! @}
public Q_SLOTS:
//! Closes the dialog asynchronously
void close();
//! Updates the descriptive text displayed in the progress dialog
void updateLabel(const QString &text);
//! @writeAcFn{ProgressControl::autoDelete}
void setAutoDelete(bool autoDelete);
//! @writeAcFn{ProgressControl::indeterminate}
void setIndeterminate(bool indeterminate);
//! @writeAcFn{ProgressControl::minimum}
void setMinimum(int minimum);
//! @writeAcFn{ProgressControl::maximum}
void setMaximum(int maximum);
//! @writeAcFn{ProgressControl::progress}
void setProgress(int progress);
//! @writeAcFn{ProgressControl::progressPercent}
void setProgress(double progressPercent);
Q_SIGNALS:
//! @notifyAcFn{ProgressControl::autoDelete}
void autoDeleteChanged(bool autoDelete, QPrivateSignal);
//! @notifyAcFn{ProgressControl::indeterminate}
void indeterminateChanged(bool indeterminate, QPrivateSignal);
//! @notifyAcFn{ProgressControl::minimum}
void minimumChanged(int minimum, QPrivateSignal);
//! @notifyAcFn{ProgressControl::maximum}
void maximumChanged(int maximum, QPrivateSignal);
//! @notifyAcFn{ProgressControl::progress}
void progressChanged(int progress, QPrivateSignal);
void changeLabel(const QString &text, QPrivateSignal);
void closeRequested(QPrivateSignal);
//! Is emitted when the user canceled the dialog
void canceled(QtMvvm::MessageConfig::StandardButton btn, QPrivateSignal);
//! Is emitted after the dialog gui has been closed
void closed(QPrivateSignal);
/**
* @name Presenter-Only signals
* @details The following signals should be used by the presenter only, not from the core
* @{
*/
//! @brief Is emitted when the descriptive text in the dialog should be updated
void changeLabel(const QString &text, QPrivateSignal);
//! Is emitted when a closed was requested from the core code
void closeRequested(QPrivateSignal);
//! @}
private:
QScopedPointer<ProgressControlPrivate> d;
};
@ -513,25 +574,40 @@ Q_MVVMCORE_EXPORT void getSaveFile(const std::function<void(QUrl)> &onResult,
const QUrl &dir = {});
//! @}
/**
* @name Methods to show simple color dialogs (MessageConfig::TypeColorDialog)
* @{
*/
//! @brief A shortcut to show a color dialog to select a color
Q_MVVMCORE_EXPORT MessageResult *getColor(const QString &title = {},
const QColor &color = {},
bool argb = false);
//! @copybrief QtMvvm::getColor(const std::function<void(QColor)> &, const QString &, const QColor &, bool)
Q_MVVMCORE_EXPORT void getColor(QObject *scope,
const std::function<void(QColor)> &onResult,
const QString &title = {},
const QColor &color = {},
bool argb = false);
//! @copybrief QtMvvm::getColor(const QString &, const QColor &, bool)
Q_MVVMCORE_EXPORT void getColor(const std::function<void(QColor)> &onResult,
const QString &title = {},
const QColor &color = {},
bool argb = false);
//! @}
/**
* @name Methods to show simple progress dialogs (MessageConfig::TypeProgressDialog)
* @{
*/
//! @brief A shortcut to show a general progress dialog
Q_MVVMCORE_EXPORT MessageResult *showProgress(const QString &title,
const QString &label,
ProgressControl *control,
bool allowCancel = true,
bool isBusy = false,
const QString &cancelText = {});
//! @copybrief QtMvvm::showProgress(const QString &, const QString &, int, int, bool, int, const QString &)
Q_MVVMCORE_EXPORT ProgressControl *showProgress(QObject *scope,
const QString &title = {},
const QString &label = {},
@ -540,6 +616,7 @@ Q_MVVMCORE_EXPORT ProgressControl *showProgress(QObject *scope,
bool allowCancel = true,
int value = 0,
const QString &cancelText = {});
//! A shortcut to show a standard progress dialog
Q_MVVMCORE_EXPORT ProgressControl *showProgress(const QString &title = {},
const QString &label = {},
int maximum = 100,
@ -547,24 +624,31 @@ Q_MVVMCORE_EXPORT ProgressControl *showProgress(const QString &title = {},
bool allowCancel = true,
int value = 0,
const QString &cancelText = {});
//! @copybrief QtMvvm::showIndeterminateProgress(const QString &, const QString &, bool, const QString &)
Q_MVVMCORE_EXPORT ProgressControl *showIndeterminateProgress(QObject *scope,
const QString &title = {},
const QString &label = {},
bool allowCancel = true,
const QString &cancelText = {});
//! A shortcut to show an indetermiante progress dialog
Q_MVVMCORE_EXPORT ProgressControl *showIndeterminateProgress(const QString &title = {},
const QString &label = {},
bool allowCancel = true,
const QString &cancelText = {});
//! @copybrief QtMvvm::showBusy(const QString &, const QString &, bool, const QString &)
Q_MVVMCORE_EXPORT ProgressControl *showBusy(QObject *scope,
const QString &title = {},
const QString &label = {},
bool allowCancel = true,
const QString &cancelText = {});
//! A shortcut to show a busy indicator dialog
Q_MVVMCORE_EXPORT ProgressControl *showBusy(const QString &title = {},
const QString &label = {},
bool allowCancel = true,
const QString &cancelText = {});
//! @}
}

8
src/mvvmcore/qsettingsaccessor.cpp

@ -15,14 +15,14 @@ public:
QSettingsAccessor::QSettingsAccessor(QObject *parent) :
QSettingsAccessor{new QSettings{}, parent}
{
d->settings->setParent(this);
}
{}
QSettingsAccessor::QSettingsAccessor(QSettings *settings, QObject *parent) :
ISettingsAccessor{parent},
d{new QSettingsAccessorPrivate{settings}}
{}
{
d->settings->setParent(this);
}
QSettingsAccessor::~QSettingsAccessor() = default;

7
src/mvvmcore/qsettingsaccessor.h

@ -10,13 +10,16 @@
namespace QtMvvm {
class QSettingsAccessorPrivate;
//! A settings accessor implementation that wrapps QSettings
class Q_MVVMCORE_EXPORT QSettingsAccessor : public ISettingsAccessor
{
Q_OBJECT
Q_INTERFACES(QtMvvm::ISettingsAccessor)
public:
//! Constructor
Q_INVOKABLE explicit QSettingsAccessor(QObject *parent = nullptr);
//! Constructor, with settings to be used (takes ownership of the settings)
explicit QSettingsAccessor(QSettings *settings, QObject *parent = nullptr);
~QSettingsAccessor() override;
@ -25,9 +28,11 @@ public:
void save(const QString &key, const QVariant &value) override;
void remove(const QString &key) override;
//! Returns the internally used settings
QSettings *settings() const;
public Q_SLOTS:
//! @copydoc ISettingsAccessor::sync
void sync() override;
private:
@ -36,4 +41,6 @@ private:
}
Q_DECLARE_METATYPE(QtMvvm::QSettingsAccessor*)
#endif // QTMVVM_QSETTINGSACCESSOR_H

4
src/mvvmcore/qtmvvmcore_global.h

@ -11,4 +11,8 @@
# define Q_MVVMCORE_EXPORT Q_DECL_IMPORT
#endif
#ifndef QTMVVM_REVISION_1
#define QTMVVM_REVISION_1 Q_REVISION(1)
#endif
#endif // QTMVVMCORE_GLOBAL_H

2
src/mvvmcore/serviceregistry.cpp

@ -68,7 +68,7 @@ void ServiceRegistry::registerService(const QByteArray &iid, const std::function
registerService(iid, fn, std::move(injectables), DestroyOnAppDestroy, weak);
}
void ServiceRegistry::registerPlugin(QByteArray iid, QString pluginType, QString pluginKey, ServiceRegistry::DestructionScope scope, bool weak)
void ServiceRegistry::registerService(QByteArray iid, QString pluginType, QString pluginKey, ServiceRegistry::DestructionScope scope, bool weak)
{
QMutexLocker _(&d->serviceMutex);
if(d->serviceBlocked(iid))

23
src/mvvmcore/serviceregistry.h

@ -17,12 +17,13 @@ class ServiceRegistryPrivate;
class Q_MVVMCORE_EXPORT ServiceRegistry //MAJOR make a QObject for invokable methods and Q_ENUM
{
public:
//! A scope to indicate when a service should be deleted
enum DestructionScope {
DestroyOnAppQuit = 1,
DestroyOnAppDestroy = 2,
DestroyOnRegistryDestroy = 3,
DestroyOnAppQuit = 1, //!< Destroy when the QCoreApplication::aboutToQuit signal is emitted
DestroyOnAppDestroy = 2, //!< Destroy as soon as the QCoreApplication gets destroyed (typically end of main)
DestroyOnRegistryDestroy = 3, //!< Destroy together with the service registry instance (static memory, unspecified order!)
DestroyNever = 127
DestroyNever = 127 //!< Never destroy the instance
};
//! @private
@ -58,6 +59,7 @@ public:
template <typename TService>
void registerObject(TService *service, DestructionScope scope = DestroyOnAppDestroy, bool weak = false);
//! Register a service via specifing a plugin to be loaded
template <typename TInterface>
void registerPlugin(QString pluginType = {}, QString pluginKey = {}, DestructionScope scope = DestroyOnAppDestroy, bool weak = false);
@ -79,11 +81,12 @@ public:
const std::function<QObject*(const QObjectList &)> &fn,
QByteArrayList injectables,
bool weak);
void registerPlugin(QByteArray iid,
QString pluginType = {},
QString pluginKey = {},
DestructionScope scope = DestroyOnAppDestroy,
bool weak = false);
//! Register a service by an iid via specifing a plugin to be loaded
void registerService(QByteArray iid,
QString pluginType = {},
QString pluginKey = {},
DestructionScope scope = DestroyOnAppDestroy,
bool weak = false);
//! Returns the service for the given interface
template <typename TInterface>
@ -238,7 +241,7 @@ void ServiceRegistry::registerObject(TService *service, DestructionScope scope,
template<typename TInterface>
void ServiceRegistry::registerPlugin(QString pluginType, QString pluginKey, DestructionScope scope, bool weak)
{
registerPlugin(qobject_interface_iid<TInterface*>(), std::move(pluginType), std::move(pluginKey), scope, weak);
registerService(qobject_interface_iid<TInterface*>(), std::move(pluginType), std::move(pluginKey), scope, weak);
}
template<typename TInterface>

78
src/mvvmcore/settingsentry.h

@ -13,6 +13,7 @@
namespace QtMvvm {
//! A generic wrapper around ISettingsAccessor used by the @ref settings_generator "qsettingsgenerator"
template <typename T>
class SettingsEntry
{
@ -21,20 +22,29 @@ class SettingsEntry
public:
SettingsEntry() = default;
//! Checks if the entry is stored in the settings
bool isSet() const;
//! Returns the key this entry uses to access the settings
QString key() const;
//! Loads the value from the settings
T get() const;
//! Stores the passed value in the settings
void set(const T &value);
//! Removes the entry and all child entries from the settings
void reset();
//! Stores the passed value in the settings
SettingsEntry<T> &operator=(const T &value);
//! Loads the value from the settings
operator T() const;
//! Adds a method to be called if the entries value changes
void addChangeCallback(const std::function<void(T)> &callback);
//! Adds a method to be called if the entries value changes, as long as scope exists
void addChangeCallback(QObject *scope, const std::function<void(T)> &callback);
// internal
//! @private
void setup(QString key, ISettingsAccessor *accessor, QVariant defaultValue = {});
private:
@ -43,6 +53,7 @@ private:
QVariant _default;
};
//! @private
template <>
class SettingsEntry<void>
{
@ -51,30 +62,38 @@ class SettingsEntry<void>
public:
inline SettingsEntry() = default;
// internal
//! @private
inline void setup(const QString &, ISettingsAccessor *, const QVariant & = {}) {}
};
//! A helper class used by the @ref settings_generator "qsettingsgenerator" to represent list nodes
template <typename TType>
class SettingsListNode
{
Q_DISABLE_COPY(SettingsListNode)
public:
//! Entry container to make deferred creation of a new list element possible
class Deferred
{
Q_DISABLE_COPY(Deferred)
public:
//! Move constructor
inline Deferred(Deferred &&other) noexcept = default;
//! Move assignment operator
inline Deferred &operator=(Deferred &&other) noexcept = default;
inline ~Deferred() { commit(); }
//! Returns a reference to the element beeing edited
inline TType &element() { return _element; }
//! Indirection operator
inline TType &operator*() { return _element; }
//! Member access operator
inline TType *operator->() { return &_element; }
//! Appends the created element to the list
inline void commit() { if(!_commited) { _commited = true; _node->commit(_index);} }
private:
@ -92,45 +111,76 @@ public:
{}
};
//! The iterator class to iterate through the list nodes entries
template <typename T>
class iterator_base
{
public:
//! @private
using iterator_category = std::random_access_iterator_tag;
//! @private
using difference_type = int;
//! @private
using value_type = T;
//! @private
using pointer = value_type*;
//! @private
using reference = value_type&;
//! Default constructor
inline iterator_base() = default;
//! Copy constructor
inline iterator_base(const iterator_base<T> &other) = default;
//! Copy assignment operator
inline iterator_base &operator=(const iterator_base<T> &other) = default;
//! Move constructor
inline iterator_base(iterator_base<T> &&other) noexcept = default;
//! Move assignment operator
inline iterator_base &operator=(iterator_base<T> &&other) noexcept = default;
//! Posfix increment operator
inline iterator_base<T> &operator++() { ++_index; return *this; }
//! Suffix increment operator
inline iterator_base<T> operator++(int) { return iterator_base<T>{_node, _index++}; }
//! Posfix decrement operator
inline iterator_base<T> &operator--() { --_index; return *this; }
//! Suffix decrement operator
inline iterator_base<T> operator--(int) { return iterator_base<T>{_node, _index--}; }
//! Indirection operator
inline reference operator*() const { return _node->at(_index); }
//! Member access operator
inline pointer operator->() const { return &_node->at(_index); }
//! Swap operator
inline friend void swap(iterator_base<T> &lhs, iterator_base<T> &rhs) noexcept { std::swap(lhs._node, rhs._node); std::swap(lhs._index, rhs._index); }
//! Equality operator
inline friend bool operator==(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index == rhs._index; }
//! Inequality operator
inline friend bool operator!=(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index != rhs._index; }
//! Lesser than operator
inline friend bool operator<(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index < rhs._index; }
//! Geater than operator
inline friend bool operator>(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index > rhs._index; }
//! Lesser equal than operator
inline friend bool operator<=(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index <= rhs._index; }
//! Geater equal than operator
inline friend bool operator>=(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index >= rhs._index; }
//! Compound assignment operator
inline iterator_base<T> &operator+=(difference_type delta) { _index += delta; return *this; }
//! Addition operator
inline friend iterator_base<T> operator+(const iterator_base<T> &iter, difference_type delta) { return iterator_base<T>{iter._node, iter._index + delta}; }
//! Addition operator
inline friend iterator_base<T> operator+(difference_type delta, const iterator_base<T> &iter) { return iterator_base<T>{iter._node, iter._index + delta}; }
//! Compound assignment operator
inline iterator_base<T> &operator-=(difference_type delta) { _index -= delta; return *this; }
//! Substraction operator
inline friend iterator_base<T> operator-(const iterator_base<T> &iter, difference_type delta) { return iterator_base<T>{iter._node, iter._index - delta}; }
//! Substraction operator
inline friend difference_type operator-(const iterator_base<T> &lhs, const iterator_base<T> &rhs) { assert(lhs._node == rhs._node); return lhs._index - rhs._index; }
//! Subscript operator
inline reference operator[](difference_type delta) const { return _node->at(_index + delta); }
private:
@ -145,37 +195,59 @@ public:
{}
};
//! Typedef for a read and write iterator
using iterator = iterator_base<TType>;
//! Typedef for a readonly iterator
using const_iterator = iterator_base<const TType>;
SettingsListNode() = default;
//! Checks if the entry that represents the list node is stored in the settings
bool isSet() const;
//! Returns the key this list node uses to access the settings
QString key() const;
//! Returns the current size of the list, as stored in the settings
int size() const;
//! @copybrief SettingsListNode::at(int)
const TType &at(int index) const;
//! Returns a reference to the element at the given position in the list
TType &at(int index);
//! Appends a new element to the list and returns a reference to that entry
TType &push();
//! Creates a new element and returns it, but does not push it yet
Deferred push_deferred();
//! Removes count elements from the back of the list from the settings
void pop(int count = 1);
//! Removes the list and all of its elements from the settings
void reset();
//! @copybrief SettingsListNode::at(int)
TType &operator[](int index);
//! @copybrief SettingsListNode::at(int)
const TType &operator[](int index) const;
//! returns an iterator pointing to the beginning of the list
iterator begin();
//! returns an iterator pointing after the end of the list
iterator end();
//! @copybrief SettingsListNode::begin()
const_iterator begin() const;
//! @copybrief SettingsListNode::end()
const_iterator end() const;
//! @copybrief SettingsListNode::begin()
const_iterator constBegin() const;
//! @copybrief SettingsListNode::end()
const_iterator constEnd() const;
//! Adds a method to be called if the number of elements stored for the list change
void addChangeCallback(const std::function<void(int)> &callback); // size
//! Adds a method to be called if the number of elements stored for the list change, as long as scope exists
void addChangeCallback(QObject *scope, const std::function<void(int)> &callback);
// internal
//! @private
void setup(QString key, ISettingsAccessor *accessor, std::function<void(int, TType&)> setupFn);
//! @private
void commit(int index);
private:

19
src/mvvmcore/settingsviewmodel.h

@ -19,6 +19,7 @@ class Q_MVVMCORE_EXPORT SettingsViewModel : public ViewModel
{
Q_OBJECT
//! Holds the settings accessor used by the viewmodel to access the settings
Q_PROPERTY(QtMvvm::ISettingsAccessor* accessor READ accessor WRITE setAccessor NOTIFY accessorChanged REVISION 1)
//! Specifies if restoring the defaults is generally allowed
@ -31,6 +32,7 @@ class Q_MVVMCORE_EXPORT SettingsViewModel : public ViewModel
QTMVVM_INJECT(QtMvvm::ISettingsSetupLoader*, settingsSetupLoader)
public:
//! The parameter for an ISettingsAccessor object for the onInit() method
static const QString paramAccessor;
//! The parameter for a QSettings object for the onInit() method
static const QString paramSettings;
@ -39,12 +41,14 @@ public:
//! Generates show parameter to show a settings viewmodel via ViewModel::show
static QVariantHash showParams(ISettingsAccessor *accessor, const QString &setupFile = {});
//! @copydetails SettingsViewModel::showParams(ISettingsAccessor*, const QString &)
static QVariantHash showParams(QSettings *settings, const QString &setupFile = {});
//! Invokable constructor
Q_INVOKABLE explicit SettingsViewModel(QObject *parent = nullptr);
~SettingsViewModel() override;
//! @readAcFn{SettingsViewModel::accessor}
QtMvvm::ISettingsAccessor* accessor() const;
//! @readAcFn{SettingsViewModel::canRestoreDefaults}
virtual bool canRestoreDefaults() const;
@ -65,26 +69,31 @@ public:
Q_INVOKABLE virtual void saveValue(const QString &key, const QVariant &value);
//! Resets the value or group identified by the key
Q_INVOKABLE virtual void resetValue(const QString &key);
Q_REVISION(1) Q_INVOKABLE void resetAll(const SettingsElements::Setup &setup);
//! Resets all values that are defined by the entries in the given setup
QTMVVM_REVISION_1 Q_INVOKABLE void resetAll(const SettingsElements::Setup &setup);
public Q_SLOTS:
//! Is called when an action type edit is pressed
virtual void callAction(const QString &key, const QVariantMap &parameters);
Q_REVISION(1) void setAccessor(QtMvvm::ISettingsAccessor* accessor);
//! @writeAcFn{SettingsViewModel::accessor}
QTMVVM_REVISION_1 void setAccessor(QtMvvm::ISettingsAccessor* accessor);
//! @writeAcFn{SettingsViewModel::settingsSetupLoader}
void setSettingsSetupLoader(QtMvvm::ISettingsSetupLoader* settingsSetupLoader);
Q_SIGNALS:
Q_REVISION(1) void accessorChanged(QtMvvm::ISettingsAccessor* accessor);
//! @notifyAcFn{SettingsViewModel::accessor}
QTMVVM_REVISION_1 void accessorChanged(QtMvvm::ISettingsAccessor* accessor);
//! @notifyAcFn{SettingsViewModel::settingsSetupLoader}
void settingsSetupLoaderChanged(QtMvvm::ISettingsSetupLoader* settingsSetupLoader, QPrivateSignal);
//! Is emitted when the initialization has been completed and the viewmodel is ready for loading settings
void beginLoadSetup();
Q_REVISION(1) void valueChanged(const QString &key); //TODO add to save/reset doc
Q_REVISION(1) void resetAccepted(QPrivateSignal);
//! Signal to be emitted whenver a value in the settings is changed or removed to update the GUI
QTMVVM_REVISION_1 void valueChanged(const QString &key); //TODO add to save/reset doc
//! Is emitted when the user accepted the reset triggered by resetAll()
QTMVVM_REVISION_1 void resetAccepted(QPrivateSignal);
protected:
void onInit(const QVariantHash &params) override;

19
src/mvvmcore/viewmodel.h

@ -37,19 +37,20 @@ Q_SIGNALS:
//! Should be emitted when the viewmodels result is ready
void resultReady(const QVariant &result);
Q_REVISION(1) void instanceInvoked(QPrivateSignal);
//! Is emitted on single instance viewmodels when they get shown again
QTMVVM_REVISION_1 void instanceInvoked(const QVariantHash &params, QPrivateSignal);
protected:
//! Show another viewmodel as a child of this one
template <typename TViewModel>
inline void show(QVariantHash params = {}) const;
inline void show(const QVariantHash &params = {}) const;
//! @copybrief ViewModel::show(const QVariantHash &) const
void show(const char *viewModelName, const QVariantHash &params = {}) const;
//! @copybrief ViewModel::show(const QVariantHash &) const
void show(const QMetaObject *viewMetaObject, const QVariantHash &params = {}) const;
//! Show another viewmodel as a child of this one and expect its result
template <typename TViewModel>
inline void showForResult(quint32 requestCode, QVariantHash params = {}) const;
inline void showForResult(quint32 requestCode, const QVariantHash &params = {}) const;
//! @copybrief ViewModel::showForResult(quint32, const QVariantHash &) const
void showForResult(quint32 requestCode, const char *viewModelName, const QVariantHash &params = {}) const;
//! @copybrief ViewModel::showForResult(quint32, const QVariantHash &) const
@ -64,29 +65,31 @@ private:
static void showImp(const QMetaObject *metaObject, const QVariantHash &params, QPointer<ViewModel> parent, quint32 requestCode = 0);
};
//TODO doc
//! A macro that makes a viewmodel a singleton viewmodel
#define QTMVVM_SINGLETON Q_CLASSINFO("qtmvvm_singleton", "true")
//! A macro to specify the container viewmodel to be used
#define QTMVVM_CONTAINER_VM(x) Q_CLASSINFO("qtmvvm_container_viewmodel", #x)
// ------------- Generic Implementation -------------
template<typename TViewModel>
inline void ViewModel::show(QVariantHash params) const
inline void ViewModel::show(const QVariantHash &params) const
{
static_assert(std::is_base_of<ViewModel, TViewModel>::value, "TViewModel must extend QtMvvm::ViewModel");
showImp(&TViewModel::staticMetaObject, std::move(params), const_cast<ViewModel*>(this));
showImp(&TViewModel::staticMetaObject, params, const_cast<ViewModel*>(this));
}
template<typename TViewModel>
void ViewModel::showForResult(quint32 requestCode, QVariantHash params) const
void ViewModel::showForResult(quint32 requestCode, const QVariantHash &params) const
{
static_assert(std::is_base_of<ViewModel, TViewModel>::value, "TViewModel must extend QtMvvm::ViewModel");
showImp(&TViewModel::staticMetaObject, std::move(params), const_cast<ViewModel*>(this), requestCode);
showImp(&TViewModel::staticMetaObject, params, const_cast<ViewModel*>(this), requestCode);
}
}
Q_DECLARE_METATYPE(QtMvvm::ViewModel*)
//! @file viewmodel.h The Header that defines the QtMvvm::ViewModel class
#endif // QTMVVM_VIEWMODEL_H

2
src/mvvmdatasynccore/datasyncsettingsaccessor.h

@ -40,4 +40,6 @@ private:
}
Q_DECLARE_METATYPE(QtMvvm::DataSyncSettingsAccessor*)
#endif // QTMVVM_DATASYNCSETTINGSACCESSOR_H

11
src/mvvmquick/inputviewfactory.h

@ -6,6 +6,7 @@
#include <QtCore/qscopedpointer.h>
#include <QtCore/qobject.h>
#include <QtCore/qmetaobject.h>
#include <QtMvvmCore/qtmvvmcore_global.h>
#include "QtMvvmQuick/qtmvvmquick_global.h"
@ -49,10 +50,10 @@ public:
//! Find the input list delegate URL of the given input type
Q_INVOKABLE virtual QUrl getDelegate(const QByteArray &type, const QVariantMap &viewProperties);
Q_REVISION(1) Q_INVOKABLE QString format(const QByteArray &type,
const QString &formatString,
const QVariant &value,
const QVariantMap &viewProperties);
QTMVVM_REVISION_1 Q_INVOKABLE QString format(const QByteArray &type,
const QString &formatString,
const QVariant &value,
const QVariantMap &viewProperties);
//! Adds a new QML file to create views for the given type
template <typename TType>
@ -84,7 +85,7 @@ public:
template <typename TAliasType, typename TTargetType>
inline void addFormatterAlias();
Q_REVISION(1) Q_INVOKABLE void addFormatterAlias(const QByteArray &alias, const QByteArray &targetType);
QTMVVM_REVISION_1 Q_INVOKABLE void addFormatterAlias(const QByteArray &alias, const QByteArray &targetType);
private:
QScopedPointer<InputViewFactoryPrivate> d;

12
tests/auto/mvvmcore/coreapp/tst_coreapp.cpp

@ -317,15 +317,21 @@ void CoreAppTest::testPresentVmForResult()
void CoreAppTest::testPresentVmContainer()
{
QVariantHash showParams {
{QStringLiteral("hello"), 13},
{QStringLiteral("qtmvvm_container_params"), QVariantHash{
{QStringLiteral("test"), 42},
}}
};
QVariantHash initMap {
{QStringLiteral("test"), 42},
{QStringLiteral("qtmvvm_container_for"), QByteArray{TestContainedViewModel::staticMetaObject.className()}},
{QStringLiteral("qtmvvm_child_params"), QVariantHash{}}
};
auto presenter = TestApp::presenter();
presenter->presented.clear();
QSignalSpy presentSpy{presenter, &TestPresenter::presentDone};
CoreApp::show<TestContainedViewModel>();
CoreApp::show<TestContainedViewModel>(showParams);
while(presentSpy.size() < 2)
QVERIFY(presentSpy.wait());
@ -341,7 +347,7 @@ void CoreAppTest::testPresentVmContainer()
auto child = std::get<0>(presenter->presented[1]);
QVERIFY(child);
QCOMPARE(child->metaObject(), &TestContainedViewModel::staticMetaObject);
QVERIFY(std::get<1>(presenter->presented[1]).isEmpty());
QCOMPARE(std::get<1>(presenter->presented[1]), showParams);
QCOMPARE(std::get<2>(presenter->presented[1]), vm);
}

44
tools/settingsgenerator/cppsettingsgenerator.cpp

@ -126,8 +126,6 @@ void CppSettingsGenerator::writeSource(const SettingsType &settings)
_src << "#include <QtMvvmCore/QSettingsAccessor>\n";
_src << "\n";
auto backend = settings.backend.value_or(BackendType{QStringLiteral("QtMvvm::QSettingsAccessor"), {}});
_src << "namespace {\n\n"
<< "void __generated_settings_setup()\n"
<< "{\n"
@ -156,26 +154,30 @@ void CppSettingsGenerator::writeSource(const SettingsType &settings)
<< "}\n"
<< "Q_COREAPP_STARTUP_FUNCTION(__generated_settings_setup)\n\n";
_src << settings.name.value() << "::" << settings.name.value() << "(QObject *parent) : \n"
<< "\t" << settings.name.value() << "{new " << backend.className << "{";
if(!backend.param.isEmpty()) {
_src << "\n";
auto first = true;
for(const auto &param : qAsConst(backend.param)) {
if(first)
first = false;
else
_src << ",\n";
_src << "\t\t";
if(param.asStr)
_src << "QVariant{QStringLiteral(\"" << param.value << "\")}.value<" << param.type << ">()";
else
_src << param.value;
_src << settings.name.value() << "::" << settings.name.value() << "(QObject *parent) : \n";
if(settings.backend) {
const auto &backend = settings.backend.value();
_src << "\t" << settings.name.value() << "{new " << backend.className << "{";
if(!backend.param.isEmpty()) {
_src << "\n";
auto first = true;
for(const auto &param : qAsConst(backend.param)) {
if(first)
first = false;
else
_src << ",\n";
_src << "\t\t";
if(param.asStr)
_src << "QVariant{QStringLiteral(\"" << param.value << "\")}.value<" << param.type << ">()";
else
_src << param.value;
}
_src << "\n\t";
}
_src << "\n\t";
}
_src << "}, parent}\n"
<< "{\n"
_src << "}, parent}\n";
} else
_src << "\t" << settings.name.value() << "{QtMvvm::ISettingsAccessor::createDefaultAccessor(nullptr), parent}\n";
_src << "{\n"
<< "\t_accessor->setParent(this);\n"
<< "}\n\n";

Loading…
Cancel
Save