GWT CEll Browser Real Time Update - gwt

has someone been able to correctly to update a cell browser at runtime, i.e. when u remove a node or add a node, the change is reflected immediately in the CEll Browser, because I am using a List and when i am making a change it is not being updated on the spot

You can use ListDataProvider setList(...) method for dynamic updates. Here is an example how I update cell browser via RPC:
private void loadAllData(final ListDataProvider<Data> dataProvider) {
dBservice.getAllData(new AsyncCallback<List<Data>>() {
public void onSuccess(List<Data> result) {
dataProvider.setList(result);
}
public void onFailure(Throwable caught) {
caught.printStackTrace();
}
});
}

to refresh a cellBrowser you have to close all the child on the root node.
anyway something like this
for (int i = 0; i < cellBrowser.getRootTreeNode().getChildCount(); i++) {
cellBrowser.getRootTreeNode().setChildOpen(i, false);
}
the AsyncDataProvider calls refreshes data
private final class Model implements TreeViewModel{
private List<ZonaProxy> zonaList = null;
private List<CategoriaProxy> categoriaList = null;
public void setCategoriaList(List<CategoriaProxy> categoriaList) {
this.categoriaList = categoriaList;
}
public void setListZona(List<ZonaProxy> zonaList) {
this.zonaList = zonaList;
}
#SuppressWarnings({ "unchecked", "rawtypes" })
public <T> NodeInfo<?> getNodeInfo(T value) {
CategoryDataProvider dataProvider1 = new CategoryDataProvider();
return new DefaultNodeInfo(dataProvider1, new CategoriaCell());
}
/**
* Check if the specified value represents a leaf node. Leaf nodes cannot be
* opened.
*/
public boolean isLeaf(Object value) {
if (value instanceof CategoriaProxy){
if (((CategoriaProxy) value).getLivello() == 3) {
return true;
}
}
return false;
}
}
private class CategoryDataProvider extends AsyncDataProvider<CategoriaProxy>
{
#Override
protected void onRangeChanged(HasData<CategoriaProxy> display)
{
requests.categoriaRequest().findAllCategorias(0, 8).with().fire(new Receiver<List<CategoriaProxy>>() {
#Override
public void onSuccess(List<CategoriaProxy> values) {
updateRowCount(values.size(), true);
updateRowData(0, values);
}
});
}
}
it Works.

Apparently it is not enough to change the data provider and refresh it.
You need also to force the affected cell to close and reopen it, as in this example
public void updateCellBrowser(String id) {
TreeNode node = getNode(cellBrowser.getRootTreeNode(),id);
if(node != null && ! node.isDestroyed()) {
TreeNode parent = node.getParent();
int index = node.getIndex();
parent.setChildOpen(index, false,true);
parent.setChildOpen(index, true, true);
}
}
In my particular example the cell ids are pathnames hence the following
implementation of getNode().
private TreeNode getNode(TreeNode node, String id) {
for(int i=0; i < node.getChildCount(); i++)
if(node.isChildOpen(i)) {
Object value = node.getChildValue(i);
if(value instanceof String) {
String nodeId = ((String) value);
if(id.equals(nodeId))
return node.setChildOpen(i, true);
if(id.startsWith(nodeId))
getNode(node.setChildOpen(i, true),id);
}
}
return null;
}

Related

Update ListView via AsyncTask or IntentService

I am trying to Update my Custom ListView which is fed by two String Arrays:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getStringArray(ARG_PARAM1);
mParam2 = getArguments().getStringArray(ARG_PARAM2);
}
setupListView();
}
private void setupListView() {
listItemList = new ArrayList();
if (mParam1 != null && mParam2 != null && mParam1.length == mParam2.length) {
for (int i = 0; i < mParam1.length; i++) {
listItemList.add(new MyListItem(mParam1[i], (mParam2[i]).substring(0, 75) + "..."));
}
} else {
listItemList.add(new MyListItem("Loading...", "Swipe Down for Update"));
}
mAdapter = new MyListAdapter(getActivity(), listItemList);
}
mParam1 and mParam2 are Values which are fetched by an XML parser (IntentService) class in the MainActivity which i can show if needed.
Now, if i am to fast, and the mPara1 and mPara2 is empty there won´t be any ListView shown. Now i want to solve this by some AsyncTask or IntentService whatever is useful. I tried AsyncTask, which didn´t work at all. I tried notifyDataSetChanged() which didn´t work too...
Now, how could i solve this....
Using AsyncTask i have the problem that i don´t know how to passt the two Arrays to publishProgress() correctly
THis is how my AsyncTask looks like:
class UpdateListView extends AsyncTask<Void, String, Void> {
private MyListAdapter adapter;
private ArrayList listItemList;
#Override
protected void onPreExecute() {
adapter = (MyListAdapter) mListView.getAdapter();
}
#Override
protected Void doInBackground(Void... params) {
for (String item1 : mParam1) {
publishProgress(item1);
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
adapter.add(new MyListItem(values[0], values[1]));
}
#Override
protected void onPostExecute(Void result) {
Log.d("onPostExecute", "Added successfully");
}
}
Okay solved it...My Fragments are running in same Activity where the Data is loaded in, so i just created getter and setter in MainActivity and access them in the needed Fragment via
String[] titles =(MainActivity) getActivity()).getTitlesArray();
String[] text=(MainActivity) getActivity()).getTextArray();
Whatever i do trying setting Bundle with
bundle.putStringArray(TITLES,titles);
doesn´t work. Should work using parceable/serializable class but didn´t try...

How to remove "no data" labels from empty nodes in GWT?

I have a widget that inherits from CellTree. If the node not have the child elements, this node can be opened and shows "no data" label.
I'd like to see nodes without child's displayed as empty.
That's how I fill the tree. My DictionaryTreeDataProvider class (relevant part):
public class DictionaryTreeDataProvider extends ListDataProvider<MValue> {
private final DictionariesServiceAsync service = GWT.create(DictionariesService.class);
...
#Override
public void onRangeChanged(HasData<MValue> result) {
service.queryDictionaryValues(range, query, new AsyncCallback<SubsetResult<MValue>>() {
#Override
public void onFailure(Throwable t) {
}
#Override
public void onSuccess(SubsetResult<MValue> result) {
getList().clear();
for (MValue value : result.items) {
getList().add(value);
}
}
});
}
}
On the server side I make EJB call which fills SubsetResult.
I found that this problem fixed in version of GWT-2.5.0-rc2 (see https://groups.google.com/forum/#!topic/google-web-toolkit/d-rFUmyHTT4).
Now everything is OK, thanks to #moutellou.
I did as he suggested:
...
#Override
public void onSuccess(SubsetResult<MValue> result) {
if (result.length == 0) {
updateRowCount(-1, true);
return;
} else {
for (MValue value : result.items) {
// some checks here
getList().add(value);
}
}
}
...
Some alternative solution. Can be defined interface that extends the interface CellTree.Resources.
In this interface must specify the path to the CSS, which override the desired style.
Interface CellTree.Resources:
public class CellTree extends AbstractCellTree implements HasAnimation,
Focusable {
...
/**
* A ClientBundle that provides images for this widget.
*/
public interface Resources extends ClientBundle {
/**
* An image indicating a closed branch.
*/
#ImageOptions(flipRtl = true)
#Source("cellTreeClosedArrow.png")
ImageResource cellTreeClosedItem();
/**
* An image indicating that a node is loading.
*/
#ImageOptions(flipRtl = true)
ImageResource cellTreeLoading();
/**
* An image indicating an open branch.
*/
#ImageOptions(flipRtl = true)
#Source("cellTreeOpenArrow.png")
ImageResource cellTreeOpenItem();
/**
* The background used for selected items.
*/
#ImageOptions(repeatStyle = RepeatStyle.Horizontal, flipRtl = true)
ImageResource cellTreeSelectedBackground();
/**
* The styles used in this widget.
*/
#Source(Style.DEFAULT_CSS)
Style cellTreeStyle();
}
...
}
Interface CustomCellTreeResources, based on CellTree.Resources:
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.user.cellview.client.CellTree;
public interface CustomCellTreeResources extends CellTree.Resources {
static final String STYLE_PATH = "components/common/client/static/custom-cell-tree.css";
#Override
#ClientBundle.Source({CellTree.Style.DEFAULT_CSS, STYLE_PATH})
CellTree.Style cellTreeStyle();
}
Overriding rule:
.cellTreeEmptyMessage {
display: none;
}
Create an instance:
private final static CellTree.Resources customCellTreeResources =
GWT.create(CustomCellTreeResources.class);
And next need to explicitly pass customCellTreeResources to the CellTree class constructor.
Message is not displayed more.
Mandatory: before filing the list, ie, before clicking on a node, the list should be cleaned( getList().clear();):
#Override
public void onRangeChanged(HasData<MValue> result) {
service.queryDictionaryValues(range, query,
new AsyncCallback<SubsetResult<MValue>>() {
#Override
public void onFailure(Throwable t) {}
#Override
public void onSuccess(SubsetResult<MValue> result) {
getList().clear();
for (MValue value : result.items) {
getList().add(value);
}
}
});
}
This is how I removed the no data label in my DataProvider
//Fetch children
int size = children.size();
if (size == 0) {
updateRowCount(-1, true); //Method called on AsyncDataProvider
return;
}
In the TreeViewModel, make sure that the isLeaf method returns true if the argument value has no children. Example:
#Override
public boolean isLeaf(Object value) {
if (value instanceof DepartmentDto) {
DepartmentDto department = (DepartmentDto) value;
return department.getEmployees().isEmpty();
} else if (value instanceof EmployeeDto) {
return true;
} else {
return false;
}
}
In this case, a department should declare itself as a leaf only if it has no employees, an employee will declare itself as a leaf, and default to false.
Note that value many also be an internal GWT node. In this example, it might not necessarily be just DepartmentDto and EmployeeDto.

I'm stuck at slick graphics

I'm trying to make a game, using slick2d, and lwjgl. I don't get why this code doesn't work
firstStage.java
package net.CharlesDickenson;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
public class firstStage extends BasicGameState {
public bossVar bossChecker() {
if(isBeforeMiddleBoss) return bossVar.beforeBoss;
if(isMiddleBoss) return bossVar.Middle;
if(isBeforeBoss) return bossVar.beforeBoss;
if(isBoss) return bossVar.Boss;
return null;
}
#SuppressWarnings("static-access")
public firstStage(int state) {
this.state = state;
}
#Override
public void init(GameContainer _arg0, StateBasedGame _arg1)
throws SlickException {
scoreBoard = new Image("res/scoreBoard.png");
backs = new Image("res/1stageBack.gif");
isBeforeMiddleBoss = true;
isMiddleBoss = false;
isBeforeBoss = false;
isBoss = false;
_arg0.setShowFPS(false);
}
#Override
public void render(GameContainer arg0, StateBasedGame _arg1, Graphics _g)
throws SlickException {
this._g = _g;
new Mob().getGraphics(_g);//i passed graphics
new Char().getGraphics(_g);//i passed graphics
new Bullet().getGraphics(_g);//i passed graphics
_g.drawImage(scoreBoard, 550, 5);
_g.drawImage(backs, 10, 10);
_g.drawString(fps, 580, 570);
_g.drawString("High Score-> Not avaiable", 560, 60);
_g.drawString("Score-> " + currScore, 595, 80);
}
#Override
public void update(GameContainer _arg0, StateBasedGame _arg1, int arg2)
throws SlickException {
fps = "Frame Per Second-> " + _arg0.getFPS();
bossVar b = bossChecker();
switch(b) {
case beforeMiddle :
break;
case Boss :
break;
default:
break;
}
}
#SuppressWarnings("static-access")
#Override
public int getID() {
return this.state;
}
private static int state;
private static int currScore = 0;
private static final int originX = 270;
private static final int originY = 490;
public static int X = originX;
public static int Y = originY;
private static String fps;
private Image scoreBoard;
private Image backs;
private Graphics _g;
public boolean isBeforeMiddleBoss;
public boolean isMiddleBoss;
public boolean isBeforeBoss;
public boolean isBoss;
}
Char.java
package net.CharlesDickenson;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
public class Char extends Bullet implements Entity {
#Override
public void getGraphics(Graphics _g) {
this._g = _g;//so i got graphics, but
if(!isInit) return;
_g.drawImage(Char, getCharX(), getCharY());//this codes doesn't works.
}
#Override
public int getCharX() {
switch(VarTracker.stage) {
case 1:
return firstStage.X;
}
return 0;
}
#Override
public int getCharY() {
switch(VarTracker.stage) {
case 1:
return firstStage.Y;
}
return 0;
}
public void setCharX(int i) {
System.out.println("asdgagsd");
switch(VarTracker.stage) {
case 1:
firstStage.X += i;
}
}
public void setCharY(int i) {
System.out.println("asdgagsd");
switch(VarTracker.stage) {
case 1:
firstStage.Y += i;
}
}
#Override
public void update() {
if(!isInit) return;
_g.drawImage(Char, getCharX(), getCharY());//this code doesn't work, too.
up = Keyboard.isKeyDown(Keyboard.KEY_UP);
down = Keyboard.isKeyDown(Keyboard.KEY_DOWN);
left = Keyboard.isKeyDown(Keyboard.KEY_LEFT);
right = Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
shift = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT);
z = Keyboard.isKeyDown(Keyboard.KEY_Z);
if(up && !shift) {
setCharY(6);
}
if(down && !shift) {
setCharY(-6);
}
if(left && !shift) {
setCharX(-6);
}
if(right && !shift) {
setCharX(6);
}
if(up && shift) {
setCharY(2);
}
if(down && shift) {
setCharY(-2);
}
if(left && shift) {
setCharX(-2);
}
if(right && shift) {
setCharX(2);
}
if(z) {
new Bullet().isFiring = true;
}
if(!z) {
new Bullet().isFiring = false;
}
}
#Override
public void init() {
System.out.println("<Char> Initializing...");
isInit = false;
try {
Char = new Image("res/char.png");
} catch (SlickException e) {
e.printStackTrace();
}
isInit = true;
System.out.println("<Char> Done with init()");
}
private boolean up;
private boolean down;
private boolean left;
private boolean right;
private boolean shift;
private boolean z;
private boolean isInit;
private Image Char;
private Graphics _g;
}
I passed graphics to other class using getGraphics method, to put a image, but it doesn't work.
at render method, it worked, but I can't put a image in other class.
The reason that it doesn't work is that you are using Graphics incorrectly. When Slick2d draws something, it uses the render method. This method is passed an instance of Graphics, to which you can draw stuff. When the call ends the Graphics object is no longer useful for anything. There is thus no reason to pass it to anything that doesn't use it immediately.
What you want to do is create a render method in your Mob, Char and Bullet classes. Make instances of said classes outside of the render method, for instance in init and store them in some data structure, for instance a List. In the render method, you simple traverse the list and call render or draw on each element. A quick example:
// Give the Entity interface two methods if they don't exist already:
public interface Entity {
void render(Graphics g);
void update(int delta);
}
// In firststage.java
List<Entity> list;
// In the init() method
public void init(GameContainer container, StateBasedGame game)
throws SlickException {
...
list = new ArrayList<Entity>();
list.add(new Mob());
list.add(new Char());
list.add(new Bullet());
}
// In the render method
public void render(GameContainer container, StateBasedGame game, Graphics g)
throws SlickException {
...
for (Entity e : list) {
e.draw(g);
}
}
// In the update method
public void update(GameContainer container, StateBasedGame game, int delta)
throws SlickException {
...
for (Entity e : list) {
e.update(delta);
}
}
TL;DR version: The Graphics object exists only to be drawn to in a single render call.
Render is called many times a second, so object creation in that method is not recommended.
Object oriented programming is good at modeling objects. Games tend to model a lot of objects. Make use of it.

GWT multiple Activities/Places with one Token

My Site has on the left a GWT-Tree. In the center is a GWT-TabBar.
Both parts are implemented as Views/Activities/Places. I have two tokenizer: "m" for the tree and "t" for the tabs.
If I visit one place (goTo()) only this place will be used to generate the history token. But I would like to see this: <page>#m:sub/sub/sub;t:map
I actually thought that the hole idea of activities&places. I don't see the point to have multiple tokenizer, when only one tokenizer can provide a token at once.
You cannot display two different tokens #m: and #t: at the same time as you cannot be in two places at the same time.
So if both tabs and tree are displaying at the same time, then the state of both must be stored at once in the same place.
This is more or less what you need.
public class ExamplePlace extends Place {
public String treePosition = "/";
public int tabIndex = 0;
public ExamplePlace() {
super();
}
public ExamplePlace(String treePosition, int tabIndex) {
this.treePosition = treePosition;
this.tabIndex = tabIndex;
}
#Prefix("overview")
public static class Tokenizer implements PlaceTokenizer<ExamplePlace> {
/**
* parse token to get state
*
*/
#Override
public ExamplePlace getPlace(String token) {
String treePosition = "";
int tabIndex = 0;
String[] states = token.split(";");
for (String state : states) {
String[] mapping = state.split("=");
if (mapping.length == 2) {
if ("t".equals(mapping[0])) {
treePosition = mapping[1];
}
if ("m".equals(mapping[0])) {
try {
tabIndex = Integer.valueOf(mapping[1]);
} catch (Throwable e) {
}
}
}
}
return new ExamplePlace(treePosition, tabIndex);
}
/**
* store state in token
*
*/
#Override
public String getToken(ExamplePlace place) {
StringBuffer sb = new StringBuffer();
if (place.getTreePosition()!=null) {
sb.append("t").append("=").append(place.getTreePosition());
sb.append(";");
}
sb.append("m=").append(place.getTabIndex());
return sb.toString();
}
}
public String getTreePosition() {
return treePosition;
}
public void setTreePosition(String treePosition) {
this.treePosition = treePosition;
}
public int getTabIndex() {
return tabIndex;
}
public void setTabIndex(int tabIndex) {
this.tabIndex = tabIndex;
}
}
This will give you URLs that look like ;
index.html#overview:t=/subtree/subtree/leaf;m=2
You might run in trouble with the forward slashes in the token, not sure. Change them to some other character if necessary;
The activity receives the incoming place and inject the state into the view;

On Gwt TreeViewModel getNodeInfo() method

I can't understand that part, neither trying the showcase examples.
I'm using an extension of AsyncDataProvider to bind my tree to RPC service. Here's my method:
public <T> NodeInfo<?> getNodeInfo(T value) {
/*
if (value instanceof Categoria) {
dataProvider.setCurrentParent((Categoria)value);
}
*/
return new DefaultNodeInfo<Categoria>(dataProvider, new CategoriaCell());
}
"currentParent" is my stuff: except for (null => root) values, I set the parent to pass via RPC to my service. Actually, in my widget code:
dataProvider = new CategorieTreeDataProvider() {
#Override
protected void onRangeChanged(HasData<Categoria> display) {
updateTree(getCurrentParent());
}
};
private void updateTree(Categoria categoria) {
rpcService.getCategorie(categoria, new AsyncCallback<Categoria[]>() {
#Override
public void onSuccess(Categoria[] result) {
dataProvider.updateRowCount(result.length, true);
dataProvider.updateRowData(0, Arrays.asList(result));
}
#Override
public void onFailure(Throwable caught) {
Window.alert(caught.toString());
}
});
}
My rpc-server code, however, is working as expected:
#Override
public Categoria[] getCategorie(Categoria parent) {
List<Categoria> categoryList = categorieDao.listByProperty("parent", parent);
for (Categoria c : categoryList) {
if (categorieDao.listByProperty("parent", c).size() == 0) {
c.setLeaf(true);
}
}
return categoryList.toArray(new Categoria[0]);
}
**Then I add some data to my Categories: 'GrandFather', 'Father' and 'Son'.
Unfortunately, after loading my widget, I see:
The grandfather correctly, with his "+" how expected;
Then I click it and...
The grandfather disappear and I see 'Father' with his '+'
same for father -> son
I suspect the bug is in updateRowCount / updateRowData usage.**
Any ideas?
The getNodeInfo is called whenever you open a node so you have to create distinct DataProvider for each of the nodes's childs.
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == null) {
return new DefaultNodeInfo<Category>(dataProvider, new CategoriaCell());
}
else if (value instanceof Categoria) {
Category category = (Category)value;
return new DefaultNodeInfo<Grandfather>(new ListDataProvider<Grandfather>(category.getGrandFathers()),new GrandFatherCell());
}
else if (value instanceof Grandfather) {
Grandfather grandfather = (Grandfather)value;
return new DefaultNodeInfo<Father>(new ListDataProvider<Father>(granfather.getFathers()),new FatherCell());
}
else if (value instanceof Father) {
//same as above but with fathers.
}
}
The category.getGrandFathers() function can for example do a RPC request to the server or just return the list if you retrieve everything in one RPC request.
UPDATE based on comment:
So in case you have only one class and want to achieve a dynamic CellTree (number of levels are not pre-determined) you could take following approach.
public <T> NodeInfo<?> getNodeInfo(T value) {
if (value == null) {
return new DefaultNodeInfo<Category>(dataProvider, new CategoriaCell());
}
else {
Category category = (Category)value;
return new DefaultNodeInfo<Category>(new ListDataProvider<Category>(category.getSubCategories()),new CategoryCell());
}
}
category.getSubCategories() is either an RPC call which retrieves the subcategories for the current category or if the Category class is a linked list type datastructure it could just return the list of subcategories.
Each data provider updates a given "list" (child nodes of a given parent node), so you have to use a distinct data provider instance for each parent node, or your calls will update some random list.