How to access another field/combo in the rowedittemplate during creation of a grid row when selectionChanged or checkValue happens? - infragistics

The situation is as follows :
I am creating a row in the grid. I have several properties among which are one combo called 'department' and one field called 'name'. The business rule is that all the 'names' in a 'department' must be unique. The grid does not load all the department-name combinations so I have to make a call to the back-end. I want to make this call when
selectionChanged on the 'department' combo happens or
when 'checkValue' of the validator options of the 'name' filed happens.
This way I check when either changes. The problem is that this happens during creation and there are no rows in the datasource and no accumulated rows in the transaction log.
How can I access the fields of the 'rowEditTemplate' during creation during these particular events in order to check my values? Is there any other/better way to achieve this?

The editors are not created until you do the first edit. You could use the editRowStarted event to attach your editors logic. They are obtainable using the editorForKey method.
editRowStarted: function (evt, ui) {
var comboEditor = ui.owner.editorForKey("ProductDescription");
}
I created a small fiddle that assigns a data source for the combo on editRowStarted. It should work as a starting point for what you are trying to achieve.
http://jsfiddle.net/hfen0qea/

Related

Display modified data from QAbstractListModel in QTableView

I have a QAbstractListModel that has a bunch of custom objects stored in it, and you can access the different fields of the custom objects in the model by specifying a role (if this is an improper use of Qt roles let me know because I must be confused). I want to display this data in a user friendly QTableView. I can get things displaying using a proxy model, but the issue is I don't want to display the raw values, I want to display specific data derived from the raw data. So for instance, I don't want a column for both ItemA.foo and ItemA.bar, I want to display just ItemA.foo - ItemA.bar in a single column. And to add to that, I want the automatic update functionality you get with models where if either ItemA.foo or ItemA.bar change, I want the difference column to automatically update and recalculate.
I would think that the way to do this would be to use some kind of table proxy model that listens to the source model, and then populates its own fields with the values derived from the source model and listens for dataChanged() signals from the source model. Then you plug this proxy model in to a QTableView. But to me this sounds like something that should be done in a view. Or is this something that should be done by the delegate? I could even go so far as to do these calculations in the base model itself and add roles specific to these values that should be displayed in the table, but that sounds like I am really overloading the responsibilities of the model.
TLDR: How do you manipulate data from a model in a QTableView? Should I do the data manipulation in the base model and then send that to the QTableView? Should I use a proxy model that manipulates the base data and sends it to the QTableView? Or am I completely misunderstanding something?
and you can access the different fields of the custom objects in the model by specifying a role
If you look at the documentation for Qt::ItemDataRole, you would see that Qt models should indeed provide different data for different roles but each role means some distinguished purpose of the data corresponding to the role. For example, the most commonly used role is probably Qt::DisplayRole as the data for this role defines the content displayed in the view e.g. it's the text in the table cell. If you are satisfied with all the other aspects of the view - font, background etc - you can just return empty QVariant for corresponding roles from your model, the view would figure out these details on its own. If you are using roles as a substitute for columns i.e. to return different pieces of conceptually the same data item, it is probably not the intended use of roles.
For the other part of your question - you can customize the appearance of data displayed in the view through the use of a delegate. For example, you could subclass QStyledItemDelegate, override its displayText method to display ItemA.foo - ItemA.bar instead of just ItemA.foo and then set this delegate into the column of your view corresponding to ItemA.foo via setItemDelegateForColumn. The tricky part here would be to detect changes in both ItemA.foo and ItemA.bar columns which would affect the text displayed in the delegate. A while back I implemented a dedicated class in one of my projects which listens to changes in some column of the original model and "reroutes" the change into another column through signal emitting. I did it to solve this very issue - to catch changes in what delegate should display although technically another model column is affected into which the delegate is not set.

Update of QTreeView without changing selection

I have a model that retrieves data from a table in a database from a certain SQL query, and shows the items in a QTreeView. The characteristics are:
the data comes from a table, but has an underlying tree structure (some rows are parents that have rows below them as children)
this tree structure is shown in the QTreeView
the children are selectable in the QTreeView (not so the parents)
the table in the database gets updated continuously
in the updates, a children can be added to any existing parent
periodically (with a QTimer) the QTreeView is updated with the contents of the table
Since the children are added at any time to any parent, the first silly approach when updating the QTreeView is clearing it all, and append all the rows again, in form of parent or children, to the QTreeView. This is a 0-order approximation, and it is indeed terrible inefficient. In particular, the following problems appear:
Any existing selection is gone
Any expanded parent showing its children is collapsed (unless ExpandAll is active)
The view is reset to show the very first row.
What is the best solution to this problem? I mean, the first solution I will try will be not to clear the QTreeView, but instead parse all the returned rows from the table, and check for each of them whether the corresponding item in the QTreeView exists, and add it if not. But I wonder if there is a trickiest solution to engage a given table in a database with a QTreeView (I know this exists for a QTableView, but then the tree structure is gone).
This thread mentions a general approach, but this might get tricky quickly, but I am not sure how this would work if the underlying model is changing constantly (i.e. the QModelIndex becoming invalid).
Worst case is that you will have to write your own mechanism to remember the selection before updating and then re-applying it.
I assume you use some model/view implementation? You could enhance your model with a safe selection handling, in case the example mentioned above does not work for you.
I guess this is the case for a self-answer.
As I presumed, after a careful analysis of what data is retrieved from the database, I had to do the following "upgrades" to the retrieval code:
I retrieve, along with the fields I want to show in the view, two identifiers, one for grouping rows and one for sorting items into groups
I also retrieve the internal record ID (an increasing integer number) from the table in the database, in order to ask only for new records in the next retrieval.
In the model population code, I added the following:
I first scan the initial records that may belong to existing groups in the model
When, in the scanning, I reach the last group in the model, this implies that the rest of retrieved records belong to new groups (remember the records are retrieved sorted such that items that belong to the same group are retrieved together)
Then start creating groups and adding items to each group, until we use all the records retrieved.
Finally, it is very important:
the use beginInsertRows() and endInsertRows() before and after inserting new items in the model
capture the sorting status of the view (with sortIndicatorSection() and sortIndicatorOrder()) and re-apply this sorting status after updating the model (with sortByColumn())
Doing that the current position and selection in the QTreeView receiving the model updates are preserved, and the items in the view are added and the view updated transparently for the user.

QTableView preserve selection after model refresh

I tried to build a user interface which displays the content of a table while the data is refreshed every second.
Therefore I have a chain of models:
QSqlTableModel - to access the tables content
MyModel - inherited from QIdentityProxyModel to modify the data a bit (source is the TableModel)
SomeFilterModels - which have MyModel as source
This chain ends in a QTableView. Because the QSqlTableModel is refreshed every second,
any selection in the TableView is removed every second also. Now I had two Ideas to fix this.
Prevent the TableModel from detecting changes. Which was not working very well.
Catching some events fired before and after the model is about to change to store and restore the current selection. Sadly the QIdentityProxyModel does not forward signals like modelAboutToBeReset or modelReset or dataChanged .. it is also impossible to reemit those signals from MyModel because they are private.
I was searching for other ways to counter those refresh problems without success. But I can't imagine that I am the first person who uses a chain of proxy models combined with a periodic model refresh and selections.
Can anyone give me some tips?
Thanks in advance.
Maybe worth to note:
One QSqlTableModel is used for many TableViews. (With a different FilterProxyModel chain.) So I can't just stop refreshing because one View has a selection.
You may think that I know when I call the models refresh method. But for now it is a bit to complicated to pass this trough my ui architecture. I mean the model is updated and the TableView has already a connection to the updated model through some ProxyModels. There should be no need for another way of communication.
Hope my question makes sense.
QAbstractItemModel includes a number of signals that can help you know when the data in the model is or will be changing. In particular, it has the following signals:
dataChanged
headerDataChanged
modelAboutToBeReset
modelReset
columnsAboutToBeInserted
columnsAboutToBeMoved
columnsAboutToBeRemoved
columnsInserted
columnsMoved
columnsRemoved
rowsAboutToBeInserted
rowsAboutToBeMoved
rowsAboutToBeRemoved
rowsInserted
rowsMoved
rowsRemoved
Given that you lose the selection, I assume that the bolded signals are the ones you want to be concerned with, because the default Qt behavior is to preserve selection if they can where the columns or rows are removed/inserted and it doesn't affect the selection.
Once you are connected to these signals, in modelAboutToBeReset I suggest getting IDs for the cells that you can reuse to select them again, and in modelReset then using those IDs to get the QModelIndexs and using them to again select the same cells.

QSortFilterProxyModel and the slot setFilterFixedString

I currently have a search button and I would like to search a specific column of my model.Thus I just want the matching rows to be displayed in my tableview.
I have attached a QSortFilterProxyModel* object as a source to the table view and have set a QStandardItemModel* as its source. Then with my search button I made the following connection
QObject::connect(ui.lineEditSearch,SIGNAL(textChanged(QString)),proxyModelFilter,SLOT(setFilterFixedString(QString)));
Now I was under the impression that upon typing the relevant rows will be returned. Then I realized that I havent specified as to which columns I want the filter proxy model to search.
I understand that I could implement a class that inherits from QSortFilterProxyModel and re implement its filterAcceptsRow. I wanted to know if there was a way for me to avoid creating a class that inherits from QSortFilterProxyModel and simply use the QSortFilterProxyModel class only to tell which columns to search on when the Slot setFilterFixedString is called ?
The column to filter by can be set via QSortFilterProxyModel::filterKeyColumn.
It allows to specify a single column, or all of them (-1, the default).
Alternatively, one can define a custom filter role returning a concatenation of all string to search for, and set it via setFilterRole().

GtkTreeView Column Header Click Event

I have a question. I have a GtkListStore and a GtkTreeView, and I want to sort the GtkListStore and update the result to the GtkTreeView when the user clicks on a certain column of the GtkTreeView. I am assuming that the columns are clickable, and cannot be re-ordered, so the numerical order of the columns can be used to set the sorting column's index. But I cannot seem to find which signal gets emitted when the user clicks on the header of a particular column. I have gone through the GTKMM documentation time and again, but it does not seem to be mentioned!
Use Gtk::TreeView::get_column(<column-no>) to get a particular column and attach to its "clicked" signal using Gtk::TreeViewColumn::signal_clicked():
Gtk::TreeViewColumn* col = myview.get_column(SOME_COLUMN_NUMBER);
col->signal_clicked().connect(sigc::mem_fun(*this,&some_method));
That's not how you're supposed to do it.
There can be several views hooked up to the same model; sorting is not something you do to the model, it's something you do to the view.
See the GtkTreeSortable interface (and its GtkTreeModelSort implementation).