How to customize style sheet of Apache wicket HeadersToolbar? - wicket

I've got problem with rendering table's header .it is not display any color on table.
I used HeadersToolbar with my data some thing like below.
import org.apache.wicket.Component;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.table.HeadersToolbar;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
import org.apache.wicket.extensions.markup.html.repeater.data.table.NavigationToolbar;
import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.OddEvenItem;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
public class CustomTable extends DataTable {
private static final long serialVersionUID = 5912216230302446976L;
public CustomTable(String id, List columns,
ISortableDataProvider dataProvider, int rowsPerPage) {
this(id, (IColumn[]) columns.toArray(new IColumn[columns.size()]),
dataProvider, rowsPerPage);
}
public CustomTable(String id, IColumn[] columns,
ISortableDataProvider dataProvider, int rowsPerPage) {
super(id, columns, dataProvider, rowsPerPage);
// super(id, columns, dataProvider, rowsPerPage);
addTopToolbar(new NavigationToolbar(this));
addTopToolbar(new HeadersToolbar(this, dataProvider));
}
protected Item newRowItem(String id, int index, IModel model) {
return new OddEvenItem(id, index, model);
}
}
I saw HeaderToolbar in details it will generate CSS class "headers" .And then i see in View Source . i have got css class in name "headers".
How to do customize HeaderToolbar to get correctly table row header display color or Can i create new one Css class instead ?
Any one can help me to solve this problem ? :)

I don't understand your goal. Do you want the color of the table header to change dynamically, or are you just trying to set the color of the header statically?
If setting the color statically, you can just use css th.header {background-color: #7FFF00;} for html: <th class="header">...</th>.
If you want it dynamically set I have had success with leaving the class out of the html & injecting it with wicket when condition is met:
if(...) {
header.add(new AttributeModifier("class", "header")`;
}
With more information I may be able to provide a more complete answer. Let me know if you have additional questions.

Related

Dynamically add widgets in a cell to represent "tags" in Datagrid

In a GWT web app, I am using a DataGrid to manage elements from a database. I represent a list of elements as rows, the columns being editable fields of their characteristics (id, name, description). I am mostly using the EditTextCell class.
I now want to create a custom cell, for a column that has to represent a list of "tags" that can be attached to every element. From this cell, tags could be added, using a + button (that makes a drop-down menu appear or something), and deleted. Each tag should be a kind of button, or interactive widget (I later want to display pop-up with info, trigger actions, etc).
Actually, it would not be so different from the "tags" bar on the Stack Overflow website...
So I have been looking for a solution:
I thought this would be easy to do. I imagined just putting a FlowPanel in the cell, adding/removing Buttons/Widgets dynamically. But it turns out that in GWT Widgets and Cells and very different objects apparently..
I read making use of the AbstractCell class to create a custom cell allows to do anything, but its working is very low level and obscure to me.
I saw that CompositeCell allows to combine various cell widgets into one cell, but I have not found if it is possible to do it dynamically, or if the widgets are going to be the same for all lines throughout a column. I mostly saw examples about, for instance, how to put two Buttons in every cell of a single column.
What is the easiest way to implement what I need?
EDIT:
So, after some tests, I am going for Andrei's suggestion and going "low-level", creating a custom cell extending AbstractCell<>. I could create an appropriate "render" function, that generates a list of html "button", and also attaches Javascript calls to my Java functions when triggering a Javascript event (onclick, onmouseover, onmouseout...).
It is working pretty well. For instance, by clicking the "+" button at the end a tag list, it calls a MenuBar widget that presents the list of tags that can be added.
But I am struggling to find a way to update the underlying data when adding a tag.
To sum up:
I have a CustomData class that represents the data I want to display in each line of the table. It also contains the list of tags as a Set.
ModelTable (extends DataGrid) is my table.
CustomCell (extends AbstractCell) can renders the list of tags as several buttons on a line.
A click on a "+" button in a cell makes a AddTagMenu popup drop down, from which I can click on the tag to add.
How do I update the content of the cell?
I tried playing around with onBrowserEvent, onEnterKeyDown, bus events... with no success. At best I can indeed add a tag element to the underlying object, but the table is not updated.
It's not possible to meet your requirements without going really "low-level", as you call it.
It's relatively easy to create a cell that would render tags exactly as you want them. Plus icon is also easy, if this is the only action on the cell. However, it is very difficult to make every tag within a cell an interactive widget, because the DataGrid will not let you attach handlers to HTML rendered within a cell. You will need to supply your own IDs to these widgets, and then attach handlers to them in your code. The problem, however, is that when the DataGrid refreshes/re-renders, your handlers will most likely be lost. So you will have to attach them again to every tag in every cell on every change in the DataGrid.
A much simpler approach is to create a composite widget that represents a "row", and then add these "rows" to a FlowPanel. You can easily make it look like a table with CSS, and supply your own widget that looks like a table header. You will need to recreate some of the functionality of the DataGrid, e.g. sorting when clicked on "column" header - if you need this functionality, of course.
As you have already noted, using CompositeCell could be a way to get what you want.
The idea is to create a cell for every tag and then (during rendering) decide which one should be shown (rendered). Finally combine all those cells into one by creating a CompositeCell.
The main disadvantage of this solution is that you need to know all possible tags before you create a DataGrid.
So, if you have a fixed list of possible tags or can get a list of all existing tags and this list is reasonably small, here is a solution.
First, we need to know which tag is represented by a column so I extended a Column class to keep information about a tag. Please, note that TagColumn uses ButtonCell and also handles update when the button is clicked:
public class TagColumn extends Column<DataType, String> {
private TagEnum tag;
public TagColumn(TagEnum tag) {
super(new ButtonCell());
this.tag = tag;
setFieldUpdater(new FieldUpdater<DataType, String>() {
#Override
public void update(int index, DataType object, String value) {
Window.alert("Tag " + getTag().getName() + " clicked");
}
});
}
public TagEnum getTag() {
return tag;
}
#Override
public String getValue(DataType object) {
return tag.getName();
}
}
Then create a cell for each tag (I have hard-coded all tags in a TagEnum):
List<HasCell<DataType, ?>> tagColumns = new ArrayList<HasCell<DataType, ?>>();
for(TagEnum tag : TagEnum.values())
tagColumns.add(new TagColumn(tag));
Now, the most important part: decide either to show the tag or not - overwrite render method of the CompositeCell:
CompositeCell<DataType> tagsCell = new CompositeCell<DataType>(tagColumns) {
#Override
protected <X> void render(Context context, DataType value, SafeHtmlBuilder sb, HasCell<DataType, X> hasCell) {
if(value.getTagList().contains(((TagColumn) hasCell).getTag()))
super.render(context, value, sb, hasCell);
else
sb.appendHtmlConstant("<span></span>");
}
};
This is important to always render any element (for example empty span when the tag should not be shown). Otherwise the CompositeCell's implemantation will get confused when accessing sibling elements.
Finally, full, working example code:
private DataGrid<DataType> getGrid() {
DataGrid<DataType> grid = new DataGrid<DataType>();
List<HasCell<DataType, ?>> tagColumns = new ArrayList<HasCell<DataType, ?>>();
for(TagEnum tag : TagEnum.values())
tagColumns.add(new TagColumn(tag));
CompositeCell<DataType> tagsCell = new CompositeCell<DataType>(tagColumns) {
#Override
protected <X> void render(Context context, DataType value, SafeHtmlBuilder sb, HasCell<DataType, X> hasCell) {
if(value.getTagList().contains(((TagColumn) hasCell).getTag()))
super.render(context, value, sb, hasCell);
else
sb.appendHtmlConstant("<span></span>");
}
};
Column<DataType, DataType> tagsColumn = new Column<DataType, DataType>(tagsCell) {
#Override
public DataType getValue(DataType object) {
return object;
}
};
grid.addColumn(tagsColumn, "Tags");
grid.setRowData(Arrays.asList(
new DataType(Arrays.asList(TagEnum.gwt)),
new DataType(Arrays.asList(TagEnum.table, TagEnum.datagrid)),
new DataType(Arrays.asList(TagEnum.datagrid, TagEnum.widget, TagEnum.customCell)),
new DataType(Arrays.asList(TagEnum.gwt, TagEnum.table, TagEnum.widget, TagEnum.customCell)),
new DataType(Arrays.asList(TagEnum.gwt, TagEnum.customCell)),
new DataType(Arrays.asList(TagEnum.gwt, TagEnum.table, TagEnum.datagrid, TagEnum.widget, TagEnum.customCell))
)
);
return grid;
}
public class TagColumn extends Column<DataType, String> {
private TagEnum tag;
public TagColumn(TagEnum tag) {
super(new ButtonCell());
this.tag = tag;
setFieldUpdater(new FieldUpdater<DataType, String>() {
#Override
public void update(int index, DataType object, String value) {
Window.alert("Tag " + getTag().getName() + " clicked");
}
});
}
public TagEnum getTag() {
return tag;
}
#Override
public String getValue(DataType object) {
return tag.getName();
}
}
public class DataType {
List<TagEnum> tagList;
public DataType(List<TagEnum> tagList) {
this.tagList = tagList;
}
public List<TagEnum> getTagList() {
return tagList;
}
}
public enum TagEnum {
gwt ("gwt"),
table ("table"),
datagrid ("datagrid"),
widget ("widget"),
customCell ("custom-cell");
private String name;
private TagEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

How can I modify data from another controller class?

I have a main class (Main.java), two FXML files (FXML1.fxml, FXML2.fxml) and the corresponding controller (FXML1Controller.java, FXML2Controller.java).
In the FXML1.fxml I have two text fields and two buttons.
In the associated controller (FXML1Controller.java) I have declared the text fields and the button as follows:
public TextField textField1;
public TextField textField2;
public Button buttonchange;
public Button buttonOpenWindow;
public void open ()
{
...
stage.show ();
}
public void change ()
{
textField2.setText (textField1.getText ());
}
I type text into textField1. When I click on the buttonChange, then the text should be set in textfield2. Works. It's simple.
When I click the buttonOpen, then a new window opens.
There, I have only one button, but want to do the same.
So something in the way like this:
public void changeFromHere ()
{
FXMLController1 c1 = new FXMLController1 ();
c1.change ();
}
I also know that similar questions have been asked here.
But somehow it does not work the way I want it.
I always get a NullPointerException. For sure. I know.
So I have done the following:
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
...
public class FXML2Controller implements Initializable
{
...
public Button buttonChangeFromHere;
URL location;
FXMLLoader fxmlLoader;
Pane root;
FXMLController1 fc1;
public voidChangeFromHere ()
{
fc1.change ();
}
#Override
public void initialize (URL url, ResourceBundle rb)
{
try
{
location = getClass ().getResource ("FXML1.fxml");
fxmlLoader = new FXMLLoader (location);
root = (Pane) fxmlLoader.load ();
fc1 = (FXMLController1) fxmlLoader.getController ();
} catch (IOException ex)
{
Logger.getLogger (FXML2Controller.class.getName ()) .log (Level.SEVERE, null, ex);
}
}
...
}
Now I can not get a NullPointerException and it should work this way. But nothing happened !?
If I use for testing System.out.println (fc1.textField2.getText ());, then I get the text "Hello", which I have defined in JavaFXSceneBuilder.
If I remove the text in SceneBuilder, then I get "null". Sure. Likewise, I get "null" when I type in the term "Hello" (in textField1) while program is running.
I have also tried to initialize the textfields first in the initialize method. Then I also get always the text "Hello", although I typed "Byebye".
The solutions to similar questions in this forum can not help me.
That's why I put so a similar question again.
This code is also just an example. I can not paste my whole code here. What I really want to do is:
In my program I have a list (listView).
In the list are paths to files that I save as a file. Works fine (In the Main Controller, Main.fxml). There, I have a method public void save (). Now I want to call from another controller class's the save () method. But almost all variables are "null".
But they can't be "null", because the listView shows me the entrys.
I do not think that getter and setter methods are appropriate, because it would be very much redundant code. And I don't want that.
If someone could answer the question how to do it with textfields from example, then I would be grateful.
If it does not work with textfields, it will not work with other components, too:-(.
Thanks in advance.

GWT: TabLayoutPanel with custom tabs does not display correctly

I have a TabLayoutPanel where I am putting custom widgets in for the tabs to be able to display some images next to the text. I originally worked with TabPanel and using custom HTML for the tab text, but custom tab widgets allows me to modify the image on the fly as needed.
My tab widget is essentially a HorizontalPanel, a number of small images, and a line of text. The problem I'm having is that the tab doesn't want to stick to the bottom of the tab bar like normal. The tab is getting positioned at the top of the space reserved for the tab bar, and there's a gap between it and the bottom of the tab bar. I uploaded an image of the problem to http://imgur.com/fkSHd.jpg.
Is there some style that I need to apply to custom widget tabs to make them appear correctly?
In my brief experience, the newer standards mode panels (they all end in "LayoutPanel") don't get along with the older ones (the ones that just end in "Panel"). So you might consider trying a DockLayoutPanel instead of the HorizontalPanel, and it may be more cooperative.
See https://developers.google.com/web-toolkit/doc/latest/DevGuideUiPanels, particularly the section called "What won't work in Standards Mode?":
HorizontalPanel is a bit trickier. In some cases, you can simply
replace it with a DockLayoutPanel, but that requires that you specify
its childrens' widths explicitly. The most common alternative is to
use FlowPanel, and to use the float: left; CSS property on its
children. And of course, you can continue to use HorizontalPanel
itself, as long as you take the caveats above into account.
After a bit more research, I found the answer here: https://groups.google.com/d/msg/google-web-toolkit/mq7BuDaTNgk/wLqPm5MQeicJ. I had to use InlineLabel or InlineHTML widgets instead of normal Label or HTML widgets. I've tested this solution and it does exactly what I want. I pasted the code of the class below for completeness. Note two things here:
The "float" attribute cannot be set on the last element (the InlineLabel) or the incorrect drawing condition occurs again.
The code could be cleaned up a bit further by having the class extend directly from FlowPanel instead of making it a composite containing a FlowPanel.
package com.whatever;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Float;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.InlineLabel;
public class StatusTab extends Composite
{
public interface StatusImages extends ClientBundle
{
public static StatusImages instance = GWT.create(StatusImages.class);
#Source("images/status-green.png")
ImageResource green();
#Source("images/status-red.png")
ImageResource red();
}
private final ImageResource greenImage;
private final ImageResource redImage;
private final FlowPanel flowPanel;
public LinkStatusTab(String text, int numStatuses) {
greenImage = StatusImages.instance.green();
redImage = StatusImages.instance.red();
flowPanel = new FlowPanel();
initWidget(flowPanel);
for (int i = 0; i < numStatuses; i++)
{
Image statusImg = new Image(redImage);
statusImg.getElement().getStyle().setMarginRight(3, Unit.PX);
statusImg.getElement().getStyle().setFloat(Float.LEFT);
flowPanel.add(statusImg);
}
flowPanel.add(new InlineLabel(text));
}
/**
* Sets the image displayed for a specific status entry.
*/
public void setStatus(int which, boolean status)
{
Image image = (Image)flowPanel.getWidget(which);
if (status)
image.setResource(greenImage);
else
image.setResource(redImage);
}
}

How to add a css class to the first column of a CellTable widget (GWT)?

I use a CellTable widget in GWT.
I want to change the font size of every texts contained in the first column. The method addColumnStyleName does not fit my need because it adds the class to the colgroup tag; only partial css is handled on this tag, and I can't change the font attributes of a colgroup (it has no incidence on text).
So, I want to add a class on each td of the first column but cannot find an easy way to do that.
Something like setRowStyles for columns would be fine but it doesn't exist...
Have you got some hint about doing such a thing ?
EDIT: I use GWT 2.3 and not 2.4 (which has the method setCellStyleNames)
It's as easy as calling setCellStyleNames on the Column instance.
I finally get it. But I'm not really happy with that solution. It's a bit verbose for a such simple task. I'm opened to any other suggestion.
The way I achieve it is to create a new cell and a new column :
private class KeyColumn extends Column<SimpleLegendItem, String> {
public KeyColumn() {
super(new KeyCell());
}
#Override
public String getValue(SimpleLegendItem item) {
return item.getKey();
}
}
private class KeyCell extends AbstractCell<String> {
#Override
public void render(com.google.gwt.cell.client.Cell.Context context, String value, SafeHtmlBuilder sb) {
sb.appendHtmlConstant("<span class=\"" + tableResources.cellTableStyle().box() + "\">");
sb.appendEscaped(value);
sb.appendHtmlConstant("</span>");
}
}
To simplify the example, I intentionally do not use a template.

Canvas and Click Handlers (GWT)

I'm trying to build a Mind Mapping application within GWT by using RDF to store the Mind Map (I'm using Jena as the RDF Library).
But I'm having to problems:
When I load the map, In java swt theres is a way a canvas draw an string as an image. But with the GWT canvas I can't do that. So, how can I convert an string to an "image" in order to put it within the GWT canvas.
Im have kind of concepts (boxes) displayed within the GWT canvas. Its posible to have a "click handler" that can identify the coordinates there the user clicks the canvas?
Thank you very much for the help :)
1) I noticed the following library which provides font rendering for the GWT Canvas. Hope that helps.
2) In a comment on the GWTCanvas wiki the following code was pasted by 'matt.d.hilliard' (direct linking appears impossible alas):
import com.google.gwt.event.dom.client.HasMouseDownHandlers;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.widgetideas.graphics.client.GWTCanvas;
public class Canvas extends GWTCanvas implements HasMouseDownHandlers {
public Canvas() {
super();
}
public Canvas(int coordX, int coordY) {
super(coordX, coordY);
}
public Canvas(int coordX, int coordY, int pixelX, int pixelY) {
super(coordX, coordY, pixelX, pixelY);
}
public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
return addDomHandler(handler, MouseDownEvent.getType());
}
}