I'm in process of replacing JFace TableViewer with NatTable. In my implementation with TableViewer I have images in cells, and I have implementation of ILabelProvider which is aware of how to get image for concrete state of object at runtime. So I call ILabelProvider.getImage(element) from ColumnLabelProvider.
In NatTable I know the way to add an image via registring configAttribute against configLabel. And for configAttribute I should explicitly tell what image to use. Surely I can create label for every state, register image for every label and use ConfigLabelAccumulator to tie it all togeather. But the amount of images is quite huge, and moreover I don't want to duplicate this logic. So is there more appropriate way for such a case? Just delegating to existing ILabelProvider?
In cases where you have quite some dynamic for retrieving the Image the label solution is insufficient (e.g. when thinking about a shop system with different images per row object). In such cases you typically implement a custom ImagePainter and implement the code the determine the Image to use in the getImage() method.
The following snippet can be used as a starting point where you only need to implement your custom logic to determine the Image to use. This way you only need to register one ImagePainter. In NatTable this is also done for some static images like for example the TreeImagePainter.
public class ContentDependentImagePainter<T> extends ImagePainter {
IRowDataProvider<T> dataProvider;
public ContentDependentImagePainter(IRowDataProvider<T> dataProvider) {
this.dataProvider = dataProvider;
}
#Override
protected Image getImage(ILayerCell cell, IConfigRegistry configRegistry) {
// get the row object
T rowObject = dataProvider.getRowObject(cell.getRowIndex());
Image result = null;
// perform your custom logic to determine the Image
return result;
}
}
Related
I have something like this.
Grid<Stock> mygrid = new Grid<Stock>(store, cm)
{
#Override
protected void onAfterFirstAttach()
{
super.onAfterFirstAttach();
//here do the binding for the cell elements that have myclass
}
};
And for the view of mygrid I have this
view.setViewConfig(new GridViewConfig<Stock>()
{
#Override
public String getRowStyle(Stock model, int rowIndex)
{
return "";
}
#Override
public String getColStyle(Stock model, ValueProvider<? super Stock, ?> valueProvider, int rowIndex, int colIndex)
{
String style = "";
if(SOME_CASE)
{
style = "myclass";
}
return style;
}
});
What I want to do is onAfterFirstAttach I want to add some listener/handler that during hover will do something, let's say for the sake of simplicity, give an alert.
Is what I'm trying to do possible? Can I accomplish what I want without using JSNI or a library like gwtquery? Is it sure that onAfterFirstAttach all the cells that should have the class myclass will be available and accessible? If yes how can I attach the listener/handler that I want?
The questions seem a lot, but I believe they are all interconnected.
I'm using GWT 2.6 with GXT 3.1 on top of it.
Update
I forgot to mention that a feasible solution would be to add a listener for the mouse move on the whole grid, and then get each cell and check if it has the required class, but this seems such an overkill. There must be a simpler way.
A browser fires native events (click, focus, blur, etc.) regardless of whether you need them. These events "bubble up" the DOM tree giving you a chance to "listen" to them at the right level.
In your example you can create 30 listeners at the cell level, waiting for something to happen in "their" cell. This is a heavy (30 objects) and slow (it takes time to build and bind all of them) solution. Alternatively, you can create a single listener at the grid level, which listens to all events that bubble up from the cells and decides if something needs to be done or an event should be ignored. A single listener is lighter and can be created faster. On the flip side, it needs to examine events, although it's usually a fast and efficient operation (e.g. checking of an event source has a particular class name). Note also that this operation takes time when a browser typically does not have much to do anyway, so examining events only to ignore them does not impact user experience.
In my experience a single listener is almost always a better solution, although modern browsers and computers are so fast that the difference is rarely noticeable.
I am having trouble understanding the undo/redo functions using UndoManager, and integrating it with the MVC model.
I am not sure where to put the various methods(in model, view or control)
and I am still not sure how to use the undo manager.
My control class implements UndoableEditListener
It creates:
private UndoManager manager = new UndoManager();
and in:
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Undo")) {
try {
manager.undo();
} catch (CannotUndoException ex) {
ex.printStackTrace();
}
}
}
I understand up to here, but the rest I am not sure what to do. I know I will have to add more in the model and view class, but not sure where.
DO I have to have the following classes?
public class UndoAction extends AbstractAction {}
public void undoableEditHappened(UndoableEditEvent e) {
I am simply placing an integer number in a textfield, and then I want to be able to undo this.I set the number in the textfield in the view class.I want to acheive this the simplest way possible, no fancy coding! This is a minor part of my assg but I just cant get it working!!
==========================================================
Here is a more detailed description of my code, maybe it will help:
I have a model, view and control package.
Contol has:
ButtonGUIControl.java, which implements both
ActionListener and
UndoableEditListener.
final UndoManager manager = new UndoManager();
In the actionPerformed method, it calls
if (e.getActionCommand().equals("Undo")){
try {
manager.undo();
}
and in:
public void undoableEditHappened(UndoableEditEvent evt) {
manager.addEdit(evt.getEdit());
}
In the View:
Grid.java , which extends JTextField will add the following, wherever it needs to display a number on the GUI:(model is simply an instance of my Model class)
getDocument().addUndoableEditListener(new ButtonGUIControl(model));
Could it be because the UndoManager is being created in a different package? I really have no idea how to debug this anymore!!
I could post my entire code if that helps. I guess Im not sure how to integrate this with my mvc model structure.
Take a step back for a second. The whole idea here is that a user will use your app and will make a series of changes to something. A text editor is a good example. You can insert characters and lines, delete them again, replace text with other text, scroll the text, etc. In order to support this with MVC you have a model that holds state and a View that displays it.
Your first instinct might be to have the view directly access the model, and then refresh the view every time the user makes a change, but it's very hard to undo those changes with that implementation. Instead, you encode every kind of change the user can make in classes that are able to perform that change and can later undo that change.
For example, an action that inserts text would be implemented by a class that knows the character offset of the insertion point and the string of characters that is to be inserted. The perform action would insert the string at the offset and the undo action would remove the right number of characters after that insertion point. You'd have a different class that would handle deletion, another to handle scrolling etc.
Every time the user takes some action, the view would construct one of these UndoableEdit classes and would tell the instance to run itself (redo()). Once executed, you put that UndoableEdit at the end of a list of UndoableEdit instances that represent all of the actions the user has taken so far. This list makes it very easy to support any sequence of undo requests, redo requests and actual edit actions (resulting in more UndoableEdit's being put on the list).
So back to your question. If your app needs to support undo and redo, then you'll need to implement an UndoManager which simply manages the list of UndoableEdit's and performs undo and redo as necessary. You also have to implement a whole bunch of UndoableEdits, one for each kind of thing your user will do against the UI. As for a listener, I can't see that you really need to do that one.
If you need only simple undo/redo, you can use UndoManager as it is, you don't need to subclass or customize it in any way.
JTextField (more specifically its model, the Document) has some built-in support for undo, which means you don't need to write UndoableEdit implementations either, the UndoableEdit objects will be automagically created for you (actually AbstractDocument.DefaultDocumentEvent implements UndoableEdit).
Full simple working example is here
I'm having problems using ResizeLayoutPanel inside DisclosurePanel.
I have a Datagrid into ResizeLayoutPanel, and ResizeLayaoutPanel inside DisclosurePanel. The problem is when data is loaded, If DisclosurePanel was closed, when user opens disclosurePanel it finds the table empty. If user does this action when DisclosurePanel is open, works fine.
Any idea how can I solve this problem?
This is the code:
ResizeLayoutPanel resizeLayoutPanel = new ResizeLayoutPanel();
resizeLayoutPanel.setWidth("100%");
resizeLayoutPanel.setStyleName("gwt-resizeLayoutPanel-Example");
/****CREATE COLUMNS [BEGIN] ***************************************************************************/
// Create column.
TextColumn<Object> column = new TextColumn<Object>() {
#Override
public String getValue(Object object) {
return "Test";
}
};
/******CREATE COLUMNS [END] ***************************************************************************/
cellTable = new DataGrid<Object>();
cellTable.addColumn(column, "Example");
cellTable.setKeyboardSelectionPolicy(HasKeyboardSelectionPolicy.KeyboardSelectionPolicy.BOUND_TO_SELECTION);
cellTable.setWidth("100%");
cellTable.setEmptyTableWidget(new Label("Example table"));
resizeLayoutPanel.add(cellTable);
//Link dataProvider with CellTable
dataProvider.addDataDisplay(cellTable);
this.container = ModuleContainer.getAdvancedDisclosurePanel("Samples");
this.container.setWidth("100%");
this.container.setContent(resizeLayoutPanel);
return this.container;
ResizeLayoutPanel provides resize (implements ProvidesResize) but does not requires resize (does not implement RequiresResize).
Since ResizeLayoutPanel in its plain state does not listen to resize, you have to deliberately resize it, or write code to resize it. Perhaps, set width and height to 100%.
And then, why did you place the table inside a ResizeLayoutPanel ?
ResizeLayoutPanel provides resize to widgets that RequiresResize. You need to extend the celltable to implement RequiresResize, so that the ResizeLayoutPanel would be able to resize it.
The first concept anyone needs to learn when programming GWT is to understand why/how to create a chain/tree of unbroken RequiresResize-RequiresResize from a root resize panel. If your root of your resize chain/tree is not RootLayoutPanel, then you have to deliberately resize that root.
In this case, you have made ResizeLayoutPanel the root of resize non-existent resize chain. Use another panel that implmements RequiresResize so that it could be resized by a parent - as well as making sure the parent is resizable manually by user or by another resizable parent.
May I ask you to ask yourself, what is the reason for using ResizeLayoutPanel without providing a way to resize it and also without using it as a root of a resizing chain?
the question is simple.
I have 2 images in PNG format (logo1.png and logo2.png) in the project. Currently the project is loaded (in a imageview) the logo1.png, but I would do, depending on the value of a variable load the logo1.png or load logo2.png in imageview control.
The project currently has 20 Activitys with this picture (each with its own layout in XML), I will not be changing code on the 20 screens, it could do with a simple instruction to verify the value of the variable, but would have to make change in the 20 screens.
wonder if there is no way to do that depending on the value of a variable, change the image in the ImageView.
will be able to access the value of the variable from the same XML?
Thanks in advance.
I'm a bit confused, but I'll give it a shot.
Yes, you can have a global variable where you define which image will load. But from my understanding, you would need to change the code in the activities that load that image to make them load the image dynamically via the code-behind.
I suspect it would be something like this:
Get info from the database indicating what value to load.
SetImageToLoad(someValue)
In each class that loads the image, you'll need to retrieve the value that you previously set in Step #2.
public class HelperClass
{
int resIDOfImageToLoad = 0;
public static void SetImageToLoad(String imageName)
{
if(imageName.equals("abc"))
{
resIDOfImageToLoad = R.id.abc;
}
else if(imageName.equals("xyz"))
{
resIDOfImageToLoad = R.id.xyz;
}
}
public static int GetResourceIDOfImageToLoad()
{
return resIDOfImageToLoad;
}
}
Then in the class that needs to load the image, you would call something like this
ImageView myImage = (ImageView)findViewById(...)
myImage.setImageResource(HelperClass.GetResourceIDOfImageToLoad());
If i understand you correctly. Create a new XML View of the image e.g. logo.xml and use it in all 20 Views and when you want to change that image change only in the logo.xml.
Assuming you have a base Activity class, you can define a method getLogo() in the base class that would return the png (or the filename or whatever suits you). Then just call that method when inflating the layout.
Initially, you'd have to change all the Activities, but after that you just need to change the base class if you decide to change the logic that chooses which image to show. (If this is not what you intended, please clarify your question).
I would recommend using Style or Themes. Read over the section that talks about inheritance, and declare a separate Style for each logo. You can then reuse the Style in each one of your XML files.
If you decide to programmatically determine which image to use, you can declare a static method that can be used application wide to determine which logo to use in each Context, then setImageResource() accordingly.
I try to realize a link (in fact many links) that update a table in an website using an AjaxLink of Wicket. But I fail, the table is never updated (I have "setOutputMarkupId(true)" and call "setDefaultModelObject" and "addComponent", but there must be something other thats wrong).
How can I realize a panel with a number of links and a table that displays dynamic data, dependent on the link clicked? Can someone give an example (Maybe two links, when the first one is clicked the table displays two random numbers from 1-10, when the second is clicked the table displays random numbers from 1-100)? Without reloading the entire page, but only the html for the table?
One possible reason might be that you are not using a 'refreshable' model, but rather fetching the list items and passing them directly to the component, thus the list get's serialized in the session and doesn't get updated.
If this is the case, pass a LoadableDetachableModel (that retrieves the list in it's load method) to the component. I can't be more specific without seeing your code.
I don't think you've defined what you are doing very clearly.
Are these 2 tables different implementations? If so, then your code is correct - you have to replace the old component with the new one, then add the new one to the ajax response.
Realistically though, I'd imagine that you have 1 table component implementation.
What you therefore need to do, is something like this:
public class RandomNumberListModel extends LoadableDetachableModel {
private int upperBound;
public RandomNumberListModel(int upperBound) {...}
public void setUpperBound(int upperBound) {...}
protected Object load() {
// generate random number list using upper bound
// return list
}
}
...
final MyTableComponent table = new MyTableComponent(new RandomNumberListModel(30));
add(table);
AjaxLink link = new AjaxLink("myButton") {
public void onClick(final AjaxRequestTarget target) {
table.getModel().setUpperBound(100);
target.addComponent(table);
}
};
add(link);
(Edit) I've added a dynamic, reusable model to illustrate how the model would work. There are different ways of implementing this, depending on what you want to be reusable. The key point is that the model generates the list dynamically, i.e. per request, and the upperBound of the number range can be manipulated in the onClick callback.
Like jboyd was asking do you have code that knows to send the table contents back in the Ajax response?:
final Component tableComponent = ....;
AjaxLink link = new AjaxLink("myButton"){
public void onClick(final AjaxRequestTarget target) {
target.addComponent(tableComponent);
}
};
add(link);
The addComponent piece is the part jboyd is referring to.
There is one such example among the wicketstuff.org examples, the tree/tree table one. The three links at the top change the table.