I have an Ecore model with classes A and B. This model can not be changed.
A has a many-to-one reference to B. B has no reference to A.
I would like to display a tree with Bs at the root and As as leaves. I would like to use EMF data binding. All examples I have seen assume that there is a list feature of the root to observe. However, in my scenario, there is no feature for this direction (i.e. B_to_A), only one for the reverse direction.
How do I create an Observable that observes B and notifies of changes of the As?
There is no mechanism for doing this. I have received a response from Tom Schindl: http://tomsondev.bestsolution.at/2009/06/06/galileo-emf-databinding-part-1/
unfortunately there’s no way. You’d have to define eOpposites
Related
I'm looking for an easy way (I think there isn't) to serialize a QGraphicsView or QGraphicsScene into XML or JSON.
I don't know if I'm supposed to save the View or the Scene. XML or JSON are fine I only need one of them. I just want to save a scene in a file to save it/load it
I found few stuff on other websites but it's seems quite complicated, or not really functional.
First of all, check out this very useful tutorial for working with json. Secondly, I think I've read you're working with a model-view based project?
If so, all model info should be saved and then there are two possibilities (depending on your design). Let's say you have created a model class PlayerList and you are showing all players using a PlayerListLayout or PlayerListView, a derived class from QVBoxLayout. Now there are two possibilities:
In each of the view classes, you have a direct reference to the model class. Well, all you need is to ask the model using getters (these getters would exist already, else you don't want to visualize the information). You don't need the json file, as long as you initialize your model first. So, for the PlayerListLayout, all you need to do is ask each Player* of that PlayerList-member and call PlayerLayout::read(Player* player) on all PlayerLayout members of PlayerListLayout. PlayerLayout will initialize it's new player-reference and ask the name, the capital, etc. to visualize it.
In one of the view class, you have no reference to any model class. Then you shall have to pass either the model or the json file to that view class, so you can get/read the information (again). This is a less clean way, which I don't prefer. It happened to me that I was creating large functions to read; that's when I found out something had to change. Reading and writing should be easy (if you divide the responsibilities in multiple classes).
I've had a Monopoly project, where I used this serialization as well, and the tutorial was really helpful. Secondly, I opened the .json file outside the model class (so in the view class), which you might want to consider as well. The disadvantage is that "when you want wo re-use the model classes, but not the view classes", you shall have to reimplement the opening and closing of a file in your new gui.
However, this way you create parallelism throughout your code, because returning true/false will happen in the view class of the main model (MonopolyLayout in my case), so the methods Monopoly::read(...), Board::read(...) all behave in a similar way.
I have a class used for permanent storage of some item that are organized in a table-like manner. This class is totally unrelated to Qt and comes from a different library. Lets call this class DataContainer for the rest of this question. It provides std-c++ compatible iterators to access and manipulate the content.
I need to display and modify that data through a Qt GUI. My idea was to create a class DataContainerQtAdaptor that inherits from QAbstractTableModel and stores a pointer to the DataContainer object. The DataContainerQtAdaptor serves as an adaptor to the DataContainer object and all manipulation from inside of my Qt app is done through this adaptor. Then I use a QTableView widget to display the information.
Unfortunately the DataContainer might be changed by threads/processes. (For example think of DataContainer as some C++ class that encapsulates a database connection and that database might be changed by someone else.)
Questions:
1) Assume I have a function that is called everytime the internal structur of the DataContainer object has been changed. What is the correct function of the QAbstractTableModel that must be called to inform the model of the underlying change? I need something like "Dear Model, your persistent storage backend changed. Please, update yourself and emit a signal to every attached view in order to reflect this change".
2) Lets say 1) is solved. What is the best way to avoid a "double" GUI update in case the change was triggered through the GUI? E.g: User clicks on a cell in the table widget -> table widget calls setData of the model -> model pushes change to backend -> backend triggers its own "onUpdate" function -> model re-reads complete backend (although it already knows the change) -> GUI is updated a second time
3) The user should be able to insert new rows/columns through the GUI and put data into it. But the position is detemined by this data, because the backend keeps the data sorted. Hence, I have the following problem: The user decides to create a new row at the end and the new data is pushed to the backend. When the backend/model is re-read this data is normally not at the last position, but has been inserted somewhere in the middle and all other data has been moved forward. Ho do I keep all the properties of the the table view widget like "selection of a cell" in sync?
I believe, there must be some simple standard solution to all these question, because it is the same way as QFileSystemModel works. The user selects a file and some other process creates a new file. The new file is displayed in the view and all subsequent rows move forward. The selection moves forward, too.
Matthias
Model Semantics
First of all, you must ensure that the QAbstractItemModel cannot be in an inconsistent state. This means that there are some signals that must be fired on the model before certain changes to the underlying data are done.
There is a fundamental difference between changes to structure and changes to data. Structure changes are the rows/columns of the model being added or removed. Data changes affect the value of existing data items only.
Structural changes require calling beginXxx and endXxx around the modification. You cannot modify any structure before calling beginXxx. When you're done changing the structure, call endXxx. Xxx is one of: InsertColumns, MoveColumns, RemoveColumns, InsertRows, MoveRows, RemoveRows, ResetModel.
If the changes affect many discontiguous rows/columns, it's cheaper to indicate a model reset - but be wary that selections on the views might not survive it.
Data changes that keep the structure intact merely require that dataChanged is sent after the underlying data was modified. This means that there is a window of time when a call to data might return a new value before dataChanged is received by the object that queries the model.
This also implies that non-constant models are almost useless from non-QObject classes, unless of course you implement bridge functionality using observer or similar patterns.
Breaking Update Loops
The Qt-idiomatic way of dealing with update loops on the model is by leveraging the item roles. It's entirely up to you how your model interprets the roles. A simple and useful behavior implemented by QStringListModel is simply to forward the role from the setData call to dataChanged, otherwise ignoring the role.
The stock view widgets react only to dataChanged with the DisplayRole. Yet, when they edit the data, they call setData with the EditRole. This breaks the loop. The approach is applicable both to view widgets and to Qt Quick view items.
Insertion of Data into Sorted Models
As long as the model properly emits the change signals when the sorting is done, you'll be fine.
The sequence of operations is:
The view adds a row and calls model's insertRow method. The model can either add this empty row to the underlying container or not. The key is that the empty row index must be kept for now.
The editing starts on an item in the row. The view state changes to Editing.
Editing is done on the item. The view exits the editing state, and sets the data on the model.
The model determines the final position of the item, based on its contents.
The model invokes beginMoveRows.
The model changes the container by inserting the item at the correct location.
The model invokes endMoveRows.
At this point, everything is as you expect it to be. The views can automatically follow the moved item if it was focused prior to being moved. The edited items are focused by default, so that works fine.
Required Container Functionality
Your DataContainer doesn't have enough functionality to make it work unless all access to it were to be done through the model. If you want to access the container directly, either make the container explicitly inherit QAbstractXxxxModel, or you'll have to add a notification system to the container. The former is an easier option.
Your core question reduces to: can I have model functionality without implementing some variant of the model notification API. The obvious answer is: no, sorry, you can't - by definition. Either the functionality is there, or it isn't. You can implement the notification API using an observer pattern if you don't want the container to be a QObject - then you'll need your model shim class. There's really no way around it.
The QFileSystemModel gets notified by the filesystem about individual directory entries that have changed. Your container has to do the same - and this amounts to providing a dataChanged signal, in some shape or form. If the model has items that get moved around or added/removed - its structure changes - it has to emit the xxxAboutToBeYyy and xxxYyy signals, by calling the relevant beginZzz and endZzz methods.
Indices
The most important underdocumented aspect of QModelIndex is: its instances are only valid for as long as the model's structure hasn't changed. If your model is passed an index that was generated prior to a structure change, you're free to behave in an undefined way (crash, launch a nuclear strike, whatever).
The whole reason for the existence of QModelIndex::internalPointer() is your use case of having an underlying, complex-indexed data container. Your implementation of the model's createIndex method must generate index instances that store references to the DataContainer's indices in some form. If those indices fit in a pointer, you don't need to allocate the data on the heap. If you need to allocate the container index storage on the heap, you must retain a pointer to this data and delete it any time the container's structure changes. You're free to do it, since nobody is supposed to use the index instance after a structure change.
From the documentation of method bool QAbstractItemModel::insertRows(int row, int count, const QModelIndex & parent = QModelIndex()):
If you implement your own model, you can reimplement this function if
you want to support insertions. Alternatively, you can provide your
own API for altering the data. In either case, you will need to call
beginInsertRows() and endInsertRows() to notify other components that
the model has changed.
The same goes for removeRows() and moveRows() (they have their own begin*() and end*() methods). For modifying data of existing item there's a dataChanged() signal.
Here's how it goes (answer for question 1):
Implement your own methods for inserting/deleting/modifying data, where each of those methods must look like this:
beginInsertRows(parentIndex, beginRow, endRow);
// code that modifies underlying data
endInsertRows();
beginRow and endRow must be provided to inform which where the rows will be inserted and how many of them (endRow-beginRow).
For beginDeleteRows() and beginMoveRows() it's the same.
When you have a method which simply modified data in existing item, then this method must emit signal at the end: dataChanged().
If you do a lot of changes in the data, it sometimes is simpler to just call beginResetModel() and endResetModel() in the method performing this huge modification. It will cause all views to refresh all data in it.
Answer for question 2:
This is up to the View class implementation if it will "double-update". When you enter data in the View, data is sent to the model through one of the edition methods in model (insertRows(), setData(), etc). Default implementation of those methods always use begin*() and end*() methods and so the proper notification signals are emitted by the model. All Views listen to those signals, including the one you used for entering the data, therefore the "double-update" will be performed.
The only way to define this behaviour is to inherit the View and reimplement its protected slots (like dataChanged() and similar) to avoid updating if the value was detected to be provided by this view.
I'm not sure if Qt views do that already or not. Answer to this requires someone more educated in Qt internals, or looking into Qt source code (which I don't have at the moment). If somebody knows this, please comment and I will update the answer.
I think it's not that bad to reload the data from model - it guarantees that what you see is indeed the value from the model. You avoid possible problems with the Editor and the View bugs.
Answer for question 3:
When you reload whole model, then there is no simple way to keep track of selection. In that case you need to ask view->selectionModel() about current selection and try to restore it after reload.
However if you do partial refreshing (using methods I described in answer 1), then the View will track the selection for you. Nothing to worry about.
Final comments:
If you want to edit data from outside of model class, you can do it. Just expose begin*() and end*() methods as public API, so other code that edits data can notify model and views about changes.
While it can be done, it's not a good practice. It may lead to bugs, because it's easy to forget about calling notification everywhere you modify the data. If you have to call model API to notify about changes, why not already move all editing code insise the model and expose editing API?
In Qt, I'm writing my own tree model (by subclassing QAbstractItemModel) which wraps around an existing data structure. It should be possible to update the data structure internally (not via the model) as well as via the model (so views can change it). In order to imagine it better: it's a scene graph which should be possible to edit using a scene view (without going via the Qt model) but also using an outliner (QTreeView which uses a Qt model as a proxy around the scene graph).
To avoid confusion we should consider two different scenarios (in the following, I use the "remove" operation as an example):
The user uses the Qt view to remove a node. The view wants to remove a row from the model using QAbstractItemModel::removeRow. This should in turn remove a corresponding node from the underlying data structure, the scene graph.
The user uses the scene view to remove a node. The scene view wants to remove a node from the scene graph. The model which wraps around the scene graph gets notified and in turn wants to notify connected views that a row has just been removed.
While I think I know how to implement 1., I don't know how to implement the notifying part in 2. There is the signal QAbstractItemModel::rowsAboutToBeRemoved() as well as rowsRemoved() which sound like they're my friends. But they are private signals (they say in the header source code: "can only be emitted by QAbstractItemModel"). There also is beginRemoveRows() and endRemoveRows() but according to their documentation, they should be called when the updates happens from the view, i.e. when removeRow has been called. Also, when I tried to use them, the view was screwed up totally.
According to the documentation it seems like it's not intended that the model class can model self-modifying data. Let's take a file system as another example. When using file system watching, which can detect changes in directories, a model should notify a view so the changes in the directory can be displayed live, even if the view was not used to modify the file system. Are such models even possible in Qt?
You're reading it wrong. The model must signal to its users when it's about to start changing its "geometry". So, no matter what is removing the rows from the model, it must tell the outside world that it happened. The sequence of events when a view removes rows from the model is such:
The view calls model->removeRows().
The model calls beginRemoveRows()
The model actually removes the rows from the internal data.
The model calls endRemoveRows().
If you implement some other interface that will remove the rows without calling model->removeRows(), you have to do exactly the same thing. It doesn't matter if it's a view or some other code that removes rows from the model, the model's behavior must be the same or else nothing will work.
You can architect an adapter class that's inserted between your SceneGraph and the Model. It should hold a pointer to the scenegraph and the model, and translate the operations between the two.
My app deals with a ton of data that I call 'Subdata' (because it's a child of my real data and not independent). They all follow a similar format: they all have ids, a type and a pointer to the parent element. This all works just fine in Ember.js the way I have it now. The server has no notion of the type (just a field of the object), but the client does. I have different Ember.js models for each type so they can each have different properties.
My problem is that I need to convert from normal subdata to typed subdata. I could do this in my adapter and transform the JSON as soon as it gets in. But I found a more elegant way using the filterProperty method. I can just make properties that filter based on the mixed subdata array. Ignoring performance (which I'm not worried about), it seems like a much cleaner method.
However, the resulting array returned from filterProperty is an array of SubdataModels. How can I convert those models to a particular subclass of SubdataModel?
I've got 2 applications (lets call them AppA and AppB) communicating with each other.
AppA is sending objects to AppB.
There could be different objects and AppB does not support every object.
An object could be a Model (think of a game, where models are vehicles, houses, persons etc).
There could be different AppBs. Each supporting another base of objects.
E.g. there could be an AppB which just supports vehicle-models. Another AppB just supports specific airplane-models.
The current case is the following:
There is a BasicModel which has a position and an orientation.
If another user wants extra attributes, he inherits an ExpandedModel. And adds e.g. an attribute Color.
Now every user who needs additional attributes inherits from a more general model. After a while there is a VehicleModel which could activate windshield-wipers, an AircraftModel which could have landing lights or a PersonModel which could wave goodbye when a certain boolean is set to true.
The AppB always needs to be customized if it should support a new Model.
This approach has a big disadvantage: It's getting extremely complex after a few inheritations. Perhaps there are redundancies like an ExpandedAircraftModel which could use windschield-wipers too.
Another approach:
I create just one Model-class which has an attribute-list. The most easy implementation would be a std::map where the Key is the attribute-name and the Value is the attribute-value.
The user could now enter as much information as he wants. If he wants to use a windshieldwiper he just adds a "windshieldwiper - ON"-pair.
If AppB supports windshieldwipers it just looks if there is such an attribute in the list and reads the related value.
A developer of AppB needs to document well what attributes he supports. Every developer has to check if the specific attribute is already existing and how it is called (e.g. one developer could name his attribute windshieldwiper and another calls it windshield-wiper)
This could get extremely complex too and the only thing a user can relate to is the documentation or a specific standard-specification which has to be kept at a central space.
Finally, the question:
Which approach is better?
Did you see any additional disadvantages?
Is there a third approach which should be used instead of these two?
Just for a comparison, Google's Protocol Buffers uses a combination of both but leans hard toward your second example.
If you have distinctly different data that needs to be sent over the channel, you use the tool to generate a derivitive of the "message" class, but each message can contain other messages, and you can nest message definitions in themselves. When a message is sent out, the receiver checks the fields to determine what type of message it is and what fields are contained within.
The downside is that your code becomes overly verbose very quickly, as you can't really use inheritance to automate the process of acting on an incoming message, but the upside is that your protocol messages stay highly organized and easy to DEBUG since you're using a reflexive attribute list of sorts.