I'm trying to use the GWT CellTree to display a heterogeneous, hierarchical data model. I need to be able to a single selection, but be able to select Parent nodes as well as child nodes. For example, if you look at GWT's own example, you'll see that they only provide one selection model for the leave nodes.
I tried to extend their example by providing one selection model for all nodes. However, that seems impossible. So what I ended up with where 3 SelectionModels one for each node type (Composer, PlayList, Song).
What am I missing?
Thanks in advance.
In the getNodeInfo function of your TreeViewModel you have to pass the selectionModel to each new DefaultNodeInfo instance at each level.
return new DefaultNodeInfo<MyDTO>(dataProvider,new MyDTOCell(),selectionModel,null);
and then in the SelectionChangeEventHandler you have do something like this:
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
Object object = selectionModel.getSelectedObject();
if (object instanceof MyRootDTO)
{
// DO SOMETHING with root level selected node
}
else if (object instanceof MySecondLevelDTO) {
// DO SOMETHING WITH 2. level selected node
}
// additional levels
});
Update:
In order to get around the typing problem, you can define an abstract base class which is extended by all your DTO's.
public abstract class BaseModel {
public static final ProvidesKey<BaseModel> KEY_PROVIDER = new ProvidesKey<BaseModel>() {
public Object getKey(BaseModel item) {
return item == null ? null : item.getId();
}
};
public abstract Object getId();
}
In your DTO's you extend the BaseModel and implement the abstract getId() method:
public class MyDTO extends BaseModel {
#Override
public Object getId() {
//return unique ID (i.e. MyDTO_1)
}
}
Related
In my application, I have a service that requires a constructor parameter not resolved by Autofac, that I instantiate using a delegate factory:
public class Service
{
public Service(string parameter /*, ... other dependencies */)
{
}
public delegate Service Factory(string parameter);
}
This works great! I really love this feature.
I also like the Controlled Lifetime relationship, so I can let my component depend on a Func<Owned<ISomething>> like this:
public class Component
{
private Func<Owned<ISomething>> _somethingFactory;
/* constructor omitted for brevity */
public void DoSomethingUseful()
{
using (var ownedSomething = _somethingFactory())
{
/* Lots of useful code here */
}
}
}
My problem is that now I want to combine the two. I can't have an instance of Func<Owned<Service>> injected, because it needs that parameter, so my current solution is to abstract the factory away into another service, say IServiceFactory:
public interface IServiceFactory
{
Service Create(string parameter);
}
...implemented as such:
public class ServiceFactory : IServiceFactory
{
private Service.Factory _internalFactory;
public ServiceFactory(Service.Factory internalFactory)
{
_internalFactory = internalFactory;
}
public Service Create(string parameter)
{
return _internalFactory(parameter);
}
}
My component then becomes this:
public class Component
{
Func<Owned<IServiceFactory>> _serviceFactoryFactory;
/* ... */
}
The need for such a field name leaves a bad taste in my mouth to the point that I suspect there must be a cleaner way to handle this case.
Is there another way?
You could change your injected factory to include the string parameter:
private Func<string, Owned<ISomething>> _somethingFactory;
Then you can pass the string to the factory when you want to create a new instance:
public void DoSomethingUseful()
{
using (var ownedSomething = _somethingFactory("my parameter"))
{
/* Lots of useful code here */
}
}
I've created a .NET Fiddle with a small working sample.
Firstly, is doing such thing a good practice ?
I tried what seems to be the right way for me but wasn't successful :
public class FormViewImpl extends CompositeView implements HasUiHandlers<C>, FormView {
public interface SettlementInstructionsSearchFormViewUiBinder extends UiBinder<Widget, SettlementInstructionsSearchFormViewImpl> {}
#Inject
static FormViewImpl uiBinder;
#Inject
static Provider<DateEditorWidget> dateEditorProvider;
#UiField(provided = true)
MyComponent<String> myComp;
#UiField
DateEditorWidget effectiveDateFrom;
// .. other fields
#Inject
public FormViewImpl () {
myComp = new MyComponent<String>("lol");
if (uiBinder == null)
uiBinder = GWT.create(SettlementInstructionsSearchFormViewUiBinder.class);
initWidget(uiBinder.createAndBindUi(this));
}
#UiFactory
DateEditorWidget createDateEditor() {
return dateEditorProvider.get();
}
}
What other things than a class with no arguments is required ? In my company's project the same kind of code works at some other place. Sorry from the high level of noob here...
If you guys had any pointers it would be nice.
Thanks
Two issues:
First, two of your #Inject fields are static - have you done anything to make static fields be injected? Static fields don't get set when Gin (or Guice) creates new instances, those have to be set once and done. As they are static, they will never be garbage collected - this may be okay with you, or it might be a problem, and you should change them to instance fields. If you want to keep them static, then you must invoke requestStaticInjection in your module to ask Gin to initialize them when the ginjector is created.
Next, if you do choose to remove static, the uiBinder field must still be null in that constructor, because the fields can't have been injected yet! How do you set a field on an object that you haven't yet created? That's what you are expecting Gin to be able to do. Instead, consider passing that as an argument into the #Inject decorated constructor. You don't even need to save it as a field, since the widget will only use it the one time.
To have a class generated by GIN (doesn't matter if it is a uiBinder or not) it is not necessary for it to have a default constructor (i.e. the one without parameters). The class you want to inject must have the constructor annotated with #Inject:
#Inject
public InjectMeClass(Object a, Object b)
The other class which is injected, suppose it is a UiBinder, must have the injected fields annotated with #UiField(provided=true):
public class Injected extends Composite {
private static InjectedUiBinder uiBinder = GWT
.create(InjectedUiBinder.class);
interface InjectedUiBinder extends UiBinder<Widget, Injected> {
}
#UiField(provided=true)
InjectMeClass imc;
public Injected(final InjectMeClass imc) {
this.imc=imc;
initWidget(uiBinder.createAndBindUi(this));
}
So, back to your case:
#UiField(provided = true)
MyComponent<String> myComp;
#Inject
public FormViewImpl (MyComponent<String> myComp) {
this.myComp = myComp;
and for example:
public class MyComponent<T> extends Composite {
private T value;
#Inject
public MyComponent(T t) {
this.value = t;
...
}
...
}
In the GIN module you can have a provider:
#Provides
#Singleton
public MyComponent<String> createMyComponent() {
return new MyComponent<String>("lol");
}
I want to bind my services to ListBox but I can't bind it.
//Service class
public class Service {
private String serviceName;
public Service(String serviceName) {
this.serviceName = serviceName;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
}
// SignUpBean class
public class SignUpBean {
private List<Service> services;
public List<Service> getServices() {
return services;
}
public void setServices(List<Service> services) {
this.services = services;
}
}
The following is my Main Editor
public class SignUpEditor extends SimplePanelimplements Editor<SignUpBean> {
public ListBox services;
public void SignUpEditor (){
services.addItem("Service1");
services.addItem("Service2");
setWidget(services);
}
}
I am not getting any error but I think I have to use ListEditor or CompositeEditor. But i don't know about it. Can anyone suggest how to bind Service to ListBox
ListBox suppose to be a LeafValueEditor. Conceptually we don't edit the list in the ListBox. Rather We select a value from the list which will be displayed in the selection. So, ListBox holds only one value and thus ListBox must be leaf value Editor.
Currently there is no GWT support to directly bind the list to ListBox. We have to write an adapter which extends ListEditor ( Refer HasDataEditor class for more detail ). This approach is strange.
Simple approach is to write an adapter which implements LeafValueEditor< List < String > >. In adapter's setValue method we should iterate over the list and call listBox.addItem for each value in the list.
I don't recommend either approaches simply because ListBox's LIST is NON EDITABLE and only VALUE is EDITABLE. I recommend doing addItems manually without using Editors.
UPDATED : HasDataAdapter is an example ListEditor. Refer that implementation. You may get some idea.
I have a model class, it contains a java.util.Properties.
public class Model{
private Properties properties;
}
This properties can contains arbitrary key-value pairs. Now I want to bind "properties" to a JFace TableViewer. How to do this?
Some example code will be good, I have googled for this, but found nothing useful.
To access your model from a TableViewer you have to provide a LabelProvider and a ContentProvider as a translation to the TableViewer and of course provide the model itself.
In short the ContentProvider wraps your models content to the structure of the TableViewer (basically a breakdown of your model to the line by line approach of the TableViewer).
The LabelProvider lets you control the actual rendering in the TableCells.
To provide your model the TableViewer supplies a setInput method.
This works best however when your model is modeled as a JavaBean.
If you look at the snippets you will find something like this in your implementation of the ContentProvider like here:
public Object[] getElements(Object inputElement) {
return (MyModel[]) inputElement;
}
So, if your model as I understand right now, is just a wrapper around your properties, one way to achieve your goal would be to introduce the notion of a PropertyLine that gets populated either by startup, or dynamically via JFace Databinding (that might be a different topic).
public class Model{
...
private PropertyLine[] propertyLineArray;
private PropertyLine[] initializeProperties(){
//initialize your PropertyLines
}
public Model(){
...
propertyLineArray=initializeProperties();
...
}
public PropertyLine[] getPropertyLines(){
return propertyLineArray;
}
}
public class ProperyLine{
...
private String propertyKey;
private String propertyText;
//getter, setter
...
}
Your ContentProvider would look something like this:
private class PropertyContentProvider implements IStructuredContentProvider {
...
public Object[] getElements(Object inputElement) {
return (PropertyLine[]) inputElement;
}
...
}
Your LabelProvider seems quite straightforward then:
public class PropertyLabelProvider extends LabelProvider implements
ITableLabelProvider {
...
public String getColumnText(Object element, int columnIndex) {
PropertyLine pl=(PropertyLine) element
return pl.getPropertyText();
}
...
}
You wire everything up somewhere by:
final TableViewer v = new TableViewer(shell, SWT.BORDER
| SWT.FULL_SELECTION);
v.setLabelProvider(new PropertyLabelProvider());
v.setContentProvider(new PropertyContentProvider ());
v.setInput(myModel.getPropertyLines());
I want to know if it's possible to use the same content and label providers for Tree and Table in Eclipse views or they must have separate content and label providers. I am trying to use the content and label providers i wrote for the tree for the table as well but i see nothing on the table view.
Thanks.
You CAN use the same Label provider.
You CAN'T use the same content provider since the tree content provider must implement ITreeContentProvider which is not "compatible" with the IStructuredContentProvider interface that must be implemented by table content provider.
By not "compatible" I mean that the implementation of IStructuredContentProvider.getElements(Object inputElement) method in TreeContentProvider must return only the "roots" objects whereas it must return all the objects for a list content provider.
You can share the providers. Your ContentProvider will have to implement both IStructuredContentProvider and ITreeContentProvider. I guess that normally you will want to have separate content providers.
In the example the Tree will show only one level with the elements (all elements are roots). The Table will show only one row.
Example:
//ContentProvider for Tree and Table
public static class CommonContentProvider extends ArrayContentProvider
implements ITreeContentProvider {
#Override
public Object[] getChildren(final Object arg0) {
return null;
}
#Override
public Object getParent(final Object arg0) {
return null;
}
#Override
public boolean hasChildren(final Object arg0) {
return false;
}
}
public static void testCommonProviderTreeTable(final Composite c) {
final Collection<String> input = Arrays.asList(new String[] { "hi",
"hola" });
final IContentProvider contentProvider = new CommonContentProvider();
final IBaseLabelProvider labelProvider = new LabelProvider() {
#Override
public String getText(final Object element) {
return element.toString();
}
};
final TreeViewer tree = new TreeViewer(c, SWT.NONE);
tree.setContentProvider(contentProvider);
tree.setLabelProvider(labelProvider);
tree.setInput(input);
final TableViewer table = new TableViewer(c, SWT.NONE);
table.setContentProvider(contentProvider);
table.setLabelProvider(labelProvider);
table.setInput(input);
}