I am beginner in GWT application development. I have searched about CellTable online. Didn't got any explaination other than some examples.
Now I really want to know what exactly the DataProvider does in CellTable?
Also would like know more about celltable and if there are any resources available for the same??
The dataprovider holds your model.
Whenever you change your model (for instance, a list of object mapped to your cellTable), it will be in charge of updating the display.
It acts as a controller between your display (the cellTable) and the model (i.e. a list of objects, typically a list of shared objects coming from your back-end).
Here is an example with a listdataprovider:
#UiField(provided = true)
protected CellTable<TableRowDataShared> cellTable;
protected ListDataProvider<TableRowDataShared> dataProvider = new ListDataProvider<TableRowDataShared>();
public void init() {
dataProvider.addDataDisplay(cellTable);
// init your cellTable here...
}
public void onModelUpdate(List<TableRowDataShared> newData) {
dataProvider.getList().clear();
dataProvider.getList().addAll(newData);
dataProvider.flush();
dataProvider.refresh();
cellTable.redraw();
}
Related
As suggested in gwt documentation, I try to follow the MVP design pattern while creating my application. When using simple tree, the example in the documentation is straight forwards and makes good example of MVP and gwt. In the example the view is created and the data is given to the view to display. As far as I understand this is exactly the way to keep view, model and presenter separated.
With CellTree, the data populating happens inside the TreeViewModel's data provider. Data provider cannot be taken outside the cell tree and therefore I need to do all data populating inside the cell tree, which is in the view. Now, the view needs to know about the model and the MVP patter is broken. I wan't to dynamically populate data to the cell tree prior to showing it to user, I need to edit the data in cell tree and save it later for different format.
My question goes how to implement CellTree, or in general Cell widgets, in MVP design patter?
I have used CellTable with MVP.
UI:
<g:HTMLPanel>
<g:ScrollPanel>
<p1:CellTable ui:field="cellTable" width="100%" styleName="style.cellTable" height="100%" />
</g:ScrollPanel>
</g:HTMLPanel>
View Interface:
public interface SomeCellListView extends IsWidget {
void setPresenter(Presenter listener);
// Method to set the CellTable data
void setCellList(ArrayList<ObjectDTO> list);
public interface Presenter {
void goTo(Place place);
void doSomething(int id);
}
}
View Implementation:
public class SomeCellListViewImpl extends Composite implements SomeCellListView {
... all Ui Binder stuff here
#UiField(provided = true)
CellTable<ObjectDTO>cellTable = new CellTable<ObjectDTO>();
SomeCellListViewImpl(){
TextColumn<ObjectDTO> someColumn= new TextColumn<ObjectDTO>(){
#Override
public String getValue(ObjectDTO o) {
return o.getSomeFieldValue();
}
};
cellTable.addColumn(someColumn, "column1");
... add other columns here
}
// This method is called from Presenter to set CellTable data
public void setCellList(ArrayList<ObjectDTO> list) {
cellTable.setRowCount(list.size(), true);
cellTable.setRowData(0, list);
}
}
Activity (or Presenter):
// Set view and service in the constructor (Get the view from ClientFactory)
public void start(AcceptsOneWidget containerWidget, EventBus eventBus) {
// Make RPC call
this.service
.getCellList(new AsyncCallback<ArrayList<ObjectDTO>>(){
#Override
public void onFailure(Throwable caught) {
view.setError("Error fetching details");
}
#Override
public void onSuccess(ArArrayList<ObjectDTO> result) {
view.setCelllist(result);
}
});
view.setPresenter(this);
containerWidget.setWidget(view.asWidget());
}
Here, the view is already created by ClientFactory. View contains just the layout for CellTable. Data is not loaded when view is created. When an Activity is started (aka Presenter), the "start" method is invoked. Here we make the RPC to get Cell data and call a method in the view to set the data.
I've not used CellTree. But you asked in general about Cell widgets. Hence thought of sharing this. Hope this helps.
i have the same issue with OP. I read the MVP tutorial part II, and then try to use CellTable in my application, while still keep the MVP architect. But i confuse at the part: the tutorial use the syntax like Presenter, but why you only use Presenter ?
I have a problem which I tried to explained in the Image.I hope that will help all to understand what I need.
My Base Page is like this (menuNavPanel is the tree panel):
<div class="colContainer">
<div class="leftColumn" >
<div wicket:id="menuNavPanel"></div>
</div>
<div class="rightColumn">
<wicket:child/>
</div>
</div>
And Ny BIA Page which is a child of Base Page is like this:
<wicket:extend>
<div wicket:id="bodyPanel"></div>
</wicket:extend>
in my Tree Panel, when I click on a node the code is this:
#Override
protected void onNodeLinkClicked(AjaxRequestTarget target, TreeNode node) {
super.onNodeLinkClicked(target, node);
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)node;
Unit unitObject =(Unit) treeNode.getUserObject();
// I want to call bodyPanel fo child page passing the unitObject param
}
Now, How can I call bodyPanel fo child page passing the unitObject param from the tree panel of the parent page?
Am I been able to express my problem? Hoping to get some help :)
Instead of doing the override method, upgrade to Wicket 1.5 and utilize the new event bus to communicate between your components. You can create a custom, type-safe, event that is specific to your component's use case: for example "ItemAddedToShoppingCart" or "GlobalThermoNuclearWarStarted".
The linked article in the 1.5 migration guide provides enough information on how to set up things.
I'm not sure I understand que question correctly. Your BasePage defines a left column with the TreePanel and lets subclasses expand themselves inside the right column div. You usually put a BodyPanel inside BasePages's subclasses. And now you want to invoke a BodyPanel's method on some event on the TreePanel.
You could do it with an overridable method on BasePage, which would be called in TreePanel through getPage(). Your child pages would override that method, and its implementation would call the BodyPanel they're holding.
public class BasePage ... {
// Hook
public void treePanelSelected(Object someObject) { }
...
}
public class ChildPage extends BasePage ... {
BodyPanel bodyPanel;
#Override
public void treePanelSelected(Object someObject) {
bodyPanel.selectionChanged/(someObject);
}
...
}
public class TreePanel ... {
...
#Override
protected void onNodeLinkClicked(AjaxRequestTarget target, TreeNode node) {
super.onNodeLinkClicked(target, node);
DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)node;
Unit unitObject =(Unit) treeNode.getUserObject();
((BasePage)getPage()).treePanelSelected(unitObject);
}
}
From my ignorance on your specific needs and details of implementation, I don't see why is subclassing the BasePage necessary. You could add the BodyPanel right there in the BasePage and control it from the same class.
Thanks all, After reviewing all the nice options I finally opted out for the event bus way defined by martijn. What I did is I have created an event payload and connected the panels for the talking. I also needed to pass the selected Id / entity to the receiving panel.
Is there a way to set a compound property model of the receiving panel according to the model of the tree element so that I don't need to do the model manually ?
I did like this for the time being:
public class TreeNodeClickUpdate {
private final AjaxRequestTarget target;
private final long selectedId;
/**
* Constructor
*
* #param target
* #param selectedId
*/
public TreeNodeClickUpdate(AjaxRequestTarget target, long selectedId)
{
this.target = target;
this.selectedId = selectedId;
}
/** #return ajax request target */
public AjaxRequestTarget getTarget()
{
return target;
}
public long getSelectedId() {
return selectedId;
}
}
On the sender side I've done like this:
send(getPage(), Broadcast.BREADTH,
new TreeNodeClickUpdate(target, unitObject.getId()));
And on the receiving end I got it like this:
#Override
public void onEvent(IEvent<?> event) {
super.onEvent(event);
if (event.getPayload() instanceof TreeNodeClickUpdate)
{
TreeNodeClickUpdate update = (TreeNodeClickUpdate)event.getPayload();
setSelectedId(update.getSelectedId()); //sets to id field of panel
update.getTarget().add(this);
}
}
and for just as an example in my receiving panel, to get the value I have created a label like this:
label = new Label("label",new PropertyModel<BiaHomePanel>(this,"selectedId"));
Later, in reality I want to get information from the entity and show in form. Is there a nice way to pass models in a better way or I should pass as a parameter in event payload.
There are two ways to do this. One is cleaner, but requires more code. The other is quick and dirty.
Method 1: (Good)
Since your parent page is being extended, you can provide an abstract method in the parent like
protected abstract WebMarkupContainer getBodyPanel();
that is implemented in your child page and returns the appropriate panel. Then, you can call that method from the panel in your parent page. This is similar to the overrideable method suggested by the other user.
Method 2: (Bad)
The Wicket Component Hierarchy is shared between the parent and child pages. So, if you make sure that your bodyPanel has a unique wicketId and is added directly to the root of the page, you can probably just call
get("bodyPanelId");
and it will return the proper panel.
When I was facing the problem, I thought of two ways to solve this (pre 1.5):
a) implement a variation of the observer pattern to notify other component of events like outlined here: Realising complex cross-component ajax actions in wicket - The observer way
b) using wicket visitors to traverse the component tree doing the same.
I decided to go for variant a) but this introduces coupling from your component to your page-implementation which leads to problems when testing panels on their own. So maybe b) might be the better idea but since my application is running quite smoothly with a) implemented and the next big step will be switching over to 1.5 and the event bus, I haven't yet tried b).
In MVP pattern the widget (the view) exposes its widgets in form like this:
#Override
public HasClickHandlers getAddIssueClickHandlers() {
return addIssueButton;
}
and like:
#Override
public HasText getTaskName() {
return taskName; // taskName is a Label
}
To allow the presenter to modify the view or get the values from a widget. However, its uncertain how to get a table widget, like FlexTable or CellTable in order for the presenter to modify the table. Any ideas is much appreciated. Thanks.
Not all GWT widgets were designed with these interfaces (i.e. HasclickHandlers, HasText, IsWidget, etc) in mind.
In recent GWT versions the basic widgets were changed so that they implement these interfaces in order to make the views which use them testable in unit tests. So I am not sure if the FlexTable implements these interfaces but in case of CellTable you can use the HasData interface.
Here you can find the interfaces that are implemented by the CellTable: Javadoc
I personally would expose the CellTable via the HasData interface, which can be used to set and retrieve the selectionModel (for selecting rows in the CellTable).
For modifying or updating the data that is displayed in the CellTable, I would use a ListDataProvider and store it in the Presenter.
#Override
public HasData getCellTableDisplay() {
return cellTable;
}
and in the constructor of the presenter
you can create a ListDataProvider and use the addDataDisplay function to add the CellTable:
final ListDataProvider<String> dataProvider = new ListDataProvider<String>();
dataProvider.addDataDisplay(getView().getCellTableDisplay);
I'm working on learning GWT (total newb) and have a question regarding the Visualiztion API provided by Google. This page:
http://code.google.com/p/gwt-google-apis/wiki/VisualizationGettingStarted
Describes getting started with a pie chart (which is what I need). However I'm trying to do this in a composite UI using UiBinder. To that end I don't know how to handle the callback correctly that is shown:
public class SimpleViz implements EntryPoint {
public void onModuleLoad() {
// Create a callback to be called when the visualization API
// has been loaded.
Runnable onLoadCallback = new Runnable() {
public void run() {
Panel panel = RootPanel.get();
// Create a pie chart visualization.
PieChart pie = new PieChart(createTable(), createOptions());
pie.addSelectHandler(createSelectHandler(pie));
panel.add(pie);
}
};
// Load the visualization api, passing the onLoadCallback to be called
// when loading is done.
VisualizationUtils.loadVisualizationApi(onLoadCallback, PieChart.PACKAGE);
}
My First assumption is this would go in the UiBinder constructor, correct? Yet this assumes that I want to place the element in the RootLayoutPanel, and I don't. I can't see an elegant and obvious way of placing it in the binder. I submit that even this guess may be wrong. Any ideas from the experts?
EDIT:
I should make clear my attempt:
public GraphPanel() {
initWidget(uiBinder.createAndBindUi(this));
Runnable onLoadCallback = new Runnable() {
public void run() {
//LayoutPanel panel = RootPanel.
// Create a pie chart visualization.
PieChart pie = new PieChart(createPieTable(), createPieOptions());
pie.addSelectHandler(createSelectHandler(pie));
mySelf.getElement().appendChild(pie.getElement()); // .add(pie);
}
};
// Load the visualization api, passing the onLoadCallback to be called
// when loading is done.
VisualizationUtils.loadVisualizationApi(onLoadCallback, PieChart.PACKAGE);
}
When run I get the following in the Composites DIV:
<div class="gwt-viz-container"></div>
But I see no graph using the code from the above page.
EDIT 2:
This link may provide additional information. However, the solution suggested is not optimal since the app then needs to know more about the widget (and if the widget is even there).
http://vaadin.com/forum/-/message_boards/message/97850
EDIT 3:
It shouldn't matter, but just in case, I'm running FF on Linux. Some articles I've read have implied that this is a problem.
EDIT 4:
Adding:
pie.draw(createPieTable(), createPieOptions());
after the append child gets the graph to display. This implies that the ordering of the example is wrong. If so what is the optimum?
It is also important to know that although the GWT JRE Emulation library supports the Runnable interface, it can't really be used for parallel processing in a separate thread, as the code is compiled into JavaScript which in turn runs single-threaded in the browser. Same goes for the synchronized keyword.
I also would recommend doing all preparation logic in the Widget/Composite's constructor but any actual drawing in the onLoad callback, which you need to override. This callback is called when the widget is loaded in the browser document, it is only then that you can perform any page/layout interaction, like enabling/disabling controls or requesting focus.
Either way you suggest would work. If the Visualization API is used by a bunch of different widgets on the page, then it might be simpler to put the loadVisualizationApi call in the EntryPoint class - an example of this is below.
You can write the Composite like so:
public MyPieChartContainer extends Composite {
interface MyUiBinder extends UiBinder<Widget, MyPieChartContainer>;
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
#UiField Panel panel;
public MyPieChartContainer() {
initWidget(uiBinder.createAndBindUi(this));
PieChart pie = new PieChart(createTable(), createOptions());
pie.addSelectHandler(createSelectHandler(pie));
panel.add(pie);
}
}
And then do this in the EntryPoint:
public class SimpleViz implements EntryPoint {
public void onModuleLoad() {
// Create a callback to be called when the visualization API
// has been loaded.
Runnable onLoadCallback = new Runnable() {
public void run() {
Panel panel = RootPanel.get();
MyPieChartContainer myPieChartContainer = new MyPieChartContainer();
panel.add(myPieChartContainer);
}
};
// Load the visualization api, passing the onLoadCallback to be called
// when loading is done.
VisualizationUtils.loadVisualizationApi(onLoadCallback, PieChart.PACKAGE);
}
I have to bind my editor widget objects in property sheet.So that i can the property of my widget from property view.
Please help me on this, if possible provide me some code snippets.
You have a good example in the Getting started with Properties
Using the Properties view is simple enough.
Since it shows properties for the selected object, the first step to using it is to make sure that the workbench selection service knows about the object selected in your view. There’s an entire Eclipse Corner article written on the subject of the selection service
public void createPartControl(Composite parent) {
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
getSite().setSelectionProvider(viewer);
viewer.setInput(getViewSite());
}
Once you have your view contributing to the workbench selection, you need to make sure that the objects that your view is selecting contribute properties
(extract)
public class Person implements IPropertySource {
private String name;
private Object street;
private Object city;
public Person(String name) {
this.name = name;
this.street = "";
this.city = "";
}
public Object getEditableValue() {
return this;
}
public IPropertyDescriptor[] getPropertyDescriptors() {
return new IPropertyDescriptor[] {
new TextPropertyDescriptor("name", "Name"),
new TextPropertyDescriptor("street", "Street"),
new TextPropertyDescriptor("city", "City")
};
}
I indicated earlier that this solution is “not necessarily [the] most correct”. This is because, for this to work, my domain object needs to know about the very view-centric (and Eclipse-centric) notion of being a property source; in short, there is a tight-coupling between the model and view and this not a good thing™.
Using adapter is a better approach, as described in this article:
Person should implement IAdaptable.
See also this recent article on how to create a custom property view
how to hack the Properties View to listen only to a specific view.
The isImportant() method is the one which decides whether to create an IPage for the specific IWorkbenchPart or not.
The idea is to override that method and return false for all the workbenchPart that we are not interested in. Lets create the view first:
<view
class="com.eclipse_tips.views.CustomPropertiesView"
icon="icons/sample.gif"
id="com.eclipse-tips.views.customePropertiesView"
name="My Properties View">
</view>
The CustomPropertiesView should extend PropertySheet and override the isImportant():
public class CustomPropertiesView extends PropertySheet {
#Override
protected boolean isImportant(IWorkbenchPart part) {
if (part.getSite().getId().equals(IPageLayout.ID_PROJECT_EXPLORER))
return true;
return false;
}
}
In this case, I'm making the view only to respond to Project Explorer and ignore other views
According to this thread, the same principle should be valid for an Editor instead of a View.
The property sheet listens to the workbench page selection provider.
The selection provider depends on what viewer/editor is active.
Each editor/viewer provides their own selection provider to use when that editor/viewer is active.
This way the property sheet doesn't care who is active, it just listens to the selection provider.
That way depending upon the view, a different set of properties are displayed.
For example, the Navigator view provides IResource selections, so the property sheet then displays IResource properties when the Navigator is active.
The Workbench Selection mechanism is illustrated in this article
The ISelectionListener is a simple interface with just one method.
A typical implementation looks like this:
private ISelectionListener mylistener = new ISelectionListener() {
public void selectionChanged(IWorkbenchPart sourcepart, ISelection selection) {
if (sourcepart != MyView.this && // 1
selection instanceof IStructuredSelection) { // 2
doSomething(((IStructuredSelection) selection).toList()); // 3
}
}
};
Depending on your requirements your listener implementation probably needs to deal with the following issues as shown in the code snippet above:
In case we also provide selections (e.g. a view or editor) we should exclude our own selection events from processing. This avoids unexpected results when the user selects elements within our part (1).
Check whether we can handle this kind of selection (2).
Get the selected content from the selection and process it (3).