What i would like to do, is create TreeViewer using databinding for a POJO class, which has multiple list properties, and all of them needs to be observed, and displayed in the viewer.
I would like to display a tree like:
Person
\
|- Dog // dogs list
|- Dog
|- Cat // cats list
|- Cat
|- Cat
Example:
public class Cat {
// ...
}
public class Dog {
// ...
}
The class which has a list reference with both types:
public class Person {
private List<Dog> dogs = Lists.newArrayList();
private List<Cat> cats = Lists.newArrayList();
// getters and setters which fire property change listeners.
}
And then i create the TreeViewer, and set the content provider:
treeViewer = new TreeViewer(parent);
IObservableFactory observableFactory = new IObservableFactory() {
public IObservable createObservable(final Object target) {
// target is a Person. What should I return here?
// If I return for example the observed dogs, cats wont be bound:
return BeanProperties.list("dogs").observe(target);
}
};
IContentProvider provider = new ObservableListTreeContentProvider(observableFactory, null);
treeViewer.setContentProvider(provider);
But because the factory can only return one IObservable, I can't observe both cats and dogs. How could i do that?
With your initial design, you can't do it. Why are dogs and cats on the same level in the tree? Levels usually contain same objects (because why would you put your cousins under your parents?).
OK, cats and dogs are both Animals, but then make them extending Animal class and use something like this:
class Person {
List<Animal> pets; // both dog and cats
}
IObservableFactory observableFactory = new IObservableFactory() {
public IObservable createObservable(final Object target) {
return BeanProperties.list("pets").observe(target);
}
};
And even this would not be a good idea, in case you want to display properties which are only related to cats, dogs, rabbits... .
I am not sure, why you want to use observable content provider (as usually Tree is convenient way to just display something). Wouldn't it be enough for you to use ITreeContentProvider? In this case you could stick with you model of having separate dogs and cats collections and do something like this:
class PetsContentProvider immplements ITreeContentProvider {
public boolean hasChildren(Object element) {
if (element instanceof Person) {
Person person = (Person) element;
return person.getCats().size > 0 || person.getDogs().size() > 0;
}
return false;
}
public Object getParent(Object element) {
// TODO: still better to have a common class
if((element instanceof Dog) || (element instanceof Cat)) {
// cast to dog or cat (or better animal)
// Animal pet = (Animal) element;
return pet.getOwner();
}
return null;
}
public Object[] getChildren(Object parentElement) {
if(parentElement instanceof Person) {
Person person = (Person) parentElement;
return person.getCats().toArray(); // and dogs
}
return EMPTY_ARRAY;
}
}
For more information, please see this very good article on JFace Trees.
And just traditionally Vogella's article on JFaceData Binding.
Related
I want to create a custom sling model which can be adapted from com.adobe.cq.dam.cfm.ContentFragment
like below,
import com.adobe.cq.dam.cfm.ContentFragment;
#Model(adaptables = ContentFragment.class, adapters = EventInfo.class)
public class EventInfoImpl implements EventInfo{
#Self
ContentFragment cf;
#Override
public String getTitle(){
return cf.getElement("title").getContent();
}
}
but in a caller class,
EventInfo e = contentFragment.adaptTo(EventInfo.class);
adaptTo() returns null.(variable "e" is null)
Why adaptTo() returns null? and How do I adapt correctly in this case?
Sling models can only be adapted from Resource or SlingHttpServletRequest. For anything else you need a classic AdapterFactory.
https://sling.apache.org/apidocs/sling11/org/apache/sling/api/adapter/AdapterFactory.html
How to implement a custom AdapterFactory for Sling Resource?
You can see it in the Sling source code of the ModelAdapterFactory. There is the method createModel:
<ModelType> ModelType createModel(#NotNull Object adaptable, #NotNull Class<ModelType> type)
https://github.com/apache/sling-org-apache-sling-models-impl/blob/master/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
If you dig down, the real filtering happens in the helper-class AdapterImplementations (line 258-268)
https://github.com/apache/sling-org-apache-sling-models-impl/blob/master/src/main/java/org/apache/sling/models/impl/AdapterImplementations.java
if (adaptableType == Resource.class) {
map = resourceTypeMappingsForResources;
resourceTypeRemovalLists = resourceTypeRemovalListsForResources;
} else if (adaptableType == SlingHttpServletRequest.class) {
map = resourceTypeMappingsForRequests;
resourceTypeRemovalLists = resourceTypeRemovalListsForRequests;
} else {
log.warn("Found model class {} with resource type {} for adaptable {}. Unsupported type for resourceType binding.",
new Object[] { clazz, resourceType, adaptableType });
return;
}
Let's say I have these two subclasses (psuedo code):
Male.class:
include Person.class;
class Male extends Person {
...
}
Female.class:
include Person.class;
class Female extends Person {
...
}
And finally I have this base class:
Person.class:
class Person {
static function makePersonBySettings(settings) {
var person;
if(settings.gender == 'male') {
person = new Male(settings.name);
}
else if(settings.gender == 'female') {
person = new Female(settings.name);
}
return person;
}
}
Parent's static method depends on knowing what Male.class and Female.class are. I can't do importing of subclasses (e.g., import Male.class) at the top of Parent.class because the subclass depends on knowing the parent.
What's the best way to resolve this issue?
You could decouple the factory method (makePersonBySettings) from your parent class by creating a dedicated class to contain factory methods.
class Person {
static function makePersonBySettings(settings) {
var person;
person = new self(settings.name);
return person;
}
}
self will reference your child object.
Male::makePersonBySettings(settings) will return a Male object.
This question is about Dart language.
I want to have a class which is just a List but with some extra functionality.
For example I have a class named Model:
class Model{
String name;
int type;
Model(this.name, this.type);
}
I know that Model's type could take only four values: from 0 to 3.
And I want to have a method, which can give me a List of Models of specified type, e.g. List<Model> modelCollection.getByType(int type);.
I plan to to have four 'hidden' Lists of the Models (grouped by type) in that class.
Thus I need to override addition and removal of List elements to make that hidden lists being up to date.
How can I realize this as easy as possible?
P.S. I know this is quite simple, but I'm poorly familiar with Object inheritance and can't find proper examples.
P.P.S. I've also checked this but don't know is it outdated or not and didn't catch the idea.
To make a class implement List there are several ways :
Extending ListBase and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends ListBase<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Mixin ListMixin and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends Base with ListMixin<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Delegating to an other List with DelegatingList from the quiver package:
import 'package:quiver/collection.dart';
class MyCustomList<E> extends DelegatingList<E> {
final List<E> _l = [];
List<E> get delegate => _l;
// your custom methods
}
Depending on your code each of those options have their advantages. If you wrap/delegate an existing list you should use the last option. Otherwise use one of the two first options depending on your type hierarchy (mixin allowing to extend an other Object).
A basic approach is to extend an Object with IterableMixin. It also seems that you don't even need to override the "length" getter or let's say all methods that the IterableMixin already provides.
import 'dart:collection';
class Model {
String name;
int type;
Model(this.name, this.type) {
}
}
class ModelCollection extends Object with IterableMixin {
List<Model> _models;
Iterator get iterator => _models.iterator;
ModelCollection() {
this._models = new List<Model>();
}
//get one or the first type
Model elementByType(int type) {
for (Model model in _models) {
if (model.type == type) {
return model;
}
}
}
//get all of the same type
List<Model> elementsByType(int type) {
List<Model> newModel = new List<Model>();
for (Model model in _models) {
if (model.type == type) {
newModel.add(model);
}
}
return newModel;
}
add(Model model) {
this._models.add(model);
}
}
Excuse my strong static typing.
You might be interested in quiver.dart's Multimap. It behaves like a Map that allows multiple values per key.
Here's the code on github: https://github.com/google/quiver-dart/blob/master/lib/src/collection/multimap.dart#L20
It's on pub simply as quiver. We'll be hosting the dartdocs somewhere soon.
Say I have a class Person that has an "IsArchived" property. A Person can have a Collection - each of which can also be Archived.
Right now I have an UpdatePerson method in my repository that looks like this:
public Person UpdatePerson(Person person)
{
_db.Persons.Attach(person);
var entry = _db.Entry(person);
entry.Property(e => e.Name).IsModified = true;
entry.Property(e => e.Friends).IsModified = true;
SaveChanges();
return entry.Entity;
}
And I have a separate Repository method for Archive:
public void ArchivePerson(int personId)
{
var person = _db.Persons.FirstOrDefault(c => c.PersonId == personId);
if (person != null)
{
person.IsArchived = true;
foreach (var friend in person.Friends)
{
ArchivePerson(friend.PersonId);
}
SaveChanges();
}
}
This means that from my WebAPI, I have to dedicate a function to Archiving/Unarchiving. It would be cool if I could just call Update and set the Archived for the given entity, and apply this to all child entities where possible. Is there any way to accomplish this, or am I best off sticking to the ArchivePerson repository method?
I have a method which i'd like to refactor
Basically i want to split the top level method in a abstract and a final part.
The method in question is overridden in quite a few places where additional functionality is added, but eventualy the super call is always made.
The code now basically look like:
(not all Extending classes override but those that do, do it this way)
class Base {
public Object getStuff(String key) {
out = //code to get data from the Database.
return out
}
class Extended1 extends Base {
public Object getStuff(String key) {
if("some_non_db_value".equals(key)) {
return "some custom stuff";
}
return super.getStuff(key);
}
}
What i'd like as a result would be something like:
class Base {
public final Object getStuff(String key) {
out = getCustom(key);
if(out != null) {
return custom;
}
out = //code to get data from the Database.
return out
}
public abstract Object getCustom(String key);
}
class Extended1 extends Base {
public Object getCustom(String key) {
if("some_non_db_value".equals(key)) {
return "some custom stuff";
}
return null;
}
}
I was hoping there would be a refactor action (or partial refactor) to get to (or closer to) this point.
I would first rename getStuff() to getCustom() which would take care of all the extended classes. Then changing the Base class should be relatively easy.