08-07-2012 02:59 AM
To developers,
I want to ask how to add this xml to ListView. Here is my example XML
<root>
<Venue>
<IdVenue>501</IdVenue>
<Name>guan sheng di jin miao. kelengteng guang gong</Name>
<IdCategory>122</IdCategory>
<Address>jalan martadinata</Address>
<City>Tuban</City>
<Latitude>-6.8908800000000001</Latitude>
<Longitude>112.0459175</Longitude>
<Distance>13091</Distance>
<UserLike>False</UserLike>
<CommentCount>0</CommentCount>
<LikeCount>0</LikeCount>
</Venue>
<Venue>
<IdVenue>1757</IdVenue>
<Name>Galang's Mansion</Name>
<IdCategory>41</IdCategory>
<Address>Jalan Basuki Rahmad Nomor 99</Address>
<City>Tulungagung</City>
<Latitude>-7.1284299999999998</Latitude>
<Longitude>112.11834</Longitude>
<Distance>19305</Distance>
<UserLike>False</UserLike>
<CommentCount>0</CommentCount>
<LikeCount>0</LikeCount>
</Venue>\
</root>
What i want to view is:
1. ViewList without header (i've used headerMode: ListHeaderMode.None to create non-group view)
2. Each row contains 1 Venue, which include it's name, address, and distance.
Can you help me?
Thank you very much for your help..
Solved! Go to Solution.
08-08-2012 01:45 PM
Take a look at sample cascadescookbookqml, especially files:
recipemodel.xml
main.qml (the ListView)
RecipeItem.qml (defining the component used by the ListView.
In your case the XML does not map directly to what you want to display. A few choices come to mind:
- change your XML to a format that XmlDataModel can easily handle, e.g. use attributes
- In C++, use QXmlSimpleParser to read your XML and feed the data to a QListDataModel or to a GroupDataModel with grouping set to none
- In C++, use QXmlSimpleParser to read your XML but use your own data model subclass to feed the data to the list view. See http://supportforums.blackberry.com/t5/Cascades-De
Stuart
08-08-2012 11:13 PM
Thank you for your reply.
Sorry if i'm not quite understand with your solution :
1. if i want to use XML for dataModel, it means i have to translate my xml into using attributes?
2. Can i use your second and third solution in QML? (I'm still blank how to integrate C++ and QML in 1 app)
3. Sorry if i'm asking more, but can you give me tutorial, how to parse XML into my own custom data model? Maybe with some code, so i can understand how to use it..
08-09-2012 09:02 AM
To do things entirely in QML, you will need to format your XML in a way that XmlDataModel supports, so yes you will need to use attributes. Look at the cascadescookbookqml sample.
To learn how to integrate C++ and QML in one application, there are many resources:
To learn C++ there are many good online tutorials, books, and other resources.
Stuart
08-11-2012 11:36 AM
yup, you have to convert the structure into xmldatamodel compatible structure, you can use C++ code to do the conversion, and pass the result into QML
<root> <Venue IdVenue="501" Name="guan sheng di jin miao. kelengteng guang gong" IdCategory="122" .../>
<Venue .../>
</root>
08-12-2012 06:06 AM
08-30-2012 06:09 PM
an example?
08-31-2012 09:04 AM
hi,
XML
<?xml version="1.0" encoding="UTF-8" ?>
<persons>
<person id="1">
<firstname>John</firstname>
<surname>Doe</surname>
<email>john.doe@example.com</email>
<website>http://aptratech.com</website>
</person>
<person id="2">
<firstname>Jane</firstname>
<surname>Doe</surname>
<email>jane.doe@example.com</email>
<website>http://aptratech.com</website>
</person>
<person id="3">
<firstname>Matti</firstname>
<surname>Meikäläinen</surname>
<email>matti.meikalainen@example.com</email>
<website>http://aptratech.com</website>
</person>
</persons>
Cpp Code
#include <QObject>
#include <QIODevice>
//#include <QXmlStreamReader>
#include <QtXml/QDomDocument>
#include <bb/cascades/QListDataModel>
#include <bb/cascades/Application>
#include <bb/cascades/ListView>
#include <bb/cascades/GroupDataModel>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
using namespace bb::cascades;
App::App() {
// Load the QML document and retrieve the root node
QmlDocument *qml = QmlDocument::create("main.qml");
AbstractPane *root = qml->createRootNode<AbstractPane>();
GroupDataModel *model = new GroupDataModel(
QStringList() << "firstname" << "surname" << "email");
model->setGrouping(ItemGrouping::ByFirstChar);
ListView *listView = root->findChild<ListView *>("listView");
QString appFolder(QDir::currentPath());
QString fileName = appFolder + "/app/native/assets/models/items.xml";
fprintf(stderr, "File Path : %s\n", fileName.toAscii().constData());
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
fprintf(stderr, "Error to open file.\n");
return;
} else {
fprintf(stderr, "File opened.\n");
}
QList<QMap<QString, QString> > persons;
QDomDocument doc("mydocument");
if (!doc.setContent(&file)) {
return;
}
//Get the root element
QDomElement docElem = doc.documentElement();
// you could check the root tag name here if it matters
QString rootTag = docElem.tagName(); // == persons
// get the node's interested in, this time only caring about person's
QDomNodeList nodeList = docElem.elementsByTagName("person");
//Check each node one by one.
QMap<QString, QVariant> person;
for (int ii = 0; ii < nodeList.count(); ii++) {
// get the current one as QDomElement
QDomElement el = nodeList.at(ii).toElement();
// person["id"] = el.attribute("id"); // get and set the attribute ID
//get all data for the element, by looping through all child elements
QDomNode pEntries = el.firstChild();
while (!pEntries.isNull()) {
QDomElement peData = pEntries.toElement();
QString tagNam = peData.tagName();
if (tagNam == "firstname") {
//We've found first name.
person["firstname"] = peData.text();
} else if (tagNam == "surname") {
//We've found surname.
person["surname"] = peData.text();
} else if (tagNam == "email") {
//We've found email.
person["email"] = peData.text();
} else if (tagNam == "website") {
//We've found website.
person["website"] = peData.text();
}
pEntries = pEntries.nextSibling();
}
model->insert(person);
}
listView->setDataModel(model);
// Set the scene using the root node
Application::setScene(root);
}
Qml File
import bb.cascades 1.0
Page {
content: Container {
ListView {
id: contactList
objectName: "listView"
listItemComponents: [
ListItemComponent {
type: "header"
HeaderListItem {
title: ListItemData
}
},
ListItemComponent {
type: "item"
Container {
Label {
text: ListItemData.firstname
}
Label {
text: ListItemData.surname
}
Label {
text: ListItemData.email
}
Container {
preferredWidth: 768
preferredHeight: 5
background: Color.Red
}
}
}
] // end of listItemComponents list
}
}
}
08-31-2012 01:53 PM
thanks!
09-08-2012 12:18 AM
Sorry for my late reply, i'm trying to merge this sample code in creating my own data model..
But, i can't structure my group data model.
The result just show address, but not the others data information.
Can you help me to find what is the problem. Thank you..
Here is my own group data model :
1. VenueDataModel.h
#ifndef VENUEDATAMODEL_H_
#define VENUEDATAMODEL_H_
#include <QVector>
#include <QtXml/QDomDocument>
#include <bb/cascades/DataModel>
#include <bb/cascades/GroupDataModel>
#include <bb/cascades/QListDataModel>
#include <bb/cascades/QmlDocument>
class VenueDataModel : public bb::cascades::GroupDataModel{
private:
public:
VenueDataModel();
virtual ~VenueDataModel();
void createDataModel();
};
#endif /* VENUEDATAMODEL_H_ */
2. VenueDataModel.cpp
#include "VenueDataModel.h"
VenueDataModel::VenueDataModel() {
// TODO Auto-generated constructor stub
createDataModel();
}
VenueDataModel::~VenueDataModel() {
// TODO Auto-generated destructor stub
}
void VenueDataModel::createDataModel() {
//open file locastion
QString appFolder(QDir::currentPath());
QString fileName = appFolder + "/app/native/assets/resource/xml/venueTag.xml";
QFile file(fileName);
//create document
QDomDocument doc("venueListDocument");
doc.setContent(&file);
QDomElement docElem = doc.documentElement();
QDomNodeList nodeList = docElem.elementsByTagName("Venue");
//parsing XML
QString id = "";
QString name = "";
QMap<QString, QVariant> venueList;
for (int i = 0; i < nodeList.count(); i++)
{
QDomElement el = nodeList.at(i).toElement();
QDomNode entryRow = el.firstChild();
while (!entryRow.isNull()) {
QDomElement entryValue = entryRow.toElement();
QString entryTag = entryValue.tagName();
if (entryTag == "IdVenue")
{
venueList["IdVenue"] = entryValue.text();
}
else if (entryTag == "Name")
{
venueList["Name"] = entryValue.text();
}
else if (entryTag == "IdCategory")
{
venueList["IdCategory"] = entryValue.text();
}
else if (entryTag == "Address")
{
venueList["Address"] = entryValue.text();
}
else if (entryTag == "City")
{
venueList["City"] = entryValue.text();
}
else if (entryTag == "Latitude")
{
venueList["Latitude"] = entryValue.text();
}
else if (entryTag == "Longitude")
{
venueList["Longitude"] = entryValue.text();
}
else if (entryTag == "Distance")
{
venueList["Distance"] = entryValue.text();
}
else if (entryTag == "UserLike")
{
venueList["UserLike"] = entryValue.text();
}
else if (entryTag == "CommentCount")
{
venueList["CommentCount"] = entryValue.text();
}
else if (entryTag == "LikeCount")
{
venueList["LikeCount"] = entryValue.text();
}
entryRow = entryRow.nextSibling();
}
this->insert(venueList);
}
}
3. i add custom lib in my app.cpp
#include <QObject>
#include <QIODevice>
#include <QVector>
#include <QtXml/QDomDocument>
#include <bb/cascades/QListDataModel>
#include <bb/cascades/Application>
#include <bb/cascades/ListView>
#include <bb/cascades/GroupDataModel>
#include <bb/cascades/QmlDocument>
#include <bb/cascades/AbstractPane>
#include "app.hpp"
#include "VenueDataModel.h"
using namespace bb::cascades;
App::App()
{
qmlRegisterType<VenueDataModel>("custom.lib", 1, 0, "VenueDataModel");
QmlDocument *qml = QmlDocument::create("main.qml");
//-- setContextProperty expose C++ object in QML as an variable
//-- uncomment next line to introduce 'this' object to QML name space as an 'app' variable
qml->setContextProperty("_app", this);
AbstractPane *root = qml->createRootNode<AbstractPane>();
Application::setScene(root);
}
4. Then in my listview, i insert my own group data model
ListView {
id: venueListID
dataModel: VenueDataModel {
grouping: ItemGrouping.None
}
selectionMode: SelectionMode.Single
layout: StackListLayout {
headerMode: ListHeaderMode.None
}
listItemComponents: [
ListItemComponent {
type: "Venue"
VenueManagerList {
}
}
]
onTriggered: {
// When an item is selected we push the recipe Page in the chosenItem file attribute.
var chosenItem = dataModel.data(indexPath);
// The _contentView property can be resolved in by the ContentPage since it will
// share the same context as the main file.
_contentView = chosenItem;
// Push the Content Page on top to drill down and show details about the stamp.
homeScreenNav.deprecatedPushQmlByString("VenueDeta ilScreen.qml");
}
}
4. This is my VenueManagerList.qml
import bb.cascades 1.0
Container {
id: venueManager
layout: StackLayout {
layoutDirection: LayoutDirection.TopToBottom
}
Container{
id: listContainerManagerID
layout: StackLayout {
layoutDirection: LayoutDirection.LeftToRight
leftPadding: 10.0
rightPadding: 10.0
topPadding: 0.0
bottomPadding: 0.0
}
ImageView {
id: venueCategoryID
imageSource: "asset:///resource/icon/venueCategory/" + ListItemData.IdCategory + ".png"
layoutProperties: StackLayoutProperties {
horizontalAlignment: HorizontalAlignment.Left
verticalAlignment: VerticalAlignment.Center
}
}
Container{
id: informationManagerID
layout: StackLayout {
leftPadding: 10.0
rightPadding: 10.0
}
layoutProperties: StackLayoutProperties {
horizontalAlignment: HorizontalAlignment.Fill
verticalAlignment: VerticalAlignment.Center
spaceQuota: 8
}
Label {
id: labelVenueTitleID
text: ListItemData.Name
layoutProperties: StackLayoutProperties {
horizontalAlignment: HorizontalAlignment.Left
}
textStyle.size: 35.0
textStyle.color: Color.create("#ff71951d")
topMargin: 0
bottomMargin: 0
}
Label {
id: labelVenueAddressID
text: ListItemData.Address
layoutProperties: StackLayoutProperties {
horizontalAlignment: HorizontalAlignment.Left
}
textStyle.size: 25.0
textStyle.color: Color.create("#ff666666")
topMargin: 0
bottomMargin: 0
}
Label {
id: labelVenueCityID
text: ListItemData.City
layoutProperties: StackLayoutProperties {
horizontalAlignment: HorizontalAlignment.Left
}
textStyle.size: 25.0
textStyle.color: Color.create("#ff666666")
topMargin: 0
bottomMargin: 0
}
}
Container{
id: iconManagerID
layout: StackLayout {
}
layoutProperties: StackLayoutProperties {
horizontalAlignment: HorizontalAlignment.Right
spaceQuota: 1.5
verticalAlignment: VerticalAlignment.Center
}
Container{
id: likeIconManagerID
layout: StackLayout {
leftPadding: 5.0
rightPadding: 5.0
layoutDirection: LayoutDirection.LeftToRight
}
ImageView {
id: iconLikeID
imageSource: "asset:///resource/icon/" +
((ListItemData.UserLike == "True") ? "LikeON.png" : "LikeOFF.png")
layoutProperties: StackLayoutProperties {
horizontalAlignment: HorizontalAlignment.Left
verticalAlignment: VerticalAlignment.Center
}
}
Label {
id: labelLikeCountID
text: ListItemData.LikeCount
textStyle.size: 25.0
textStyle.color: Color.create("#ff666666")
topMargin: 0
bottomMargin: 0
}
}
Container{
id: commentIconManagerID
layout: StackLayout {
leftPadding: 5.0
rightPadding: 5.0
layoutDirection: LayoutDirection.LeftToRight
}
ImageView {
id: iconCommentID
imageSource: "asset:///resource/icon/Comment.png"
layoutProperties: StackLayoutProperties {
horizontalAlignment: HorizontalAlignment.Left
verticalAlignment: VerticalAlignment.Center
}
}
Label {
id: labelCommentCountID
text: ListItemData.CommentCount
textStyle.size: 25.0
textStyle.color: Color.create("#ff666666")
topMargin: 0
bottomMargin: 0
}
}
}
}
Container{
id: bottomManagerListID
layout: StackLayout {
leftPadding: 0.0
rightPadding: 0.0
topPadding: 0.0
bottomPadding: 0.0
}
layoutProperties: StackLayoutProperties {
verticalAlignment: VerticalAlignment.Bottom
}
background: Color.create ("#ffbad79d")
minWidth: 250.0
Label {
id: labelVenueDistanceID
text: "Distance : " + ListItemData.Distance + " m "
layoutProperties: StackLayoutProperties {
horizontalAlignment: HorizontalAlignment.Left
}
textStyle.size: 25.0
textStyle.color: Color.create("#ff666666")
topMargin: 0
bottomMargin: 0
}
}
Divider {
topMargin: 0.0
bottomMargin: 0.0
}
}