[solved] A sort of tree view in QML?
-
Hi all...
I'm here again with another problem, or better, in this case, I'm wondering how to do a certain thing... :)
I have an xml file containing the comments to a certain wordpress blog post. Each comment in the list has a key saying of which other comment it is child of (i.e. there is the id of the parent).
Now I need to show this comments in the app, but in threaded way, such as, maybe, any comment is a few pixel indented with respect to its parent... Some easy and practical ideas on how to do this? I think that the listview is not a solution. Maybe it should be usefoul to have a TreeView view, to connect to an XmlListModel, but I don't think such a component is available in QML!As always, thanks all :P
-
It should not be a problem in QML to build a TreeView. As outer most element you talke a ListView and as delegate a Text element which represents the top level item and a Column that contains the children. The Column delegates again can have a top level item + a column again...understand what I mean? I think the most difficult thing is to build a model for such a view. But I think it is doable.
-
Will try to write up some code, then will come back here, let's see what I can sort out :P
-
Ok, I have had an idea on hot to "solve" this, that maybe is easier than the Column one (btw: hot to define a delegate for a Column?).
The idea is to use a "Comment" model for the delegate of the ListView, that has as first item an empty item deciding the distance from the border, and then the content of the comment, that are the text, author and date. Code:@
import QtQuick 1.1
import com.nokia.symbian 1.1Component {
property int commentId;
property int level;
property alias text: commentText.text
property alias author: commentAuthor.text
property alias date: commentDate.textItem { id: commentWrapper height: childrenRect.height Item { id: levelMarginElement width: (level > 6 ? 7 : level) * 5 anchors.left: parent.left } Item { anchors.left: levelMarginElement.right anchors.verticalCenter: commentWrapper.verticalCenter Text { id: commentText } Row { id: commentInfos height: childrenRect.height anchors { top: commentText.bottom left: parent.left right: parent.right topMargin: 10 } Label { id: commentAuthor anchors { top: parent.top left: parent.left } width: (parent.width / 2) platformInverted: window.platformInverted font.pixelSize: platformStyle.fontSizeSmall horizontalAlignment: Text.AlignLeft } Label { id: commentDate anchors { top: parent.top right: parent.right left: commentAuthor.right } platformInverted: window.platformInverted font.pixelSize: platformStyle.fontSizeSmall horizontalAlignment: Text.AlignRight } } Button { id: commentsReply anchors { top: commentInfos.bottom right: parent.right } text: "Reply" } } }
}@
Now the problem shoul be to define the ListModel for this ListView.... :S
-
I think I get the first part of it :D
So, the idea is to have a XmlListModel for handling data, inside a standard ListModel. Once the data are loaded into the xmlListModel, I use javascript and sort item, inserting them into the outermost list model, in the desirable order. This seems to work!
Now I need to better understand how I can select the right level for the comment object of the previous post in all of this thing...
An easy way is to add a tag to the server generated xml file, and use it, but is not really a good solution, i suppose! :)
@
import QtQuick 1.1ListModel {
id: rootproperty alias source: xmlListModel.source property alias query: xmlListModel.query property alias namespaceDeclarations: xmlListModel.namespaceDeclarations property alias status: xmlListModel.status function push(item) { append(item); } property variant __xmlListModel: XmlListModel { id: xmlListModel XmlRole { name: "id" query: "id/number()" isKey: true } XmlRole { name: "author" query: "author/string()" } XmlRole { name: "comment" query: "comment/string()" } XmlRole { name: "pubDate" query: "date/string()" } XmlRole { name: "parentId" query: "parent/number()" } property variant keys: [] onSourceChanged: { console.debug(source) } function searchForChilds(itemId, startingFrom) { for(var i = startingFrom; i < xmlListModel.count; i++) { var item = xmlListModel.get(i); if(item.parentId === itemId) { push(item); item.parentId = -1; searchForChilds(item.id, i + 1); } } } function reconstructCommentsTree() { if(xmlListModel.count === 0) return; var item = xmlListModel.get(0); push(item); searchForChilds(item.id, 1); for(var i = 1; i < xmlListModel.count; i++) { item = xmlListModel.get(i); if(item.parentId === 0) { push(item); item.parentId = -1; searchForChilds(item.id, i + 1); } } for(i = 0; i < root.count; i++) { item = root.get(i); console.debug(item.id + " " + item.pubDate + " " + item.parentId); } } onItemsInserted: reconstructCommentsTree() } Component.onCompleted: { var keys = new Array() for(var i = 0; i < xmlListModel.roles.length; i++) { if(xmlListModel.roles[i].isKey) { keys.push(xmlListModel.roles[i].name); } } xmlListModel.keys = keys; }
}
@ -
Yeahhh! Find the way this morning :P
I slightly changed the order algorithm in this way:@
function searchForChilds(itemId, startingFrom, currLevel) {
for(var i = startingFrom; i < xmlListModel.count; i++) {
var item = xmlListModel.get(i);
if(item.parentId === itemId) {
item.commentLevel = currLevel;
push(item);
searchForChilds(item.commentId, i + 1, currLevel + 1);
}
}
}function reconstructCommentsTree() {
if(xmlListModel.count === 0)
return;
var item;// = xmlListModel.get(0);for(var i = 0; i < xmlListModel.count; i++) { item = xmlListModel.get(i); if(item.parentId === 0) { item.commentLevel = 0; push(item); searchForChilds(item.commentId, i + 1, 1); } }
}
@In this way, i add the property commentLevel to the items of the outer listmodel, so that I can use this value in the delegate of the listview. ;)
hope this is not to much complex as an algorithm for a mobile device...