summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/demos/CMakeLists.txt4
-rw-r--r--examples/demos/photoviewer/CMakeLists.txt13
-rw-r--r--examples/demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml31
-rw-r--r--examples/demos/photoviewer/PhotoViewerCore/RssModel.qml9
-rw-r--r--examples/demos/photoviewer/doc/src/photoviewer.qdoc155
-rw-r--r--examples/demos/photoviewer/main.cpp4
-rw-r--r--examples/demos/photoviewer/photoviewer.pro11
-rw-r--r--examples/demos/rssnews/CMakeLists.txt15
-rw-r--r--examples/demos/rssnews/content/NewsDelegate.qml15
-rw-r--r--examples/demos/rssnews/doc/src/rssnews.qdoc132
-rw-r--r--examples/demos/rssnews/rssnews.pro9
-rw-r--r--examples/demos/rssnews/rssnews.qml13
-rw-r--r--examples/demos/shared/xmllistmodel.cpp645
-rw-r--r--examples/demos/shared/xmllistmodel.h264
14 files changed, 147 insertions, 1173 deletions
diff --git a/examples/demos/CMakeLists.txt b/examples/demos/CMakeLists.txt
index 2b42e7720..abbf03617 100644
--- a/examples/demos/CMakeLists.txt
+++ b/examples/demos/CMakeLists.txt
@@ -12,9 +12,7 @@ endif()
if(TARGET Qt::Quick AND TARGET Qt::QuickControls2)
add_subdirectory(coffee)
endif()
-if(TARGET Qt::Quick AND TARGET Qt::Network AND TARGET Qt::Xml)
+if(TARGET Qt::Quick AND TARGET Qt::Network AND TARGET Qt::QmlXmlListModel)
add_subdirectory(rssnews)
-endif()
-if(TARGET Qt::Quick AND TARGET Qt::Network AND TARGET Qt::QuickControls2)
add_subdirectory(photoviewer)
endif()
diff --git a/examples/demos/photoviewer/CMakeLists.txt b/examples/demos/photoviewer/CMakeLists.txt
index b0a8bb1f8..638541fb9 100644
--- a/examples/demos/photoviewer/CMakeLists.txt
+++ b/examples/demos/photoviewer/CMakeLists.txt
@@ -19,24 +19,22 @@ find_package(Qt6 COMPONENTS Core)
find_package(Qt6 COMPONENTS Gui)
find_package(Qt6 COMPONENTS Qml)
find_package(Qt6 COMPONENTS Quick)
+find_package(Qt6 COMPONENTS QmlXmlListModel)
qt_add_executable(photoviewer
- ../shared/xmllistmodel.cpp ../shared/xmllistmodel.h
main.cpp
)
set_target_properties(photoviewer PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
-target_include_directories(photoviewer PUBLIC
- ../shared
-)
target_link_libraries(photoviewer PUBLIC
Qt::Core
Qt::Gui
Qt::Qml
Qt::Quick
+ Qt::QmlXmlListModel
)
@@ -77,10 +75,3 @@ install(TARGETS photoviewer
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)
-
-set_target_properties(photoviewer PROPERTIES
- QT_QML_MODULE_VERSION 1.0
- QT_QML_MODULE_URI XmlListModel
-)
-
-qt6_qml_type_registration(photoviewer)
diff --git a/examples/demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml b/examples/demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
index 0d9d52828..2d62ff882 100644
--- a/examples/demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
+++ b/examples/demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
@@ -49,7 +49,7 @@
****************************************************************************/
import QtQuick
-import XmlListModel
+import QtQml.XmlListModel
import QtQml.Models
Component {
@@ -109,7 +109,7 @@ Component {
Tag {
anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom; bottomMargin: 10 }
frontLabel: tag; backLabel: qsTr("Remove"); flipped: mainWindow.editMode
- onTagChanged: rssModel.tags = tag
+ onTagChanged: function(tag) { rssModel.tags = tag }
onBackClicked: if (mainWindow.editMode) photosModel.remove(index);
}
@@ -129,14 +129,29 @@ Component {
}
]
- GridView.onAdd: NumberAnimation {
- target: albumWrapper; properties: "scale"; from: 0.0; to: 1.0; easing.type: Easing.OutQuad
+ NumberAnimation {
+ id: onAddAmination
+ target: albumWrapper
+ properties: "scale"
+ from: 0.0
+ to: 1.0
+ easing.type: Easing.OutQuad
}
- GridView.onRemove: SequentialAnimation {
- PropertyAction { target: albumWrapper; property: "GridView.delayRemove"; value: true }
- NumberAnimation { target: albumWrapper; property: "scale"; from: 1.0; to: 0.0; easing.type: Easing.OutQuad }
- PropertyAction { target: albumWrapper; property: "GridView.delayRemove"; value: false }
+ GridView.onAdd: onAddAmination
+
+ SequentialAnimation {
+ id: onRemoveAnimation
+ PropertyAction {
+ target: albumWrapper; property: "GridView.delayRemove"; value: true
+ }
+ NumberAnimation {
+ target: albumWrapper; property: "scale"; from: 1.0; to: 0.0; easing.type: Easing.OutQuad
+ }
+ PropertyAction {
+ target: albumWrapper; property: "GridView.delayRemove"; value: false
+ }
}
+ GridView.onRemove: onRemoveAnimation
transitions: [
Transition {
diff --git a/examples/demos/photoviewer/PhotoViewerCore/RssModel.qml b/examples/demos/photoviewer/PhotoViewerCore/RssModel.qml
index 5fb1cce4e..395a30d40 100644
--- a/examples/demos/photoviewer/PhotoViewerCore/RssModel.qml
+++ b/examples/demos/photoviewer/PhotoViewerCore/RssModel.qml
@@ -48,8 +48,7 @@
**
****************************************************************************/
-import QtQuick
-import XmlListModel
+import QtQml.XmlListModel
XmlListModel {
property string tags : ""
@@ -60,8 +59,6 @@ XmlListModel {
query: "/feed/entry"
- roles: [
- XmlListModelRole { elementName: "title"; attributeName: "" },
- XmlListModelRole { elementName: "link"; attributeName: "href" }
- ]
+ XmlListModelRole { name: "title"; elementName: "title"; attributeName: "" }
+ XmlListModelRole { name: "link"; elementName: "link"; attributeName: "href" }
}
diff --git a/examples/demos/photoviewer/doc/src/photoviewer.qdoc b/examples/demos/photoviewer/doc/src/photoviewer.qdoc
index 8f4742460..4f4312a39 100644
--- a/examples/demos/photoviewer/doc/src/photoviewer.qdoc
+++ b/examples/demos/photoviewer/doc/src/photoviewer.qdoc
@@ -29,9 +29,9 @@
\title Qt Quick Demo - Photo Viewer
\ingroup qtquickdemos
\example demos/photoviewer
- \brief A QML photo viewer that uses XmlListModel and XmlListModelRole
- custom QML types to download Flickr feeds, and Package to display the photos
- in different views.
+ \brief A QML photo viewer that uses \l XmlListModel and \l XmlListModelRole
+ to download Flickr feeds, and \l Package to display the photos in different
+ views.
\image qtquick-demo-photoviewer-small.png
@@ -39,14 +39,14 @@
\list
\li Using custom QML types.
- \li Using Qt Quick Controls 1 to create an application window.
+ \li Using Qt Quick Controls to create an application window.
\li Using the \l Package type with a \l DelegateModel to provide
delegates with a shared context to multiple views.
- \li Using custom types to download Flickr feeds.
+ \li Using XML list models to download Flickr feeds.
\li Using the \l Flipable type to create labels with different text on
the front and back.
- \li Using the PathView, \l Path, PathAttribute, and PathLine types to
- lay out photos on a path.
+ \li Using the \l PathView, \l Path, \l PathAttribute, and \l PathLine
+ types to lay out photos on a path.
\li Providing feedback to users while data is loading.
\li Localizing applications.
\endlist
@@ -70,59 +70,17 @@
\endlist
To use the custom types, we add an import statement to the main QML file,
- main.qml, that imports the folder called \c PhotoViewerCore where the types
- are located:
+ \c main.qml, that imports the folder called \c PhotoViewerCore where the
+ types are located:
\quotefromfile demos/photoviewer/main.qml
\skipto PhotoViewerCore
\printuntil "
- We also use the following custom types that are defined in C++:
-
- \list
- \li \c XmlListModel
- \li \c XmlListModelRole
- \endlist
-
- To register QML types from C++ we add the QML_ELEMENT macro to the QObject
- derived classes' definitions like this:
-
- \quotefromfile demos/shared/xmllistmodel.h
- \skipto XmlListModelRole
- \printuntil QML_ELEMENT
-
- In addition we need to add the following to the CMakeLists.txt file of the
- example:
-
- \quotefromfile demos/photoviewer/CMakeLists.txt
- \skipto set_target_properties
- \printuntil PROPERTIES
- \skipto QT_QML_MODULE_VERSION 1.0
- \printuntil qt6_qml_type_registration(photoviewer)
-
- To build with qmake, we add \c CONFIG += qmltypes, \c QML_IMPORT_NAME, and
- \c QML_IMPORT_MAJOR_VERSION to the project file:
-
- \quotefromfile demos/photoviewer/photoviewer.pro
- \skipto CONFIG
- \printuntil qmltypes
- \skipto QML_IMPORT_NAME
- \printuntil QML_IMPORT_MAJOR_VERSION
-
- For more information on defining QML types from C++ see the
- \l {Defining QML Types from C++} documentation.
-
- To use the new types, we add an import statement that imports them to the QML
- files that use the types:
-
- \quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
- \skipto XmlListModel
- \printuntil import
-
\section1 Creating the Main Window
- In main.qml, we use the ApplicationWindow Qt Quick Control to create the app
- main window:
+ In \c main.qml, we use the \l ApplicationWindow Qt Quick Control to create the
+ app main window:
\quotefromfile demos/photoviewer/main.qml
\skipto ApplicationWindow
@@ -139,31 +97,31 @@
how the data is accessed and include the data itself. For each list element,
we use the \c tag role to specify the photos to download.
- A DelegateModel type is used together with the \l Package type to provide
+ A \l DelegateModel type is used together with the \l Package type to provide
delegates to multiple views. The \c model property holds the model providing
data for the delegate model and the \c delegate property specifies the
template defining each item instantiated by a view:
\printuntil DelegateModel
- We use a GridView type to lay out the albums as a grid:
+ We use a \l GridView type to lay out the albums as a grid:
\printuntil }
The \c model property references the package name \c album that we specify
- in AlbumDelegate.qml. We use the \l Package type to allow the photos to move
- between different views. The \l Package contains the named items \c browser,
- \c fullscreen, and \c album:
+ in \c AlbumDelegate.qml. We use the \l Package type to allow the photos
+ to move between different views. The \l Package contains the named items
+ \c browser, \c fullscreen, and \c album:
\quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
\skipto Package
\printuntil albumWrapper
The named items are used as the delegates by the views that reference the
- special DelegateModel::parts property to select the model that provides
+ special \l {DelegateModel::parts} property to select the model that provides
the chosen delegate.
- We use a ListView type to lay out albums in other views:
+ We use a \l ListView type to lay out albums in other views:
\quotefromfile demos/photoviewer/main.qml
\skipto ListView
@@ -173,9 +131,9 @@
\section1 Displaying Photos
- We use the PhotoDelegate custom type that is specified in PhotoDelegate.qml
- to display photos. We use a \l Package type to lay out the photos either in
- a stack, list, or a grid:
+ We use the \c PhotoDelegate custom type that is specified in
+ \c PhotoDelegate.qml to display photos. We use a \l Package type to lay
+ out the photos either in a stack, list, or a grid:
\quotefromfile demos/photoviewer/PhotoViewerCore/PhotoDelegate.qml
\skipto Package
@@ -186,22 +144,22 @@
\printuntil stackItem
- We use a BorderImage type to create borders for the images:
+ We use a \l BorderImage type to create borders for the images:
\printuntil border.left
\printuntil }
\section1 Downloading Flickr Feeds
- In AlbumDelegate.qml, we use the DelegateModel to provide the
- PhotoDelegate delegate to the RssModel model:
+ In \c AlbumDelegate.qml, we use the \l DelegateModel to provide the
+ \c PhotoDelegate delegate to the \c RssModel model:
\quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
\skipto DelegateModel
\printuntil RssModel
\printuntil }
- In RssModel.qml, we use the XmlListModel custom type as a data source for
+ In \c RssModel.qml, we use the \l XmlListModel type as a data source for
\l Package objects to download photos from the selected feeds:
\quotefromfile demos/photoviewer/PhotoViewerCore/RssModel.qml
@@ -217,10 +175,10 @@
\printuntil query
- The \c query property specifies that the XmlListModel generates a model item
- for each feed entry.
+ The \c query property specifies that the \l XmlListModel generates a model
+ item for each feed entry.
- We use the XmlListModelRole custom type to specify the model item attributes.
+ We use the \l XmlListModelRole type to specify the model item attributes.
Each model item has the \c title and \c link attributes that match the
values of the corresponding feed entry:
@@ -232,8 +190,8 @@
their front side to their back side and the text on them changes from album
name to \b Remove.
- In AlbumDelegate.qml, we use the Tag custom type to specify the text to
- display on the front and back sides of album labels:
+ In \c AlbumDelegate.qml, we use the \c Tag custom type to specify the
+ text to display on the front and back sides of album labels:
\quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
\skipto Tag
@@ -244,14 +202,14 @@
which the model is populated. The \c onBackClicked signal handler is used to
remove the album.
- In Tag.qml, we use a \l Flipable type with custom properties and signals to
- create the labels:
+ In \c Tag.qml, we use a \l Flipable type with custom properties and
+ signals to create the labels:
\quotefromfile demos/photoviewer/PhotoViewerCore/Tag.qml
\skipto Flipable
\printuntil tagChanged
- The \c front property holds the EditableButton custom type that enables
+ The \c front property holds the \c EditableButton custom type that enables
users to edit the label text:
\printuntil onLabelChanged
@@ -265,9 +223,9 @@
\section1 Laying Out Photos on a Path
- In AlbumDelegate.qml, we use a PathView type to lay out the photos provided
- by the \c visualModel.parts.stack model on a path that has the form of a
- stack:
+ In \c AlbumDelegate.qml, we use a \l PathView type to lay out the photos
+ provided by the \c visualModel.parts.stack model on a path that has the
+ form of a stack:
\quotefromfile demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml
\skipto PathView
@@ -276,17 +234,17 @@
\printuntil }
The \c path property holds the \l Path type that defines the path used by
- the PathView. The PathAttribute types are used to set a range of
+ the \l PathView. The \l PathAttribute types are used to set a range of
\c 0 to \c 9999 for the \c z attribute. This way, the path creates a stack
- of album photos. Because each PhotoDelegate is slightly rotated at a random
- angle, this results in a realistic-looking stack of photos.
+ of album photos. Because each \c PhotoDelegate is slightly rotated at a
+ random angle, this results in a realistic-looking stack of photos.
\section1 Providing Feedback to Users
We use a busy indicator and a progress bar to indicate activity while
Flickr feeds and photos are being loaded.
- In AlbumDelegate.qml, we use the \c BusyIndicator custom type and the
+ In \c AlbumDelegate.qml, we use the \c BusyIndicator custom type and the
\c on custom property to display a rotating image while the Flickr feed is
being loaded:
@@ -295,7 +253,7 @@
\printuntil rssModel
\printuntil }
- In PhotoDelegate.qml, we use them to indicate activity while a photo is
+ In \c PhotoDelegate.qml, we use them to indicate activity while a photo is
being loaded:
\quotefromfile demos/photoviewer/PhotoViewerCore/PhotoDelegate.qml
@@ -303,18 +261,18 @@
\printuntil }
We define the \c BusyIndicator type in \c BusyIndicator.qml. We use an
- \l Image type to display an image and apply a NumberAnimation to its
- \c rotation property to rotate the image in an infinite loop:
+ \l [QML] {Image} type to display an image and apply a \l NumberAnimation to
+ its \c rotation property to rotate the image in an infinite loop:
\quotefromfile demos/photoviewer/PhotoViewerCore/BusyIndicator.qml
\skipto Image
\printuntil }
\printuntil }
- In your apps, you can also use the BusyIndicator type from the
+ In your apps, you can also use the \l BusyIndicator type from the
\l {Qt Quick Controls} module.
- In main.qml, we use the \c ProgressBar custom type to indicate progress
+ In \c main.qml, we use the \c ProgressBar custom type to indicate progress
while a high quality version of a photo is being opened on full screen:
\quotefromfile demos/photoviewer/main.qml
@@ -322,15 +280,15 @@
\printuntil }
We define the \c ProgressBar type in \c ProgressBar.qml. We use a
- \l Rectangle type to create the progress bar and apply a NumberAnimation to
- its \c opacity property to change the color of the bar from black to white
- as data loading proceeds:
+ \l Rectangle type to create the progress bar and apply a \l NumberAnimation
+ to its \c opacity property to change the color of the bar from black to
+ white as data loading proceeds:
\quotefromfile demos/photoviewer/PhotoViewerCore/ProgressBar.qml
\skipto Item
\printuntil /^\}/
- In your apps, you can also use the ProgressBar type from the
+ In your apps, you can also use the \l ProgressBar type from the
\l {Qt Quick Controls} module.
\section1 Localizing Applications
@@ -338,7 +296,7 @@
The example application is translated into German and French. The translated
strings are loaded at runtime according to the current locale.
- We use a \l Column type in main.qml to position buttons for adding and
+ We use a \l Column type in \c main.qml to position buttons for adding and
editing albums and exiting the application:
\quotefromfile demos/photoviewer/main.qml
@@ -347,17 +305,18 @@
\printuntil }
\printuntil }
- We use the \l[QML]{Qt::}{qsTr()} command to mark the button labels translatable.
+ We use the \l[QML]{Qt::}{qsTr()} command to mark the button labels
+ translatable.
- We use the \c lupdate() tool to generate the translation source files and
- the \c lrelease() tool to convert the translated strings to the QM files used
+ We use the \c lupdate tool to generate the translation source files and
+ the \c lrelease tool to convert the translated strings to the QM files used
by the application at runtime. These files are stored in the \c i18n
directory.
To make the application aware of the translations, we add code to the
- \c main() function in the main.cpp file. The code creates a \l QTranslator
- object, loads a translation according to the current locale at runtime, and
- installs the translator object into the application:
+ \c main() function in the \c {main.cpp} file. The code creates a
+ \l QTranslator object, loads a translation according to the current locale
+ at runtime, and installs the translator object into the application:
\quotefromfile demos/photoviewer/main.cpp
\skipto main
diff --git a/examples/demos/photoviewer/main.cpp b/examples/demos/photoviewer/main.cpp
index e9d828230..3281e520e 100644
--- a/examples/demos/photoviewer/main.cpp
+++ b/examples/demos/photoviewer/main.cpp
@@ -58,8 +58,8 @@ int main(int argc, char *argv[])
QGuiApplication app(argc, argv);
QTranslator qtTranslator;
- qtTranslator.load(QLocale(), "qml", "_", ":/i18n/");
- app.installTranslator(&qtTranslator);
+ if (qtTranslator.load(QLocale(), "qml", "_", ":/i18n/"))
+ app.installTranslator(&qtTranslator);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
diff --git a/examples/demos/photoviewer/photoviewer.pro b/examples/demos/photoviewer/photoviewer.pro
index 2d3d34aff..57289e84f 100644
--- a/examples/demos/photoviewer/photoviewer.pro
+++ b/examples/demos/photoviewer/photoviewer.pro
@@ -1,16 +1,9 @@
TEMPLATE = app
QT += qml quick
-CONFIG += lrelease embed_translations qmltypes
+CONFIG += lrelease embed_translations
-INCLUDEPATH += ../shared
-
-HEADERS += ../shared/xmllistmodel.h
-SOURCES += main.cpp \
- ../shared/xmllistmodel.cpp
-
-QML_IMPORT_NAME = XmlListModel
-QML_IMPORT_MAJOR_VERSION = 1
+SOURCES += main.cpp
lupdate_only {
SOURCES = *.qml \
diff --git a/examples/demos/rssnews/CMakeLists.txt b/examples/demos/rssnews/CMakeLists.txt
index ed8255c1d..ef1c35bf3 100644
--- a/examples/demos/rssnews/CMakeLists.txt
+++ b/examples/demos/rssnews/CMakeLists.txt
@@ -19,26 +19,22 @@ find_package(Qt6 COMPONENTS Core)
find_package(Qt6 COMPONENTS Gui)
find_package(Qt6 COMPONENTS Quick)
find_package(Qt6 COMPONENTS Qml)
-find_package(Qt6 COMPONENTS Xml)
+find_package(Qt6 COMPONENTS QmlXmlListModel)
qt_add_executable(rssnews
- ../shared/xmllistmodel.cpp ../shared/xmllistmodel.h
main.cpp
)
set_target_properties(rssnews PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
-target_include_directories(rssnews PUBLIC
- ../shared
-)
target_link_libraries(rssnews PUBLIC
Qt::Core
Qt::Gui
Qt::Qml
Qt::Quick
- Qt::Xml
+ Qt::QmlXmlListModel
)
@@ -79,10 +75,3 @@ install(TARGETS rssnews
BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
)
-
-set_target_properties(rssnews PROPERTIES
- QT_QML_MODULE_VERSION 1.0
- QT_QML_MODULE_URI XmlListModel
-)
-
-qt6_qml_type_registration(rssnews)
diff --git a/examples/demos/rssnews/content/NewsDelegate.qml b/examples/demos/rssnews/content/NewsDelegate.qml
index fb6b3045e..9ed8bbd1d 100644
--- a/examples/demos/rssnews/content/NewsDelegate.qml
+++ b/examples/demos/rssnews/content/NewsDelegate.qml
@@ -102,6 +102,8 @@ Column {
Image {
id: titleImage
source: content
+ width: Math.min(delegate.width / 2, sourceSize.width)
+ fillMode: Image.PreserveAspectFit
}
}
@@ -122,19 +124,8 @@ Column {
textFormat: Text.RichText
font.italic: true
text: timeSinceEvent(pubDate) + " (<a href=\"" + link + "\">Link</a>)"
- onLinkActivated: {
+ onLinkActivated: function(link) {
Qt.openUrlExternally(link)
}
}
-
- Text {
- id: descriptionText
-
- text: description.replace(/\<a href=.*\/a\>/, '')
- width: parent.width
- wrapMode: Text.WordWrap
- font.pixelSize: 14
- textFormat: Text.StyledText
- horizontalAlignment: Qt.AlignLeft
- }
}
diff --git a/examples/demos/rssnews/doc/src/rssnews.qdoc b/examples/demos/rssnews/doc/src/rssnews.qdoc
index e0ec016a0..40bc924f6 100644
--- a/examples/demos/rssnews/doc/src/rssnews.qdoc
+++ b/examples/demos/rssnews/doc/src/rssnews.qdoc
@@ -40,11 +40,12 @@
\list
\li Using custom QML types.
\li Using list models and list elements to represent data.
- \li Using custom list models to download XML data.
+ \li Using XML list models to download XML data.
\li Using list views to display data.
\li Using the \l Component type to create a footer for the news item
list view.
- \li Using the \l Image type to create a button for closing the app.
+ \li Using the \l [QML] {Image} type to create a button for closing the
+ app.
\endlist
\include examples-run.qdocinc
@@ -70,53 +71,10 @@
\skipto content
\printuntil "
- We also use the following custom types that are defined in C++:
-
- \list
- \li \c XmlListModel
- \li \c XmlListModelRole
- \endlist
-
- To register QML types from C++ we add the \l QML_ELEMENT macro to the QObject
- derived classes' definitions like this:
-
- \quotefromfile demos/shared/xmllistmodel.h
- \skipto XmlListModelRole
- \printuntil QML_ELEMENT
-
- In addition we need to add the following to the CMakeLists.txt file of the
- example:
-
- \quotefromfile demos/rssnews/CMakeLists.txt
- \skipto set_target_properties
- \printuntil PROPERTIES
- \skipto QT_QML_MODULE_VERSION 1.0
- \printuntil qt6_qml_type_registration(rssnews)
-
- To build with qmake, we add \c CONFIG += qmltypes, \c QML_IMPORT_NAME, and
- \c QML_IMPORT_MAJOR_VERSION to the project file:
-
- \quotefromfile demos/rssnews/rssnews.pro
- \skipto CONFIG
- \printuntil qmltypes
- \skipto QML_IMPORT_NAME
- \printuntil QML_IMPORT_MAJOR_VERSION
-
- For more information on defining QML types from C++ see the
- \l {Defining QML Types from C++} documentation.
-
- To use the new types, we add an import statement that imports them to the QML
- files that use the types:
-
- \quotefromfile demos/rssnews/rssnews.qml
- \skipto XmlListModel
- \printuntil import
-
-
\section1 Creating the Main Window
- In rssnews.qml, we use a \l{Rectangle} type with custom properties to create
- the app main window:
+ In \c rssnews.qml, we use a \l{Rectangle} type with custom properties to
+ create the app main window:
\printuntil isPortrait
@@ -125,13 +83,13 @@
\section1 Creating a Category List
- In rssnews.qml, we use the RssFeeds custom type that we specify in
- RssFeeds.qml to create a list of feed categories:
+ In \c rssnews.qml, we use the \c RssFeeds custom type that we specify in
+ \c RssFeeds.qml to create a list of feed categories:
\skipto RssFeeds
\printuntil }
- In RssFeeds.qml, we use a ListModel type with a ListElement type to
+ In \c RssFeeds.qml, we use a \l ListModel type with a \l ListElement type to
create a category list where list elements represent feed categories:
\quotefromfile demos/rssnews/content/RssFeeds.qml
@@ -146,7 +104,7 @@
the \c feed role to specify the URL to load the data from, and the \c image
role to display an image for the category.
- In rssnews.qml, we use a ListView type to display the category list:
+ In \c rssnews.qml, we use a \l ListView type to display the category list:
\quotefromfile demos/rssnews/rssnews.qml
\skipto ListView
@@ -168,8 +126,8 @@
\section1 Creating List Elements
- In CategoryDelegate.qml, we use the \l Rectangle type with custom properties
- to create list elements:
+ In \c CategoryDelegate.qml, we use the \l Rectangle type with custom
+ properties to create list elements:
\quotefromfile demos/rssnews/content/CategoryDelegate.qml
\skipto Rectangle
@@ -179,9 +137,9 @@
property to specify that \c selected is \c true if \c delegate is the
current item.
- We use the \l Image type \c source property to display the image, centered
- in the delegate, specified for the list element by the \c image role in the
- \c rssFeeds list model:
+ We use the \l [QML] {Image} type \c source property to display the image,
+ centered in the delegate, specified for the list element by the \c image
+ role in the \c rssFeeds list model:
\skipto Image
\printuntil }
@@ -195,13 +153,13 @@
element, with a 20-pixel margin. We use \c font properties to adjust font
size and text formatting.
- We use the \c color property to brighten the text and to scale it slightly
- larger when the list item is the current item. By applying a \l Behavior to
- the property, we animate the actions of selecting and deselecting list
- items.
+ We use the \c color and \c scale properties to brighten the text and to
+ scale it slightly larger when the list item is the current item.
+ By applying a \l Behavior to the property, we animate the actions of
+ selecting and deselecting list items.
- We use a MouseArea type to download XML data when users tap a category list
- element:
+ We use a \l MouseArea type to download XML data when users tap a category
+ list element:
\skipto MouseArea
\printuntil }
@@ -216,8 +174,8 @@
\section1 Downloading XML Data
- In rssnews.qml, we use an XmlListModel custom type as a data source for ListView
- elements to display news items in the selected category:
+ In \c rssnews.qml, we use an \l XmlListModel type as a data source for
+ \l ListView elements to display news items in the selected category:
\quotefromfile demos/rssnews/rssnews.qml
\skipto XmlListModel {
@@ -226,18 +184,18 @@
We use the \c source property and the \c window.currentFeed custom property
to fetch news items for the selected category.
- The \c query property specifies that the XmlListModel generates a model item
- for each \c <item> in the XML document.
+ The \c query property specifies that the \l XmlListModel generates a model
+ item for each \c <item> in the XML document.
- We use the XmlListModelRole custom type to specify the model item attributes.
- Each model item has the \c title, \c description, \c content, \c link, and \c pubDate
- attributes that match the values of the corresponding \c <item> in the XML
- document:
+ We use the \l XmlListModelRole type to specify the model item attributes.
+ Each model item has the \c title, \c content, \c link, and \c pubDate
+ attributes that match the values of the corresponding \c <item> in the
+ XML document:
\printuntil pubDate
\printuntil }
- We use the \c feedModel model in a ListView type to display the data:
+ We use the \c feedModel model in a \l ListView type to display the data:
\skipuntil ScrollBar
\skipto ListView
@@ -262,7 +220,7 @@
and use \c NewsDelegate as the delegate to instantiate each item in the
list.
- In NewsDelegate.qml, we use a \l Column type to lay out the XML data:
+ In \c NewsDelegate.qml, we use a \l Column type to lay out the XML data:
\quotefromfile demos/rssnews/content/NewsDelegate.qml
\skipto Column
@@ -287,8 +245,8 @@
\section1 Providing Feedback to Users
- In CategoryDelegate.qml, we use the \c BusyIndicator custom type to indicate
- activity while the XML data is being loaded:
+ In \c CategoryDelegate.qml, we use the \c BusyIndicator custom type to
+ indicate activity while the XML data is being loaded:
\quotefromfile demos/rssnews/content/CategoryDelegate.qml
\skipto BusyIndicator
@@ -301,22 +259,22 @@
data is being loaded.
We define the \c BusyIndicator type in \c BusyIndicator.qml. We use an
- \l Image type to display an image and apply a NumberAnimation to its
- \c rotation property to rotate the image in an infinite loop:
+ \l [QML] {Image} type to display an image and apply a \l NumberAnimation to
+ its \c rotation property to rotate the image in an infinite loop:
\quotefromfile demos/rssnews/content/BusyIndicator.qml
\skipto Image
\printuntil }
\printuntil }
- In your apps, you can also use the BusyIndicator type from the
+ In your apps, you can also use the \l BusyIndicator type from the
\l {Qt Quick Controls} module.
\section1 Creating Scroll Bars
- In rssnews.qml, we use our own custom \c ScrollBar type to create scroll
+ In \c rssnews.qml, we use our own custom \c ScrollBar type to create scroll
bars in the category and news item list views. In your apps, you can also
- use the ScrollView type from the \l {Qt Quick Controls} module.
+ use the \l ScrollView type from the \l {Qt Quick Controls} module.
First, we create a scroll bar in the category list view. We bind the
\c orientation property to the \c isPortrait property and to the
@@ -356,7 +314,7 @@
\skipto Item
\printuntil opacity
- We use a BorderImage type to display the scroll bar thumb at the x and y
+ We use a \l BorderImage type to display the scroll bar thumb at the x and y
position that we calculate by using the \c position() function:
\skipto BorderImage
@@ -372,14 +330,14 @@
\printuntil }
\printuntil }
- We use \c transitions to apply a NumberAnimation to the \c "opacity"
- property when the state changes from "visible" to the default state:
+ We use \c transitions to apply a \l NumberAnimation to the \c opacity
+ property when the state changes from \c "visible" to the default state:
\printuntil /^\}/
\section1 Creating Footers
- In rssnews.qml, we use a \l Component type with a \l Rectangle type to
+ In \c rssnews.qml, we use a \l Component type with a \l Rectangle type to
create a footer for the news list view:
\quotefromfile demos/rssnews/rssnews.qml
@@ -389,13 +347,13 @@
\printuntil }
We bind the \c width of the footer to the width of the component and the
- \c height to the of close button to align them when no news items are
+ \c height to the height of close button to align them when no news items are
displayed.
\section1 Creating Buttons
- In rssnews.qml, we use an \l Image type to create a simple push button that
- users can tap to close the app:
+ In \c rssnews.qml, we use an \l [QML] {Image} type to create a simple push
+ button that users can tap to close the app:
\printuntil Qt.quit()
\printuntil }
@@ -408,7 +366,7 @@
property to make the button almost fully transparent when users are
scrolling the category list.
- We use the \c onClicked signal handler within a MouseArea to call the
+ We use the \c onClicked signal handler within a \l MouseArea to call the
\c quit() function when users select the close button.
\sa {QML Applications}
diff --git a/examples/demos/rssnews/rssnews.pro b/examples/demos/rssnews/rssnews.pro
index a64ad9b99..c90789f33 100644
--- a/examples/demos/rssnews/rssnews.pro
+++ b/examples/demos/rssnews/rssnews.pro
@@ -1,13 +1,8 @@
TEMPLATE = app
-QT += quick qml xml
-CONFIG += qmltypes
+QT += quick qml
-INCLUDEPATH += ../shared
-
-HEADERS += ../shared/xmllistmodel.h
-SOURCES += main.cpp \
- ../shared/xmllistmodel.cpp
+SOURCES += main.cpp
QML_IMPORT_NAME = XmlListModel
QML_IMPORT_MAJOR_VERSION = 1
diff --git a/examples/demos/rssnews/rssnews.qml b/examples/demos/rssnews/rssnews.qml
index 0bdd5f84f..85f56ae33 100644
--- a/examples/demos/rssnews/rssnews.qml
+++ b/examples/demos/rssnews/rssnews.qml
@@ -50,7 +50,7 @@
import QtQuick
import QtQuick.Window
-import XmlListModel
+import QtQml.XmlListModel
import "./content"
Rectangle {
@@ -76,13 +76,10 @@ Rectangle {
source: "https://" + window.currentFeed
query: "/rss/channel/item"
- roles: [
- XmlListModelRole { elementName: "title"; attributeName: ""},
- XmlListModelRole { elementName: "description"; attributeName: ""},
- XmlListModelRole { elementName: "content"; attributeName: "url" },
- XmlListModelRole { elementName: "link"; attributeName: "" },
- XmlListModelRole { elementName: "pubDate"; attributeName: "" }
- ]
+ XmlListModelRole { name: "title"; elementName: "title"; attributeName: ""}
+ XmlListModelRole { name: "content"; elementName: "content"; attributeName: "url" }
+ XmlListModelRole { name: "link"; elementName: "link"; attributeName: "" }
+ XmlListModelRole { name: "pubDate"; elementName: "pubDate"; attributeName: "" }
}
ListView {
diff --git a/examples/demos/shared/xmllistmodel.cpp b/examples/demos/shared/xmllistmodel.cpp
deleted file mode 100644
index 8595b6d04..000000000
--- a/examples/demos/shared/xmllistmodel.cpp
+++ /dev/null
@@ -1,645 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "xmllistmodel.h"
-
-#include <QQmlFile>
-#include <QFile>
-#include <QCoreApplication>
-#include <QMutexLocker>
-
-Q_DECLARE_METATYPE(XmlListModelQueryResult)
-
-QHash<QQmlEngine *, XmlListModelQueryEngine*> XmlListModelQueryEngine::queryEngines;
-QMutex XmlListModelQueryEngine::queryEnginesMutex;
-
-XmlListModelQueryThreadObject::XmlListModelQueryThreadObject(XmlListModelQueryEngine *e)
- : m_queryEngine(e)
-{
-}
-
-void XmlListModelQueryThreadObject::processJobs()
-{
- QCoreApplication::postEvent(this, new QEvent(QEvent::User));
-}
-
-bool XmlListModelQueryThreadObject::event(QEvent *e)
-{
- if (e->type() == QEvent::User) {
- m_queryEngine->processJobs();
- return true;
- }
- return QObject::event(e);
-}
-
-XmlListModelQueryEngine::XmlListModelQueryEngine(QQmlEngine *eng)
-: QThread(eng), m_threadObject(nullptr), m_queryIds(1), m_engine(eng), m_eventLoopQuitHack(nullptr)
-{
- qRegisterMetaType<XmlListModelQueryResult>("XmlListModelQueryResult");
-
- m_eventLoopQuitHack = new QObject;
- m_eventLoopQuitHack->moveToThread(this);
-
- connect(m_eventLoopQuitHack, &QObject::destroyed,
- this, &QThread::quit, Qt::DirectConnection);
- start(QThread::IdlePriority);
-}
-
-XmlListModelQueryEngine::~XmlListModelQueryEngine()
-{
- queryEnginesMutex.lock();
- queryEngines.remove(m_engine);
- queryEnginesMutex.unlock();
-
- m_eventLoopQuitHack->deleteLater();
- wait();
-}
-
-void XmlListModelQueryEngine::abort(int id)
-{
- QMutexLocker ml(&m_mutex);
- if (id != -1)
- m_cancelledJobs.insert(id);
-}
-
-void XmlListModelQueryEngine::run()
-{
- m_mutex.lock();
- m_threadObject = new XmlListModelQueryThreadObject(this);
- m_mutex.unlock();
-
- processJobs();
- exec();
-
- delete m_threadObject;
- m_threadObject = nullptr;
-}
-
-XmlListModelQueryEngine *XmlListModelQueryEngine::instance(QQmlEngine *engine)
-{
- QMutexLocker ml(&queryEnginesMutex);
- XmlListModelQueryEngine *queryEng = queryEngines.value(engine);
- if (!queryEng) {
- queryEng = new XmlListModelQueryEngine(engine);
- queryEngines.insert(engine, queryEng);
- }
-
- return queryEng;
-}
-
-int XmlListModelQueryEngine::doQuery(QString query, QByteArray data, QList<XmlListModelRole *>* roles)
-{
- {
- QMutexLocker m1(&m_mutex);
- m_queryIds.ref();
- if (m_queryIds.loadRelaxed() <= 0)
- m_queryIds.storeRelaxed(1);
- }
-
- XmlListModelQueryJob job;
- job.queryId = m_queryIds.loadRelaxed();
- job.data = data;
- job.query = query;
-
- for (int i = 0; i < roles->count(); i++) {
- if (!roles->at(i)->isValid()) {
- job.roleNames << QString();
- job.roleQueries << QString();
- continue;
- }
- job.roleNames << roles->at(i)->elementName();
- job.roleQueries << roles->at(i)->attributeName();
- job.roleQueryErrorId << static_cast<void*>(roles->at(i));
- }
-
- {
- QMutexLocker ml(&m_mutex);
- m_jobs.append(job);
- if (m_threadObject)
- m_threadObject->processJobs();
- }
-
- return job.queryId;
-}
-
-void XmlListModelQueryEngine::processJobs()
-{
- QMutexLocker locker(&m_mutex);
-
- while (true) {
- if (m_jobs.isEmpty())
- return;
-
- XmlListModelQueryJob currentJob = m_jobs.takeLast();
- while (m_cancelledJobs.remove(currentJob.queryId)) {
- if (m_jobs.isEmpty())
- return;
- currentJob = m_jobs.takeLast();
- }
-
- locker.unlock();
- processQuery(&currentJob);
- locker.relock();
- }
-}
-
-void XmlListModelQueryEngine::processQuery(XmlListModelQueryJob *job)
-{
- XmlListModelQueryResult result;
- result.queryId = job->queryId;
- doQueryJob(job, &result);
-
- QMutexLocker ml(&m_mutex);
- if (m_cancelledJobs.contains(job->queryId)) {
- m_cancelledJobs.remove(job->queryId);
- } else {
- ml.unlock();
- Q_EMIT queryCompleted(result);
- }
-}
-
-void XmlListModelQueryEngine::doQueryJob(XmlListModelQueryJob *currentJob, XmlListModelQueryResult *currentResult)
-{
- Q_ASSERT(currentJob->queryId != -1);
-
- QByteArray data(currentJob->data);
- QXmlStreamReader reader;
- reader.addData(data);
-
- QStringList items = currentJob->query.split(QLatin1Char('/'), Qt::SkipEmptyParts);
-
- while (!reader.atEnd()) {
- int i = 0;
- while (i < items.count()) {
- if (reader.readNextStartElement()) {
- if (reader.name() == items.at(i)) {
- if (i != items.count() - 1) {
- i++;
- continue;
- } else {
- processElement(currentJob, currentResult, items.at(i), reader);
- }
- } else {
- reader.skipCurrentElement();
- }
- }
- if (reader.tokenType() == QXmlStreamReader::Invalid) {
- reader.readNext();
- break;
- }
- else if (reader.hasError()) {
- reader.raiseError();
- break;
- }
- }
- }
-}
-
-void XmlListModelQueryEngine::processElement(XmlListModelQueryJob *currentJob, XmlListModelQueryResult*& currentResult, QString element, QXmlStreamReader &reader)
-{
- if (!reader.isStartElement() || reader.name() != element)
- return;
-
- const QStringList &roleQueries = currentJob->roleQueries;
- const QStringList &roleNames = currentJob->roleNames;
- QHash<int, QString> resultList;
-
-
- while (reader.readNextStartElement()) {
-
- if (roleNames.contains(reader.name()) && !reader.name().isEmpty()) {
- bool hasLink = false;
- bool hasJpegImageLink = false;
-
- QString roleResult;
- const int index = roleNames.indexOf(reader.name());
-
- if (!roleQueries.at(index).isEmpty()) {
- if (reader.attributes().hasAttribute(roleQueries.at(index))) {
- if (roleQueries.at(index) == "href") {
- hasLink = true;
- if (reader.attributes().value("type").toString() == "image/jpeg")
- hasJpegImageLink = true;
- }
- roleResult = reader.attributes().value(roleQueries.at(index)).toString();
- } else {
- Q_EMIT error(currentJob->roleQueryErrorId.at(index), roleQueries[index]);
- }
- } else if (!roleNames.at(index).isEmpty()) {
- roleResult = reader.readElementText();
- }
-
- if (hasLink && !hasJpegImageLink)
- reader.skipCurrentElement();
- else
- resultList[index] = roleResult;
-
- } else {
- reader.skipCurrentElement();
- }
- }
-
- if (resultList.count() <= 0)
- resultList = QHash<int, QString>();
- currentResult->data << resultList;
-}
-
-QString XmlListModelRole::elementName() const { return m_elementName; }
-
-void XmlListModelRole::setElementName(const QString &name)
-{
- if (name == m_elementName)
- return;
- m_elementName = name;
- Q_EMIT elementNameChanged();
-}
-
-QString XmlListModelRole::attributeName() const { return m_attributeName; }
-
-void XmlListModelRole::setAttributeName(const QString &attributeName)
-{
- if (m_attributeName == attributeName)
- return;
- m_attributeName = attributeName;
- Q_EMIT attributeNameChanged();
-}
-
-bool XmlListModelRole::isValid() const
-{
- return !m_elementName.isEmpty();
-}
-
-XmlListModel::XmlListModel(QObject *parent) : QAbstractListModel(parent)
- , m_isComponentComplete(true), m_size(0), m_highestRole(Qt::UserRole)
-#if QT_CONFIG(qml_network)
- , m_reply(nullptr)
-#endif
- , m_status(XmlListModel::Null), m_progress(0.0)
- , m_queryId(-1), m_roleObjects(), m_redirectCount(0)
-{
-}
-
-QModelIndex XmlListModel::index(int row, int column, const QModelIndex &parent) const
-{
- return !parent.isValid() && column == 0 && row >= 0 && m_size
- ? createIndex(row, column)
- : QModelIndex();
-}
-
-int XmlListModel::rowCount(const QModelIndex &parent) const
-{
- return !parent.isValid() ? m_size : 0;
-}
-
-QVariant XmlListModel::data(const QModelIndex &index, int role) const
-{
- const int roleIndex = m_roles.indexOf(role);
- return (roleIndex == -1 || !index.isValid())
- ? QVariant()
- : m_data.value(index.row()).value(roleIndex);
-}
-
-QHash<int, QByteArray> XmlListModel::roleNames() const
-{
- QHash<int,QByteArray> roleNames;
- for (int i = 0; i < m_roles.count(); ++i)
- roleNames.insert(m_roles.at(i), m_roleNames.at(i).toUtf8());
- return roleNames;
-}
-
-int XmlListModel::count() const
-{
- return m_size;
-}
-
-QUrl XmlListModel::source() const
-{
- return m_source;
-}
-
-void XmlListModel::setSource(const QUrl &src)
-{
- if (m_source != src) {
- m_source = src;
- reload();
- Q_EMIT sourceChanged();
- }
-}
-
-QString XmlListModel::query() const
-{
- return m_query;
-}
-
-void XmlListModel::setQuery(const QString &query)
-{
- if (!query.startsWith(QLatin1Char('/'))) {
- qmlWarning(this) << QCoreApplication::translate("XmlListModelRoleList", "An XmlListModel query must start with '/'");
- return;
- }
-
- if (m_query != query) {
- m_query = query;
- reload();
- Q_EMIT queryChanged();
- }
-}
-
-QQmlListProperty<XmlListModelRole> XmlListModel::roleObjects()
-{
- QQmlListProperty<XmlListModelRole> list(this, &m_roleObjects);
- list.append = &XmlListModel::appendRole;
- list.clear = &XmlListModel::clearRole;
- return list;
-}
-
-void XmlListModel::appendRole(XmlListModelRole* role)
-{
- int i = m_roleObjects.count();
- m_roleObjects.append(role);
- if (m_roleNames.contains(role->elementName())) {
- qmlWarning(role) << XmlListModel::tr("\"%1\" duplicates a previous role name and will be disabled.").arg(role->elementName());
- return;
- }
- m_roles.insert(i, m_highestRole);
- m_roleNames.insert(i, role->elementName());
- ++m_highestRole;
-}
-
-void XmlListModel::clearRole()
-{
- m_roles.clear();
- m_roleNames.clear();
- m_roleObjects.clear();
-}
-
-void XmlListModel::appendRole(QQmlListProperty<XmlListModelRole>* list, XmlListModelRole* role)
-{
- reinterpret_cast<XmlListModel*>(list->object)->appendRole(role);
-}
-
-void XmlListModel::clearRole(QQmlListProperty<XmlListModelRole>* list)
-{
- reinterpret_cast<XmlListModel*>(list->object)->clearRole();
-}
-
-XmlListModel::Status XmlListModel::status() const
-{
- return m_status;
-}
-
-qreal XmlListModel::progress() const
-{
- return m_progress;
-}
-
-QString XmlListModel::errorString() const
-{
- return m_errorString;
-}
-
-void XmlListModel::classBegin()
-{
- m_isComponentComplete = false;
-
- XmlListModelQueryEngine *queryEngine = XmlListModelQueryEngine::instance(qmlEngine(this));
- connect(queryEngine, &XmlListModelQueryEngine::queryCompleted,
- this, &XmlListModel::queryCompleted);
- connect(queryEngine, &XmlListModelQueryEngine::error,
- this, &XmlListModel::queryError);
-}
-
-void XmlListModel::componentComplete()
-{
- m_isComponentComplete = true;
- reload();
-}
-
-void XmlListModel::reload()
-{
- if (!m_isComponentComplete)
- return;
-
- XmlListModelQueryEngine::instance(qmlEngine(this))->abort(m_queryId);
- m_queryId = -1;
-
- if (m_size < 0)
- m_size = 0;
-
-#if QT_CONFIG(qml_network)
- if (m_reply) {
- m_reply->abort();
- deleteReply();
- }
-#endif
-
- if (m_source.isEmpty()) {
- m_queryId = 0;
- notifyQueryStarted(false);
- QTimer::singleShot(0, this, &XmlListModel::dataCleared);
- }
- else if (QQmlFile::isLocalFile(m_source)) {
- QFile file(QQmlFile::urlToLocalFileOrQrc(m_source));
- QByteArray data = file.open(QIODevice::ReadOnly) ? file.readAll() : QByteArray();
- notifyQueryStarted(false);
- if (data.isEmpty()) {
- m_queryId = 0;
- QTimer::singleShot(0, this, &XmlListModel::dataCleared);
- } else {
- m_queryId = XmlListModelQueryEngine::instance(qmlEngine(this))->doQuery(
- m_query, data, &m_roleObjects);
- }
- } else {
-#if QT_CONFIG(qml_network)
- notifyQueryStarted(true);
- QNetworkRequest req(m_source);
- req.setRawHeader("Accept", "application/xml,*/*");
- m_reply = qmlContext(this)->engine()->networkAccessManager()->get(req);
-
- QObject::connect(m_reply, &QNetworkReply::finished,
- this, &XmlListModel::requestFinished);
- QObject::connect(m_reply, &QNetworkReply::downloadProgress,
- this, &XmlListModel::requestProgress);
-#else
- m_queryId = 0;
- notifyQueryStarted(false);
- QTimer::singleShot(0, this, &XmlListModel::dataCleared);
-#endif
- }
-}
-
-#define XMLLISTMODEL_MAX_REDIRECT 16
-
-#if QT_CONFIG(qml_network)
-void XmlListModel::requestFinished()
-{
- m_redirectCount++;
- if (m_redirectCount < XMLLISTMODEL_MAX_REDIRECT) {
- QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirect.isValid()) {
- QUrl url = m_reply->url().resolved(redirect.toUrl());
- deleteReply();
- setSource(url);
- return;
- }
- }
- m_redirectCount = 0;
-
- if (m_reply->error() != QNetworkReply::NoError) {
- m_errorString = m_reply->errorString();
- deleteReply();
-
- if (m_size > 0) {
- beginRemoveRows(QModelIndex(), 0, m_size - 1);
- m_data.clear();
- m_size = 0;
- endRemoveRows();
- Q_EMIT countChanged();
- }
-
- m_status = Error;
- m_queryId = -1;
- Q_EMIT statusChanged(m_status);
- } else {
- QByteArray data = m_reply->readAll();
- if (data.isEmpty()) {
- m_queryId = 0;
- QTimer::singleShot(0, this, &XmlListModel::dataCleared);
- } else {
- m_queryId = XmlListModelQueryEngine::instance(qmlEngine(this))->doQuery(m_query, data, &m_roleObjects);
- }
- deleteReply();
-
- m_progress = 1.0;
- Q_EMIT progressChanged(m_progress);
- }
-}
-
-void XmlListModel::deleteReply()
-{
- if (m_reply) {
- QObject::disconnect(m_reply, 0, this, 0);
- m_reply->deleteLater();
- m_reply = nullptr;
- }
-}
-#endif
-
-void XmlListModel::requestProgress(qint64 received, qint64 total)
-{
- if (m_status == Loading && total > 0) {
- m_progress = qreal(received)/total;
- Q_EMIT progressChanged(m_progress);
- }
-}
-
-void XmlListModel::dataCleared()
-{
- XmlListModelQueryResult r;
- r.queryId = 0;
- queryCompleted(r);
-}
-
-void XmlListModel::queryError(void* object, const QString& error)
-{
- for (int i = 0; i < m_roleObjects.count(); i++) {
- if (m_roleObjects.at(i) == static_cast<XmlListModelRole*>(object)) {
- qmlWarning(m_roleObjects.at(i)) << XmlListModel::tr("invalid query: \"%1\"").arg(error);
- return;
- }
- }
- qmlWarning(this) << XmlListModel::tr("invalid query: \"%1\"").arg(error);
-}
-
-void XmlListModel::queryCompleted(const XmlListModelQueryResult &result)
-{
- if (result.queryId != m_queryId)
- return;
-
- int origCount = m_size;
- bool sizeChanged = result.data.count() != m_size;
-
- if (m_source.isEmpty())
- m_status = Null;
- else
- m_status = Ready;
- m_errorString.clear();
- m_queryId = -1;
-
- if (origCount > 0) {
- beginRemoveRows(QModelIndex(), 0, origCount - 1);
- endRemoveRows();
- }
- m_size = result.data.count();
- m_data = result.data;
-
- if (m_size > 0) {
- beginInsertRows(QModelIndex(), 0, m_size - 1);
- endInsertRows();
- }
-
- if (sizeChanged)
- Q_EMIT countChanged();
-
- Q_EMIT statusChanged(m_status);
-}
-
-void XmlListModel::notifyQueryStarted(bool remoteSource)
-{
- m_progress = remoteSource ? 0.0 : 1.0;
- m_status = XmlListModel::Loading;
- m_errorString.clear();
- Q_EMIT progressChanged(m_progress);
- Q_EMIT statusChanged(m_status);
-}
-
-
-
-
diff --git a/examples/demos/shared/xmllistmodel.h b/examples/demos/shared/xmllistmodel.h
deleted file mode 100644
index 2ec23e3df..000000000
--- a/examples/demos/shared/xmllistmodel.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef XMLLISTMODEL_H
-#define XMLLISTMODEL_H
-
-#include <QtQml>
-#include <QQmlContext>
-#include <QQmlEngine>
-#include <QAbstractItemModel>
-#include <QThread>
-#include <QByteArray>
-#include <QMap>
-#include <QMutex>
-#include <QHash>
-#include <QStringList>
-#include <QTimer>
-#include <QUrl>
-#if QT_CONFIG(qml_network)
-#include <QNetworkRequest>
-#include <QNetworkReply>
-#include <QXmlStreamReader>
-#endif
-
-
-class QQmlContext;
-struct XmlListModelQueryJob
-{
- int queryId;
- QByteArray data;
- QString query;
- QStringList roleNames;
- QStringList roleQueries;
- QList<void*> roleQueryErrorId;
-};
-struct XmlListModelQueryResult {
- int queryId;
- QList<QHash<int, QString> > data;
-};
-
-class XmlListModelRole : public QObject
-{
- Q_OBJECT
- Q_PROPERTY(QString elementName READ elementName WRITE setElementName NOTIFY elementNameChanged)
- Q_PROPERTY(QString attributeName READ attributeName WRITE setAttributeName NOTIFY attributeNameChanged)
- QML_ELEMENT
-
-public:
- XmlListModelRole() = default;
- ~XmlListModelRole() = default;
-
- QString elementName() const;
- void setElementName(const QString &name);
- QString attributeName() const;
- void setAttributeName(const QString &attributeName);
- bool isValid() const;
-
-signals:
- void elementNameChanged();
- void attributeNameChanged();
-
- private:
- QString m_elementName;
- QString m_attributeName;
-
-};
-
-class XmlListModel : public QAbstractListModel, public QQmlParserStatus
-{
- Q_OBJECT
- Q_INTERFACES(QQmlParserStatus)
-
- Q_PROPERTY(Status status READ status NOTIFY statusChanged)
- Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged)
- Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
- Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged)
- Q_PROPERTY(QQmlListProperty<XmlListModelRole> roles READ roleObjects)
- Q_PROPERTY(int count READ count NOTIFY countChanged)
- QML_ELEMENT
-
-public:
- XmlListModel(QObject *parent = nullptr);
- ~XmlListModel() = default;
-
- QModelIndex index(int row, int column, const QModelIndex &parent) const override;
- int rowCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const override;
- QHash<int, QByteArray> roleNames() const override;
-
- int count() const;
-
- QUrl source() const;
- void setSource(const QUrl&);
-
- QString query() const;
- void setQuery(const QString&);
-
- QQmlListProperty<XmlListModelRole> roleObjects();
-
- void appendRole(XmlListModelRole*);
- void clearRole();
-
- enum Status { Null, Ready, Loading, Error };
- Q_ENUM(Status)
- Status status() const;
- qreal progress() const;
-
- Q_INVOKABLE QString errorString() const;
-
- void classBegin() override;
- void componentComplete() override;
-
-Q_SIGNALS:
- void statusChanged(XmlListModel::Status);
- void progressChanged(qreal progress);
- void countChanged();
- void sourceChanged();
- void queryChanged();
-
-public Q_SLOTS:
- void reload();
-
-private Q_SLOTS:
-#if QT_CONFIG(qml_network)
- void requestFinished();
-#endif
- void requestProgress(qint64,qint64);
- void dataCleared();
- void queryCompleted(const XmlListModelQueryResult &);
- void queryError(void* object, const QString& error);
-
-private:
- Q_DISABLE_COPY(XmlListModel)
-
- void notifyQueryStarted(bool remoteSource);
-
- static void appendRole(QQmlListProperty<XmlListModelRole>*, XmlListModelRole*);
- static void clearRole(QQmlListProperty<XmlListModelRole>*);
-
-#if QT_CONFIG(qml_network)
- void deleteReply();
-
- QNetworkReply *m_reply;
-#endif
-
- int m_size;
- QUrl m_source;
- QString m_query;
- QStringList m_roleNames;
- QList<int> m_roles;
- QList<XmlListModelRole *> m_roleObjects;
- QList<QHash<int, QString> > m_data;
- bool m_isComponentComplete;
- Status m_status;
- QString m_errorString;
- qreal m_progress;
- int m_queryId;
- int m_redirectCount;
- int m_highestRole;
-
-};
-
-class XmlListModelQueryThreadObject;
-
-class XmlListModelQueryEngine : public QThread
-{
- Q_OBJECT
-public:
- XmlListModelQueryEngine(QQmlEngine *eng);
- ~XmlListModelQueryEngine();
-
- int doQuery(QString query, QByteArray data, QList<XmlListModelRole *>* roles);
- void abort(int id);
-
- void processJobs();
-
- static XmlListModelQueryEngine *instance(QQmlEngine *engine);
-
-signals:
- void queryCompleted(const XmlListModelQueryResult &);
- void error(void*, const QString&);
-
-protected:
- void run() override;
-
-private:
- void processQuery(XmlListModelQueryJob *job);
- void doQueryJob(XmlListModelQueryJob *job, XmlListModelQueryResult *currentResult);
- void processElement(XmlListModelQueryJob *currentJob, XmlListModelQueryResult*& currentResult, QString element, QXmlStreamReader &reader);
-
- QMutex m_mutex;
- XmlListModelQueryThreadObject *m_threadObject;
- QList<XmlListModelQueryJob> m_jobs;
- QSet<int> m_cancelledJobs;
- QAtomicInt m_queryIds;
-
- QQmlEngine *m_engine;
- QObject *m_eventLoopQuitHack;
-
- static QHash<QQmlEngine *, XmlListModelQueryEngine*> queryEngines;
- static QMutex queryEnginesMutex;
-};
-
-class XmlListModelQueryThreadObject : public QObject
-{
- Q_OBJECT
-public:
- XmlListModelQueryThreadObject(XmlListModelQueryEngine *);
-
- void processJobs();
- bool event(QEvent *e) override;
-
-private:
- XmlListModelQueryEngine *m_queryEngine;
-};
-
-#endif