How to calculate figure's size including all sub figures (that have separate edit parts) in GEF? - eclipse-gef

I'm trying to draw diagram that contains a single entity which holds multiple elements inside.
My MVC structure looks something like this:
Model: contains EntityModel.java and ElementModel.java which represents my model objects.
View: EntityFigure.java and ElementFigure.java
Controller: EntityEditPart.java and ElementEditPart.java
I'm overriding getModelChildren() in EntityEditPart.java to return list of ElementModel.java so that is how GEF knows that an element "belongs" to an entity.
Since I would like to calculate my entity's figure size and include the embedded elements in this calculation, I cannot call entityFigure.getPreferredSize() during createFigure() in EntityEditPart.java since at this point - the elements figures do not exists (createFigure() in ElementEditPart.java is not invoked yet).
I'm looking for a place to set my entity figure after all child figures were created.
I though about overriding addNotify() in ElementEditPart.java, however, it is being called after creating a specific inner element and not after all elements created.
Any ideas?
Hope I was clear enough...

You can do it in an extension of
refreshChildren()
method of an edit part, since all the child creation is done in refreshChildren() of superclass's (AbstractEditPart) refresh method:
public void refresh() {
refreshVisuals();
refreshChildren();
}
Or, you can just extend
refresh()

Related

How to model updated items with UICollectionViewDiffableDataSource

I'm struggling to understand how to use UICollectionViewDiffableDataSource and NSDiffableDataSourceSnapshot to model change of items.
Let's say I have a simple item which looks like this:
struct Item {
var id: Int
var name: String
}
Based on the names of the generic parameters, UICollectionViewDiffableDataSource and NSDiffableDataSourceSnapshot should operate not with Item itself, but only with identifier, which Int in this example.
On the other hand, again based on names of generic parameters, UICollectionView.CellRegistration should operate on complete Item's. So my guess is that UICollectionViewDiffableDataSource.CellProvider is responsible for finding complete Item's by id. Which is unfortunate, because then aside from snapshots, I need to maintain a separate storage of items. And there is a risk that this storage may go out of sync with snapshots.
But it is still not clear to me how do I inform UICollectionViewDiffableDataSource that some item changed its name without changing its id. I want UICollectionView to update the relevant cell and animate change in content size, but I don't want insertion or removal animation.
There are two approaches that would work solve your problem in this scenario.
The first is to conform your Item model to the hashable protocol. This would allow you to use the entire model as an identifier, and the cell provider closure would pass you an object of type Item. UICollectionViewDiffableDataSource would use the hash value for each instance of your model (which would consider both the id and name properties, thereby solving your name changing issue) to identify the data for a cell. This is better than trying to trick the collection view data source into considering only the id as the identifier because, as you stated, other aspects of the model might change. The whole point of structs is to act as a value-type, where the composition of all the model's properties determine its 'value'...no need to trick the collection view data source into looking only at Item.id.
Do as you said, and create a separate dictionary in which you can retrieve the Items based on their id's. While it is slightly more work to maintain a dictionary, it is a fairly trivial difference in terms of lines of code. All you should do is dump and recalculate the dictionary every time you apply a new snapshot. In this case, to update a cell when the model changes, make sure to swap out the model in your dictionary and call reloadItem on your snapshot.
While the second option is generally my preferred choice because the point of diffable data source is to allow for the handling of massive data sets by only concerning the data source with a simple identifier for each item, in this case your model is so simple that there's really no concern about wasted compute time calculating hash values, etc. If you think your model is likely to grow over time, I would probably go with the dictionary approach.

How to bind a domain object to a JavaFX TreeView?

How can I bind a domain object to a JavaFX TreeView? ComboBox has getItems() and you can add something to that collection. TreeView does not seem to have such a method. I could only build the tree manually by adding TreeItems to the TreeView's root and then using getChildren().add(...) to add children, but there seems no way of just adding an observable tree structure.
The domain object can read itself from a file and write itself to a file. It has methods to modify its contents. How do I best hook this up with a TreeView so that the user can add and delete nodes?
I don't want GUI code (i.e., JavaFX classes) in my domain objects.
Do I need to write an Adapter class that can turn my domain object into a JavaFX tree? Then add listeners to the tree and map the changes back to the domain object? Or is there a better way?
Some time ago I had a similar problem. I've written a custom TreeItem implementation that can handle recursive data structures. I've written a blog post with a detailed explanation here.
The code for the RecursiveTreeItem can be found as gist.
As an example think of a class Task that can contain many sub-tasks and so on.
public class Task {
private ObservableList<Task> subtasks = FXCollections.observableArrayList();
public ObservableList<Task> getSubtasks() {
return subtasks;
}
}
In this case you could use it as follows:
Task root = new Task();
TreeItem<Task> rootItem = new RecursiveTreeItem<Task>(root, Task::getSubtasks);
tree.setRoot(rootItem);
The second parameter is of type Callback<T, ObservableList<T>>: a function that takes an element of T (in our case Task) and returns the child elements for this element. In the example I've used a method reference as a shortcut.
This is a fully reactive implementation i.e. when a new sub item is added it will immediately be shown in the TreeView.
You said you don't like to have JavaFX classes in you domain model. In this case you could write something like this (not tested):
TreeItem<Task> rootItem = new RecursiveTreeItem<Task>(root,
task -> FXCollections.observableArrayList(task.getSubtasks()));
Here getSubtasks() returns a plain List<Task> that is wrapped in an observableList. But of cause in this case the TreeView won't update automatically when your model changes.

QTreeView: Filtering contents - looking for best practices

I have a QTreeView in which I wish to filter the contents. I only wish to filter these contents on the top level children (the ones immediately below the root index). Currently I am accomplishing this by creating a simple filtering method in my QTreeView subclass and selectively hiding those rows that do not match.
While the above approach seems to work fine, I am wondering whether I should re-implement this using a QSortFilterProxyModel. If so, what would be the advantages?
If I change to using the QSortFilterProxyModel, I have a few (hopefully small) questions:
1) Since I am filtering only on the top-level children, I would have to re-implement whatever method was actually doing the sorting so that it would leave all the grandchildren alone, right?
2) My data model has a number of custom methods in it that are responsible for unique keyboard navigation and the like. Do I re-implement these in the proxy model and have them point to my data model's methods? If so, how to I reference the model? I can't seem to find any thing comparable to a QTreeView's model() method.
Thanks!
Using a derived class from QSortFilterProxyModel is better. You keep responsibilities of sorting outside of your tree view.
To reuse at maximum the existing code, you can override filterAcceptsRow like this
bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow,
const QModelIndex &sourceParent) const
{
if( sourceParent.IsValid() ) return true; // Don't filter other than top level
return QSortFilterProxyModel( sourceRow, sourceParent );
}
For the custom methods, you will need to implement them in your proxy. Then for the navigation, you may need to used mapToSource and mapFromSource to convert proxy index to orignal model index

Mimicking SQL Insert Trigger with LINQ-to-SQL

Using LINQ-to-SQL, I would like to automatically create child records when inserting the parent entity. Basically, mimicking how an SQL Insert trigger would work, but in-code so that some additional processing can be done.
The parent has an association to the child, but it seems that I cannot simply add new child records during the DataContext's SubmitChanges().
For example,
public partial class Parent
{
partial void OnValidate(System.Data.Linq.ChangeAction action)
{
if(action == System.Data.Linq.ChangeAction.Insert)
{
Child c = new Child();
... set properties ...
this.Childs.Add(c);
}
}
}
This would be ideal, but unfortunately the newly created Child record is not inserted to the database. Makes sense, since the DataContext has a list of objects/statements and probably doesn't like new items being added in the middle of it.
Similarly, intercepting the partial void InsertParent(Parent instance) function in the DataContext and attempting to add the Child record yields the same result - no errors, but nothing added to the database.
Is there any way to get this sort of behaviour without adding code to the presentation layer?
Update:
Both the OnValidate() and InsertParent() functions are called from the DataContext's SubmitChanges() function. I suspect this is the inherent difficulty with what I'm trying to do - the DataContext will not allow additional objects to be inserted (e.g. through InsertOnSubmit()) while it is in the process of submitting the existing changes to the database.
Ideally I would like to keep everything under one Transaction so that, if any errors occur during the insert/update, nothing is actually changed in the database. Hence my attempts to mimic the SQL Trigger functionality, allowing the child records to be automatically inserted through a single call to the DataContext's SubmitChanges() function.
If you want it to happen just before it is saved; you can override SubmitChanges, and call GetChangeSet() to get the pending changes. Look for the things you are interested in (for example, delta.Inserts.OfType<Customer>(), and make your required changes.
Then call base.SubmitChanges(...).
Here's a related example, handling deletes.
The Add method only sets up a link between the two objects: it doesn't mark the added item for insertion into the database. For that, you need call InsertOnSubmit on the Table<Child> instance contained within your DataContext. The trouble, of course, is that there's no innate way to access your DataContext from the method you describe.
You do have access to it by implementing InsertParent in your DataContext, so I'd go that route (and use InsertOnSubmit instead of Add, of course).
EDITED I assumed that the partial method InsertParent would be called by the DataContext at some point, but in looking at my own code that method appears to be defined but never referenced by the generated class. So what's the use, I wonder?
In linq to sql you make a "trigger" by making a partial class to the dbml file, and then inserting a partial method. Here is an example that wouldn't do anything because it calls the build-in deletion.
partial void DeleteMyTable(MyTable instance)
{
//custom code here
ExecuteDynamicDelete(instance);
//or here :-)
}

How can I extract a part of a xaml object graph via linq to xml?

I have an object graph serialized to xaml. A rough sample of what it looks like is:
<MyObject xmlns.... >
<MyObject.TheCollection>
<PolymorphicObjectOne .../>
<HiImPolymorphic ... />
</MyObject.TheCollection>
</MyObject>
I want to use Linq to XML in order to extract the serialized objects within the TheCollection.
Note: MyObject may be named differently at runtime; I'm interested in any object that implements the same interface, which has a public collection called TheCollection that contains types of IPolymorphicLol.
The only things I know at runtime are the depth at which I will find the collection and that the collection element is named ``*.TheCollection`. Everything else will change.
The xml will be retrieved from a database using Linq; if I could combine both queries so instead of getting the entire serialized graph and then extracting the collection objects I would just get back the collection that would be sweet.
Will,
It is not possible to find out whether an object implements some interface by looking at XAML.
With constraints given you can find xml element that has a child named .
You can use following code:
It will return all elements having child element which name ends with .TheCollection
static IEnumerable<XElement> FindElement(XElement root)
{
foreach (var element in root.Elements())
{
if (element.Name.LocalName.EndsWith(".TheCollection"))
{
yield return element.Parent;
}
foreach (var subElement in FindElement(element))
{
yield return subElement;
}
}
}
To make sure that object represented by this element implements some interface you need to read metadata from your assemblies. I would recommend you to use Mono.Cecil framework to analyze types in your assemblies without using reflection.
#aku
Yes, I know that xaml doesn't include any indication of base types or interfaces. But I do know the interface of the root objects, and the interface that the collection holds, at compile time.
The serialized graphs are stored in a sql database as XML, and we're using linq to retrieve them as XElements. Currently, along with your solution, we are limited to deserializing the graphs, iterating through them, pulling out the objects we want from the collection, removing all references to them from, and then disposing, their parents. Its all very kludgy. I was hoping for a single stroke solution; something along the lines of an xpath, but inline with our linq to sql query that returns just the elements we're looking for...

Resources