Page 1 of 2 12 LastLast
Results 1 to 20 of 25

Thread: Updating a view's proxy model when the source model changes

  1. #1
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Updating a view's proxy model when the source model changes

    Hello,

    I have a model that manages a list of files. It's viewed by two widgets (a combobox and a tableview). Each widget has it's own QSortFilterProxy to pick which files it's supposed to display.

    The problem I'm encountering is related to drag and drop operations. After I perform a drag and drop (reordering list items), I've had trouble updating the views. For some reason, neither proxy model responds to the source model's dataChanged() signal (which I emit in the source model's setData() function, as well as the removeRows() function which is called last in the drag-drop operation). Anyway, I can solve the tableview refresh problem easily enough by adding a call to reset() in a slot in it's proxymodel, but the combo box is proving more difficult.

    I can't use the reset() trick with the combobox's proxy model because it will reset the current index to -1, losing whatever item has been selected.

    This leaves me with two possible solutions. Either I need to make a connection which ensures a proxy model is always synced with changes in it's source, or I need to save the current index of the combo box before the model is changed, then restore that index after the change is made. On the latter technique, I'm not sure how I can do that, nor am I certain that the view would update if I updated it's proxy model programmatically...

    Any help would be much appreciated...

  2. #2
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Updating a view's proxy model when the source model changes

    The problem I'm encountering is related to drag and drop operations. After I perform a drag and drop (reordering list items), I've had trouble updating the views.
    What do you mean by reordering?
    If it is just inserting row(s), are you using beginInsertRows() and endInsertRows()?
    If it is complete reordering, are you using beginModelReset() and endResetModel()?
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  3. #3
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    I'm only inserting a row at a time. I still have to call reset() on each proxy (or in the source model alone) to get the view to refresh properly. That's fine for the table view, but not good for the combo box view...

  4. #4
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Updating a view's proxy model when the source model changes

    are you using beginInsertRows() and endInsertRows()?

  5. #5
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    Yes - sorry - I forgot to mention that. Here's some code...

    Source model drag/drop and other relevant code...

    Qt Code:
    1. Qt::ItemFlags EsxModel::ContentModel::flags(const QModelIndex &index) const
    2. {
    3. if (!index.isValid())
    4. return Qt::NoItemFlags;
    5.  
    6. EsmFile *file = item(index.row());
    7.  
    8. if (!file)
    9. return Qt::NoItemFlags;
    10.  
    11. Qt::ItemFlags dragDropFlags = Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
    12. Qt::ItemFlags checkFlags = Qt::ItemIsUserCheckable;
    13. Qt::ItemFlags defaultFlags = Qt::ItemIsDropEnabled | Qt::ItemIsSelectable;
    14.  
    15. if (canBeChecked(file))
    16. return Qt::ItemIsEnabled | dragDropFlags | checkFlags | defaultFlags;
    17. else
    18. return defaultFlags;
    19. }
    20.  
    21. bool EsxModel::ContentModel::setData(const QModelIndex &index, const QVariant &value, int role)
    22. {
    23. if (index.isValid() && role == Qt::EditRole)
    24. {
    25. QString fname = value.value<QString>();
    26. mFiles.replace(index.row(), findItem(fname));
    27. emit dataChanged(index, index);
    28. return true;
    29. }
    30.  
    31. return false;
    32. }
    33.  
    34. bool EsxModel::ContentModel::insertRows(int position, int rows, const QModelIndex &parent)
    35. {
    36. beginInsertRows(QModelIndex(), position, position+rows-1);
    37.  
    38. for (int row = 0; row < rows; ++row)
    39. mFiles.insert(position, new EsmFile);
    40.  
    41. endInsertRows();
    42. return true;
    43. }
    44.  
    45. bool EsxModel::ContentModel::removeRows(int position, int rows, const QModelIndex &parent)
    46. {
    47. beginRemoveRows(QModelIndex(), position, position+rows-1);
    48.  
    49. for (int row = 0; row < rows; ++row)
    50. mFiles.removeAt(position);
    51.  
    52. endRemoveRows();
    53. emit dataChanged(index(0,0,parent), index(rowCount()-1, 0, parent));
    54. return true;
    55. }
    56.  
    57. Qt::DropActions EsxModel::ContentModel::supportedDropActions() const
    58. {
    59. return Qt::CopyAction | Qt::MoveAction;
    60. }
    61.  
    62. QStringList EsxModel::ContentModel::mimeTypes() const
    63. {
    64. QStringList types;
    65. types << "application/omwcontent";
    66. return types;
    67. }
    68.  
    69. QMimeData *EsxModel::ContentModel::mimeData(const QModelIndexList &indexes) const
    70. {
    71. QMimeData *mimeData = new QMimeData();
    72. QByteArray encodedData;
    73.  
    74. QDataStream stream(&encodedData, QIODevice::WriteOnly);
    75.  
    76. foreach (const QModelIndex &index, indexes)
    77. {
    78. if (index.isValid())
    79. {
    80. QString text = data(index, Qt::DisplayRole).toString();
    81. stream << text;
    82. }
    83. }
    84.  
    85. mimeData->setData("application/omwcontent", encodedData);
    86. return mimeData;
    87. }
    88.  
    89. bool EsxModel::ContentModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
    90. {
    91. if (action == Qt::IgnoreAction)
    92. return true;
    93.  
    94. if (!data->hasFormat("application/omwcontent"))
    95. return false;
    96.  
    97. if (column > 0)
    98. return false;
    99.  
    100. int beginRow;
    101.  
    102. if (row != -1)
    103. beginRow = row;
    104. else if (parent.isValid())
    105. beginRow = parent.row();
    106. else
    107. beginRow = rowCount(QModelIndex());
    108.  
    109. QByteArray encodedData = data->data("application/omwcontent");
    110. QDataStream stream(&encodedData, QIODevice::ReadOnly);
    111. QStringList newItems;
    112. int rows = 0;
    113.  
    114. while (!stream.atEnd())
    115. {
    116. QString text;
    117. stream >> text;
    118. newItems << text;
    119. ++rows;
    120. }
    121.  
    122. insertRows(beginRow, rows, QModelIndex());
    123.  
    124. foreach (const QString &text, newItems)
    125. {
    126. QModelIndex idx = index(beginRow, 0, QModelIndex());
    127. setData(idx, text);
    128. beginRow++;
    129. }
    130.  
    131. return true;
    132. }
    To copy to clipboard, switch view to plain text mode 

    And the proxy model:

    Qt Code:
    1. EsxModel::MasterProxyModel::MasterProxyModel(QObject *parent, QAbstractTableModel* model) :
    2. {
    3. setFilterRegExp(QString("game"));
    4. setFilterRole (Qt::UserRole);
    5.  
    6. if (model)
    7. setSourceModel (model);
    8. }
    9.  
    10. QVariant EsxModel::MasterProxyModel::data(const QModelIndex &index, int role) const
    11. {
    12. return QSortFilterProxyModel::data (index, role);
    13. }
    To copy to clipboard, switch view to plain text mode 

  6. #6
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Updating a view's proxy model when the source model changes

    Can you show the rowCount()? Is it based on anything other than mFiles.size()?
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  7. #7
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    Nope.

    Qt Code:
    1. int EsxModel::ContentModel::rowCount(const QModelIndex &parent) const
    2. {
    3. return mFiles.size();
    4. }
    To copy to clipboard, switch view to plain text mode 

  8. #8
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Updating a view's proxy model when the source model changes

    Add this
    Qt Code:
    1. int EsxModel::ContentModel::rowCount(const QModelIndex &parent) const
    2. {
    3. if(parent.isValid())
    4. return 0;
    5.  
    6. return mFiles.size();
    7. }
    To copy to clipboard, switch view to plain text mode 

    also do the corresponding changes in parent() and index()
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  9. #9
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    Being new to Qt in general, I'm a bit lost... The parent() and index() functions have not been implemented in the source model. I presume that's something that needs to be done? Any examples you could point to that might fill in the gaps in my understanding on this?

  10. #10
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    I may not have a clear enough understanding of Qt, but could it be that the proxied view gets messed up because the item is being manipulated w.r.t the source model parent index and not the proxy model? That is, I presume each proxy has a local parent for it's filtered version of the source model (since it will have it's own unique index values)... So, if the drag/drop and related operations reference the items according to the source model's parent, then it would make sense that they would get screwed up when rendered in a view that is filtered by a proxy...

    Which would suggest implementing the source model methods that take a parent() parameter in the proxy and calling the source model method with mapToSource() ... ?

  11. #11
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Updating a view's proxy model when the source model changes

    What is you model based on QAbstractItemModel/QAbstractTableModel/QStandardItemModel?
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  12. #12
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    source inherits QAbstractTableModel, proxies inherhit QSortFilterProxyModel...

  13. #13
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Updating a view's proxy model when the source model changes

    Ok, Can you post a minimal working code which illustrates the problem?
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  14. #14
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    Ok, attached are the code files.

    A few notes:

    1. The purpose is to manage the selection of items which have dependencies. A base item is selected in the combo box ("master"), and the corresponding items in the table view which share that master are enabled ("slaves"). Also, some dependencies serve as bases for others. For example, "slave1.10.1" and "slave1.10.2" depend upon "slave 1.10" and "master 1"...

    2. "slave" Items are checkable. Whether or not an item is checkable is not affected by whether or not it is enabled (i.e., whether or not it's dependencies are checked).

    3. Drag/drop allows for ordering of dependencies...

    4. The error, here, appears to have something to do with the fact that when I replace the dummy item inserted in my model list (resulting from a drop operation) with the item that was dragged, the item is copied, but not the "master" list that is associated with it. Thus, the dropped item disappears from the slave view and apperas in the master view. Calling reset() fixes this for both views.

    5. For some reason, removeRows() is not being called, though I have the drag action set to Qt::MoveAction.

    6. The problem appears to be related to the fact that I'm filtering SourceModel with a QSortFilterProxy for both views.

    Wish I could have boiled it down to a simpler case, but I'm not really sure where the problem lies, so I kept a lot of code that I might have otherwise removed.

    Thanks for taking time to look at this...

    EDIT: I just noticed I forgot to remove the call to reset() in SourceModel::setData(). Also, adding "mModel->toggleCheckState(0);" to the end of MainWindow::buildMasterView will sync the combobox and tableview on startup...

    Last two files...
    Attached Files Attached Files
    Last edited by graffy; 2nd September 2013 at 04:02.

  15. #15
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Updating a view's proxy model when the source model changes

    Here is corrected code
    Attached Files Attached Files
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  16. #16
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    Hmmm...

    I see that the code works... and I noticed how you recopied the master string list for the item that gets dropped. I had thought to do that, but it didn't make sense to me that the originial master list would be lost when the pointer to the itemContainer object was moved to a different place in the QList... Seems to me that's a bug?

    Anyway, I ran your code and it worked... sort of. That is, the master view isn't corrupted, but the item that's dragged and dropped disappears from the slave view entirely... It's still in the list, but the tableView doesn't refresh properly. Strangely, when I ran in debug mode, put a break at the end of SourceModel::dropMimeData(), and then resumed, it behaved perfectly. Wondering if maybe this a problem with my machine and not the code?

    I'm at a loss. I appreciate the help you've provided thus far and would be grateful for any other thougths you might have.

    Thanks.

  17. #17
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Updating a view's proxy model when the source model changes

    It is only a matter of emitting proper dataChanged() signals. Take a closer look at all the dataChanged() signals in my code and try to understand why they are emitted.

    Hint: When a master is selected (using the combo box), you will have to emit dataChaged() for the master and all the slaves which have the selected item as master. The second emit was missing in your code.
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  18. #18
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    Ok - I see that dataChanged calls must track all of the changes in the underlying model... Following that logic, it seems the reordering of items in a model would require a dataChanged() signal be emitted for those items whose list position changed. Presumably, this would be the item which is dragged / dropped to a different position, as well as the items between the two positions? (I tried emitting dataChanged() for every item in the model after a drop event, but no luck...)

  19. #19
    Join Date
    Mar 2011
    Location
    Hyderabad, India
    Posts
    1,882
    Thanks
    3
    Thanked 452 Times in 435 Posts
    Qt products
    Qt4 Qt5
    Platforms
    MacOS X Unix/X11 Windows
    Wiki edits
    15

    Default Re: Updating a view's proxy model when the source model changes

    Presumably, this would be the item which is dragged / dropped to a different position, as well as the items between the two positions?
    dataChanged not required in this case. it just row insert and and row remove.

    Quote Originally Posted by Santosh Reddy
    Hint: When a master is selected (using the combo box), you will have to emit dataChaged() for the master and all the slaves which have the selected item as master. The second emit was missing in your code.
    Did you understand the hint?
    When you know how to do it then you may do it wrong.
    When you don't know how to do it then it is not that you may do it wrong but you may not do it right.

  20. #20
    Join Date
    May 2013
    Posts
    35
    Thanks
    1
    Thanked 3 Times in 3 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: Updating a view's proxy model when the source model changes

    I thought I understood you but it seems clear I did not. On a hunch, I added a loop under the Qt::EditRole switch case in setData(), which took the item being dropped, looked up the master, then looked up any other items which depended on that master and called dataChanged() for each, including the master item... Should be functionally identical to the code you added under the Qt::UserRole + 1 switch case. Unfortunately, the dragged / dropped (reordered) slave item in the slave table view still disappears completely...

    Unfortunately, I'm at a loss to see what you're getting at.
    Last edited by graffy; 4th September 2013 at 01:55.

Similar Threads

  1. Replies: 1
    Last Post: 29th August 2013, 06:41
  2. Source Model Ad Proxy Model
    By sajis997 in forum Qt Programming
    Replies: 1
    Last Post: 19th July 2011, 06:13
  3. Replies: 0
    Last Post: 16th November 2010, 10:55
  4. Model, View and Proxy
    By No-Nonsense in forum Qt Programming
    Replies: 2
    Last Post: 21st November 2006, 09:50
  5. Filter Proxy Model to Autoupdate View
    By Big Duck in forum Qt Programming
    Replies: 1
    Last Post: 1st June 2006, 21:32

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.