I am using JFace CheckboxTreeViewer and adding on ICheckStateListener to get checked elemets,
My CheckboxTreeViewer structure is as follows,
P1
----Child1
----Child2
----Child3
----Child4
P2
----Child6
----Child7
----Child8
----Child9
My Requirement is that when I am checked a Children node to get its Related parent node
for example
when I checked Child8 then get Parent Node p2
when I checked Child2 then get Parent Node p1
how to achieve this?
You get the element that has changed from the CheckStateChangedEvent passed to the listener by calling the getElement method:
public void checkStateChanged(CheckStateChangedEvent event) {
Object changed = event.getElement();
This is the object that your tree content provider provided. So you can get its parent by asking the content provider:
ITreeContentProvider provider = (ITreeContentProvider)viewer.getContentProvider();
Object parent = provider.getParent(changed);
where viewer is the CheckboxTreeViewer.
Related
I am experimenting with ZK framework and look for ways to load a zul-defined view programmatically via a utility class that uses Executions to load a view definition programmatically.
I do however fail to find a way to set the view model class programmatically, which would be very convenient and would allow some very simple way of reusing a view with different view model classes.
I.e. the code to load the view looks like this:
public static Component loadComponent(Class<?> modelClz, String zulFile, Component parent, Map<String,Object> params) {
Execution exec = Executions.getCurrent();
PageDefinition page = exec.getPageDefinitionDirectly(
new InputStreamReader(modelClz.getResourceAsStream(zulFile)),
null
);
return exec.createComponents(
page,
// no (previous parent)
parent,
params
);
}
I thought about "forcing" the view model by setting annotations programmatically on the top component info from the page definition, like so:
public static Component loadComponent(Class<?> modelClz, String zulFile, Component parent, Map<String,Object> params) {
Execution exec = Executions.getCurrent();
PageDefinition page = exec.getPageDefinitionDirectly(
new InputStreamReader(modelClz.getResourceAsStream(zulFile)),
null
);
if (!page.getChildren().isEmpty()) {
ComponentInfo top = (ComponentInfo) page.getChildren().get(0);
AnnotationMap annotationMap = top.getAnnotationMap();
String viewModel = "viewModel";
if (annotationMap==null || !annotationMap.getAnnotatedProperties().contains(viewModel)) {
// no view model set on top declaration,
// force ours
Map<String,String[]> id = new HashMap<>();
id.put(null, new String[]{"vm"});
top.addAnnotation("viewModel","id",id, null);
Map<String,String[]> init = new HashMap<>();
init.put(null, new String[]{String.format("%s", modelClz.getName())});
top.addAnnotation("viewModel","init",init, null);
top.enableBindingAnnotation();
}
}
return exec.createComponents(
page,
// no (previous parent)
parent,
params
);
}
This did not work however. Maybe it was too late in the process. Or there is some really simple way of doing this but I missed it. Or maybe I should "apply" some BindComposer, but I am not sure how to do that.
Any helpful idea would be great!
Just to make sure I've understood:
You have some zul fragment (such as a reusable UI structure)
This fragment uses the MVVM pattern, but you want to choose a viewModel object when you are instantiating that fragment, instead of declaring a class name in the zul viewModel="#id()#init()" attribute
You want to initialize that fragment from a java class that has access to the UI (using Execution#createComponents to load the fragment and attach them to the page)
Does that sound correct?
If that's the case, you can make this way simpler
The attribute can be written as viewModel="#id('yourVmId')#init(aReferenceToAnAlreadyInstantiatedObject)".
Important note here: Notice that I have NOT put quotes around the object in the #init declaration. I'm passing an actual object, not a string containing a reference to a class to be instantiated.
When you invoke execution.createComponents() you may pass a map<String, Object> of arguments to the created page. You can then use the name of the relevant passed object when you create bind the VM.
have a look at this fiddle (bit rough, but it should make sense): https://zkfiddle.org/sample/2jij246/4-Passing-an-object-through-createComponents-as-VM#source-2
HashMap<String, Object> args = new HashMap<String, Object>();
args.put("passedViewModel", new GenericVmClass("some value in the passed VM here"));
Executions.createComponents("./fragment.zul", e.getTarget().getPage(),null, args);
FYI if you are using ZK shadow-elements, you can also pass that object to the fragment from an apply with a source in pure MVVM pattern.
The <apply> shadow element for example can pass objects to the created content with a variable name, and you can use that variable name when initializing the VM.
Regarding BindComposer:
You need to instantiate BindComposer up to ZK 7.X
In ZK 8.X and above, BindComposer will be instantiated automatically when you use the viewModel="..." attribute on a ZK component.
I want to access to a specific property in resource.
The main resource hat two children and the app is in the first one. I want to get a property from the second child.
Can i find something like :
${resource.parent.child[1].valueMap.title}
Thanks!
To start - note that the order of the children may not be guaranteed, unless you're using sling:OrderedFolder or some other ordered type. So trying to get the "second" child may not even make sense.
Having said that, there may some valid use cases that I am not thinking of for needing to get the second child -- as far as I can tell you will need to create a Java or JS object and make use of the Use Api.
Simple Example Java object
package apps.your_app.components.yourComponent;
import com.adobe.cq.sightly.WCMUsePojo;
import org.apache.sling.api.resource.Resource;
import java.util.Iterator;
public class Model extends WCMUsePojo {
#Override
public void activate() throws Exception {
//do some stuff if needed
}
public Resource getSecondSibling() {
Resource parent = getResource().getParent();
Resource secondSib = null;
Iterator<Resource> children = parent.listChildren();
//find the second child
for (int i = 0; i < 2; i++)
secondSib = children.next();
return secondSib;
}
}
Using it in the sightly:
<sly data-sly-use.model="Model">${model.secondSibling.propertyName}</sly>
Here's another example that i used with converting the content to JSON. The contents of the JSON as parsed Objects and each Object has Attributes.
<div data-sly-use.jsonHelper="${'com.service.helpers.JSONHelper'
#json=model.getRawJson}">
${jsonHelper.parsedJSON[item].commodityList[subitem].name}
...
</div>
Given the following example:
public class Parent
{
public Guid ID {get;set;}
public string Name {get;set;}
public Child Child {get;set;}
}
public class Child
{
public Guid ID {get;set;}
public string Name {get;set;}
}
I want to save a Parent object instance, with a Child instance assigned to it. The fact here is: the given child object already exists in the Database,
Parent p = new Parent();
p.ID = Guid.NewGuid();
// Get the Child Object
Child c = GetTheChild(...);
p.Child = c;
SaveParent ( p );
in function Save Parent, the following code is implemented:
public void SaveParent ( Parent p )
{
using (MyContext context = new ClinicContext())
{
context.Parents.Add( P );
context.SaveChanges();
}
}
Now the problem comes: since the child in this example already exists in the database, but when adding the parent in the context DBSet, the entity c given also holds a entry state of "Added", guess what? DBContext tries to save another child record with a duplicated Key!
Any body know how to solve this? I am thinking whether there is a way to turn a Insert into Update if the Entity Framework can detect the records already exists in the database.
Thanks for your help.
If you add an entity all releated entity will be added. If you attach an entity all related entities will be attached. In your case you want to add the Parent entity and then attach the child entity. What you could also try would be to use foreign keys and add parent and just set the foreign key to the related child Id. This way you would not have to bring the entity to the client to create the relationship (you need to know the key of the related entity though).
How are you getting the child? The child should be attached to the same context you save the parent on.
My guess is your GetTheChild function uses a new context - which means when you return the child is detached and for all intents and purposes EF figures its been 'added'
As panel said you can just add a foreign key and just set the child's key instead of the child itself but there seems to be some design issues you should address.
I guess GetTheChild() will return a child from database. So, all you need to do is call ChangeObjectState method to mark the child as Unchanged before calling SaveChanges.
var osm = context.ObjectStateManager;
osm.ChangeObjectState(child, EntityState.Unchanged);
I'm developing an XTEXT 2.0 plugin. I'd like to group some nodes inside my outline in a "virtual" node. Which is the right way to achieve this result?
Currently if i want to group nodes of type "A", in my OutlineTreeProvider I define the following method
protected void _createNode(IOutlineNode parentNode, A node) {
if(this.myContainerNode == null){
A container = S3DFactoryImpl.eINSTANCE.createA();
super._createNode(parentNode, container);
List<IOutlineNode> children = parentNode.getChildren();
this.myContainerNode = children.get(children.size()-1);
}
super._createNode(this.myContainerNode, node);
}
Reading the Xtext 2.0 documentation i saw also that there is a EStructuralFeatureNode. I didn't understand exactly what this type of node is and how to use it. Can you explain what EStructuralFeatureNode is used for?
Many thanks
There are a couple of problems with your code:
this.myContainerNode: There is no guarantee that your provider is a prototype; someone could configure the instance as singleton. Therefore, avoid instance fields.
There are two solutions to this problem:
Search the parent node for your container node whenever you need it (slow but simple)
Add a cache to your instance (see How do I attach some cached information to an Eclipse editor or resource?)
super._createNode(): Don't call the methods with _, always call the plain version (super.createNode()). That method will figure out which overloaded _create* method to call for you. But in your case, you can't call any of these methods because you'd get a loop. Call createEObjectNode() instead.
Lastely, you don't need to create an instance of A (S3DFactoryImpl.eINSTANCE.createA()). Nodes can be backed by model elements but that's optional.
For grouping, I use this class:
public class VirtualOutlineNode extends AbstractOutlineNode {
protected VirtualOutlineNode( IOutlineNode parent, Image image, Object text, boolean isLeaf ) {
super( parent, image, text, isLeaf );
}
}
In your case, the code would look like so:
protected void _createNode(IOutlineNode parentNode, A node) {
VirtualOutlineNode group = findExistingNode();
if( null == group ) {
group = new VirtualOutlineNode( parentNode, null, "Group A", false );
}
// calling super._createNode() or super.createNode() would create a loop
createEObjectNode( group, node );
}
When I have a parent Entity hold a list of other entity (one to many relationship), I modify this list then call function to save the parent Entity. With the entities has removed from this list, is that the framework will delete them from database? And also the new entity has added to the list will be added to database?
thank for your help!
Assuming you have one to many relationship between Parent and Child, i. e., Parent has ChildList and Child has Parent.
Looking at the cases. If Parent is in the entity context and you add an instance of Child to ChildList of Parent, and save the context, then Child will be added to the database.
Parent parent = new Parent() { Name = "parent1" };
provider.AddToParentSet(parent)
parent.ChildList.Add(new Child() { Name = "child1" });
parent.ChildList.Add(new Child() { Name = "child2" });
parent.ChildList.Add(new Child() { Name = "child3" });
provider.SaveChanges();
If you remove one of the Child from the ChildList of Parent, and save the context, then you will get an exception because of the foreign key constraint.
Parent parent = provider.ParentSet.FirstOrDefault();
parent.ChildList.Remove(parent.ChildList.FirstOrDefault());
provider.SaveChanges();
If you delete one of the Childs that belong to ChildList of Parent from the context and save the context, it will be successful, it will be removed from database.
provider.DeleteObject(parent.ChildList.FirstOrDefault());
provider.SaveChanges();
Above situations are valid for default configuration of an entity model. Entity Framework also provides many options, you can also decide how your entity context behaves.
You just need to try these and such situations on your own. It will be better I think.