I am trying to implement a QAbstractItemModel/QTreeView MVC in a program. I have my data in the form of QLists - a list of albums, and every album contains a list of tracks.

Everything is working, except my data() implementation never returns the right data for the children (tracks). Instead, it always returns the data for the albums, with the result that when the albums expand they list the albums yet again. There is no infinite recursion - i.e. the rowCount() implementation works. I also checked with debug prints to the console that the index() and parent() methods work as expected.

Here is the code for the model implementation:

Qt Code:
  1. /***************************************************************************
  2.  * Copyright (C) 2007 by Lawrence Lee *
  3.  * valheru@facticius.net *
  4.  * *
  5.  * This program is free software; you can redistribute it and/or modify *
  6.  * it under the terms of the GNU General Public License as published by *
  7.  * the Free Software Foundation; either version 2 of the License, or *
  8.  * (at your option) any later version. *
  9.  * *
  10.  * This program is distributed in the hope that it will be useful, *
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13.  * GNU General Public License for more details. *
  14.  * *
  15.  * You should have received a copy of the GNU General Public License *
  16.  * along with this program; if not, write to the *
  17.  * Free Software Foundation, Inc., *
  18.  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  19.  ***************************************************************************/
  20. #include <KDE/KDebug>
  21. #include "kzenalbumviewmodel.h"
  22. #include "kzenalbum.h"
  23. #include "kzentrack.h"
  24.  
  25. KZenAlbumViewModel::KZenAlbumViewModel( QObject *parent, const QList<KZenAlbum*> &albums )
  26. : QAbstractItemModel( parent ), albumItems( albums )
  27. {
  28. rootItem << "Album" << "Artist" << "Genre" << "Nr. of Tracks";
  29. }
  30.  
  31. KZenAlbumViewModel::~KZenAlbumViewModel()
  32. {
  33. qDeleteAll( albumItems );
  34. }
  35.  
  36. int KZenAlbumViewModel::columnCount( const QModelIndex& /*parent*/ ) const
  37. {
  38. return 4;
  39. }
  40.  
  41. QVariant KZenAlbumViewModel::data( const QModelIndex &index, int role ) const
  42. {
  43. kDebug() << index;
  44.  
  45. if( !index.isValid() )
  46. return QVariant();
  47.  
  48. if( role != Qt::DisplayRole )
  49. return QVariant();
  50.  
  51. QObject *item = static_cast<QObject*>( index.internalPointer() );
  52.  
  53. if( item ){
  54. KZenAlbum *album = qobject_cast<KZenAlbum*>( item );
  55.  
  56. if( album ){ //Album
  57.  
  58. switch( index.column() ){
  59. case 0:
  60. return album->name();
  61. case 1:
  62. return album->artist();
  63. case 2:
  64. return album->genre();
  65. case 3:
  66. return album->numTracks();
  67. default:
  68. return QVariant();
  69. }
  70. }else{ //Track
  71. KZenTrack *track = qobject_cast<KZenTrack*>( item );
  72.  
  73. if( track ){
  74. switch( index.column() ){
  75. case 0:
  76. return track->title();
  77. case 1:
  78. return track->artist();
  79. case 2:
  80. return track->genre();
  81. case 3:
  82. return track->tracknumber();
  83. default:
  84. return QVariant();
  85. }
  86. }else{
  87. return QVariant();
  88. }
  89. }
  90. }
  91.  
  92. return QVariant();
  93. }
  94.  
  95. Qt::ItemFlags KZenAlbumViewModel::flags( const QModelIndex &index ) const
  96. {
  97. if( !index.isValid() )
  98. return 0;
  99.  
  100. return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
  101. }
  102.  
  103. QVariant KZenAlbumViewModel::headerData( int section, Qt::Orientation orientation, int role ) const
  104. {
  105. if (orientation == Qt::Horizontal && role == Qt::DisplayRole){
  106. return rootItem.value( section );
  107. }
  108.  
  109. return QVariant();
  110. }
  111.  
  112. QModelIndex KZenAlbumViewModel::index( int row, int column, const QModelIndex &parent ) const
  113. {
  114. if( !hasIndex( row, column, parent ) )
  115. return QModelIndex();
  116.  
  117. if( !parent.isValid() ){ // This is an album, and therefor a top-level item
  118. KZenAlbum *album = const_cast<KZenAlbum*>( albumItems.at( row ) );
  119.  
  120. if( album )
  121. return createIndex( row, column, album );
  122. else
  123. return QModelIndex();
  124.  
  125. }else{ //This is a track, and has an album as a parent
  126. QObject *item = static_cast<QObject*>( parent.internalPointer() );
  127. KZenAlbum *album = qobject_cast<KZenAlbum*>( item );
  128. KZenTrack *track = album->albumTracks().value( row );
  129. return createIndex( row, column, track );
  130. }
  131.  
  132. return QModelIndex();
  133. }
  134.  
  135. QModelIndex KZenAlbumViewModel::parent( const QModelIndex &index ) const
  136. {
  137. if( !index.isValid() )
  138. return QModelIndex();
  139.  
  140. QObject *item = static_cast<QObject*>( index.internalPointer() );
  141.  
  142. if( item ){
  143. KZenAlbum *album = qobject_cast<KZenAlbum*>( item );
  144.  
  145. if( album ){
  146. return QModelIndex();
  147. }else{
  148. KZenTrack *track = qobject_cast<KZenTrack*>( item );
  149.  
  150. if( track ){
  151. KZenAlbum *album = track->parent();
  152. return createIndex( albumItems.indexOf( album ), 0, album );
  153. }else{
  154. return QModelIndex();
  155. }
  156. }
  157. }
  158.  
  159. return QModelIndex();
  160. }
  161.  
  162. int KZenAlbumViewModel::rowCount( const QModelIndex &parent ) const
  163. {
  164. if( parent.column() > 0 )
  165. //Out of model bounds
  166. return 0;
  167.  
  168. if( !parent.isValid() )
  169. //We are in the root of the model
  170. return albumItems.size();
  171.  
  172. //Check to see if this is a track
  173. QObject *item = static_cast<QObject*>( parent.internalPointer() );
  174.  
  175. if( item ){
  176. KZenAlbum *album = qobject_cast<KZenAlbum*>( item );
  177.  
  178. if( album ){
  179. return album->numTracks();
  180. }else{
  181. return 0;
  182. }
  183. }
  184.  
  185. return 0;
  186.  
  187. }
  188.  
  189. #include "kzenalbumviewmodel.moc"
To copy to clipboard, switch view to plain text mode