Qt Drag and Drop Mime Data rejection - c++

I have a subclass of QStandardItemModel in which I have drag and drop working quite nicely. I store my data (pointers to classes) in a subclass of QStandardItem.
The classes stored in my standarditem all inherit from the same class, and I wish to enable collections of each subclass through dropping onto a collection type object.
E.g
--Apples
--braeburn
--golden delicious
--Oranges
--Meat
--pork
--lamb
--beef
So I can drag different types of apple underneath Apples, different meats under "Meat", etc. I do this by examining the type of both the target and the dropped item in my version of dropMimeData (i.e. get the stored class from my standardItem, check its type).
My problem is when I reject an item by returning false, the item is gone from the tree. Is there a way to get the original location of the dropped item, so I can put it back?

Related

How to signal QAbstractItemModel::dataChanged with changes to few columns only?

After updating the model data of my derived class of a QAbstractItemModel, I do not want the listeners (assume a QTreeView) to completely update all of the tree representation, but only the data in an individual column of most of the rows.
Example: I want to only update the second column of my items, so I thought I had to emit dataChanged(createIndex(0,1,&root), createIndex(rowCount(),1,&root);
However, this still updates the complete tree for some reason - is that expected behaviour? Does it have to do with the underlying model organisation (which works very similar to Qt's own simple tree example)? Or does it have yet other reasons I did not consider?

Which component of MV should transform raw data into user friendly format?

There is a structure that holds raw data (consider int) and a gui that should visualize this data. Gui part consists of a few models and and a few standard views (table and tree). The value should be presented either as a string or as a picture depend on user choice. There are some additional difficulties: in some cases the text is different for different elements - i.e., for the same column 0 normally means "Ok", but for a particular element it should be printed as "Yes", also depend on a user choice some columns should not print text for 0 values at all, living a cell empty and don't clutter the table; next, sometimes cell should show two values - e.g., current value and requested - something like "Yes -> No". This also applies to the case when user wants to see icons.
I see two options:
The model forms string text itself and store it somewhere (in the model item may be). The model also forms composite icon from base icons if it is needed. In that scenario I can use standard delegate and just use standard roles reimplementing QAbstractItemModel::data() method.
Reimplement delegates' paint() method (actually I need to reimplement delegates anyway because I need custom editors like QComboBox). The delegate can get any information it needs through the model and custom roles in paint() method and form the string or complex icon itself. As a suboption, I suppose, it's possible for a model to compose needed information itself, like returning std::tuple<int /*value*/, int /*requested value*/, int /*source element type*/, bool /*text or icon*/> in data() method for Qt::DisplayRole.
Update: I want add one thought about second option. Presumably delegates were introduced to handle the work of representing data. One of the consequences of that is the flexibility delegates can give. If you want to see a raw number in some column, you can just leave the default delegate, if you want some additional info presented in a cell you can set a special delegate for that specific column. And it seems you don't need even touch the model or something else.

Can I get all instances of some class in Qt?

I have implemented QAbstractItemModel and QSortFilterProxyModel with it as a source model. I have one itemModel instance and several filterModel instances. In each filterModel I have some variable value of which is calculated based on filtered data from itemModel. When itemModel is recreated (all items removed and the new ones are inserted back) value of this variable should be set to default (or just be recalculated after filtering is done).
The problem is that I don't have some list of pointers to filterModel instances to iterate by them. Sure I can create such static list in constructor. But probably MOC did it instead of me and saved such list inside of QMetaObject of this class?
Your filter proxy implementation is broken. The proxies are fully informed of each and every change to the model - that's why the models are QObjects and emit change signals! There's nothing preventing you from changing the "some variable" as appropriate, when the source model indicates that it has changed.
You need to think of your "some variable" as depending on some data (and structure!) from the source model. Every time the source model indicates changes to the dependent data or structure, your proxy must recompute the value - or at least set a flag so that the value might be recomputed lazily when needed.

Qt QTreeWidgetItem text contents vs widget item vs data

upon construction of QTreeWidgetItem you can pass a list of strings, so when you insert it in a table(QTreeWidget), you get the strings listed on a row. However, from the methods of the table you can also call setItemWidget and set a text widget or any sort of widget to be in that row, but it seems incompatible with having a string list, since the widget is drawn over the strings. There is also a setData method for the QTreeWidgetItem, which sets some data that can be retreived, but isn't visible to the user. Is there a cookie-cutter way of properly using all three data storage methods? Are they even compatible or must I stick to only one?
The Constructor of QTreeWidgetItem is convenient to immediately list the desired content.
When inserting a custom widget in a cell, you need to change its autoFillBackgroundproperty to true, so that it is not transparent. See the QTreewidget::setItemWidget description:
The given widget's autoFillBackground property must be set to true,
otherwise the widget's background will be transparent, showing both
the model data and the tree widget item.
QTreeWidgetItem::setData can be used when already having an item and you want to change one of its contents.
Of course you can combine any of these methods, but it is hard to say, which approach is best without knowing your use case. Just one more hint: If you just need a plain stupid representation of data that does not change, using QTreeWidget is fine. But if your displayed data can change, e.g. objects get deleted, added, changed in various locations of your code, a QTreeView with a custom data model might be a better choice.

Virtual List Controls (MFC)

I am using a List Control to display a representation of elements within a vector. When the list is clicked on another control shows information about that element. The index of the element is currently determined by its index in the control, however if I wish to sort or filter the results this will no longer work.
I have been told that I could use a virtual list control, but the MSDN is not very friendly, can someone run me through how I could use a virtual list control for this?
Frankly - tying data (the position in your data vector) to the presentation of the data in the list control (the position in the list ctrl) is something I would stay away from.
In MFC each control has a "Data" DWORD member variable - when coding in MFC I Always called "SetItemData" for each item added and passed in a pointer that the relevant row referred to e.g.
YourListCtrl.SetItemData((DWORDPTR)&YourData);
Then when the ListCtrl item is selected, you just call
DataTypeYouWant* pData = (DataTypeYouWant*)(YourListCtrl.GetItemData(indexofselecteditem));
Or somesuch thing.
Alternatively - if you don't want to use pointers - hold the index of the item in your original vector in the itemdata for your row (just pass it into the above fns).
To use a virtual list control, set the LVS_OWNERDATA style. You then need to handle the LVN_GETDISPINFO notification message (which is sent via WM_NOTIFY).
If you do this, you are entirely responsible for the data, including the order in which it is shown. Therefore it is up to you to handle sorting and so forth.
By far the easiest way is just to use the item data to set/get an ID that can be used to retrieve the original data, whether that's a vector index or a pointer to the data, or even a key into an associative container.
It really depends on the performance you require.
I have personally seen MAJOR increases in performance for lists holding massive amount of data. However it is much more work to implement, thus for simple uses with not so many data I recommend staying away from it.
Basically, what happens with virtual list controls is that you have your data somewhere in some data structure of your own. Since the list view shows only a small subset of the whole data, it queries you for the content to display when ever something happens (redraw necessary, scroll up or down, change the sorting, etc.).
I don't have handy examples for you. But you can look on codeguru, I am quite sure there are very good examples to start from.
The purpose of virtual list controls is totally different: You should use it for performance reason when you have A LOT of items in your list (I'd say 2500+).
In your case, all you need is to store the vector index in the list item data as NotJarvis explains.