PDA

View Full Version : Custom CheckBoxSelectionModel - change default icon



grandanat
12 Apr 2010, 7:07 AM
Simplified problem:
I have a grid with a CheckBoxSelectionModel and i want to change default checkbox icons with my own, programmatically. Basically i think the best solution would be to extend gxt CheckBoxSelectionModel class and create a method setIcon(String imageUrl) that points to my image. I tried following code in my CustomCheckBoxSelectionModel ctor but it dowsn't work properly, it just append my image right to default image.


public CustomCheckBoxSelectionModel(String myImage) {
super();
this.getColumn().setRenderer(new GridCellRenderer<M>() {
public String render(M model, String property, ColumnData config, int rowIndex, int colIndex, ListStore<M> store,
Grid<M> grid) {
config.cellAttr = "rowspan='2'";
config.style = "background-image: url(" + myImage + ");";
return "<div class='x-grid3-row-checker'> </div>";
}
});
}
I just want to replace this image :


.x-grid3-row-checker, .x-grid3-hd-checker {
background-image:url(../images/default/grid/row-check-sprite.gif);
}
With my own one. Can anyone advice me how to approach the problem ?


Extended problem.
If i want to use a larger image then toggle selection area will have to be increased. Although size of this area is defined din css file. How do i change it dynamically in code ? I don;t want to override css, since i don;t want to apply this change to all grids that uses a checkbox selection model.
Another abandoned solution was to use a custom identifier instead of checker



void replaceDivs() {
grid.addListener(Events.ViewReady, new Listener<ComponentEvent>() {
@Override
public void handleEvent(ComponentEvent be) {

El header = grid.getView().getHeader().el();
El headerBody = header.getChild(1);
header.setInnerHtml(header.getInnerHtml().replace("-checker", "-mychecker"));
El hdc = headerBody.child("div.x-grid3-hd-checker");
if (hdc != null) {
hdc.child("x-grid3-hd-checker");
hdc.getId();
hdc.getParent().setStyleName(hdc.getParent().getStyleName().replace("-checker", "-mychecker"));
hdc.getChild(0).getParent().setStyleName(
hdc.getChild(0).getParent().getStyleName().replace("-checker", "-mychecker"));
}
}
});
}

This solution worked better but is not really ok. i shouldn't have different different css classes for same thing(even icons are different).

grandanat
13 Apr 2010, 4:53 AM
After one more day i've progressed but still not have a full working solution.
At this point all i have to change only background-position for "selected" image (checker-on)
So, i set my custom image to header( in constructor)


this.getColumn().setRenderer(new GridCellRenderer<M>() {
public String render(M model, String property, ColumnData config, int rowIndex, int colIndex, ListStore<M> store,
Grid<M> grid) {
config.cellAttr = "rowspan='2'";
return "<div class='x-grid3-row-checker' style=' height: " + (imageSize + 2 * 2) + "px; background-image: " + imageURL + "; '>&#160;</div>";
}
});

I set my image to rows after ViewReady event

El hdc = grid.getView().getHeader().el().getChild(1).child("div.x-grid3-hd-checker");
hdc.dom.getStyle().setBackgroundImage(imageURL);
, change checker size according to row height and place image in center to look nice

hdc.setStyleAttribute("height", this.rowHeight - 2);
this.padding = (this.rowHeight - 2 - this.imageSize)/2;
hdc.setStyleAttribute("background-position", padding + "px " + padding + "px");


THE PROBLEM:
When a selection is changed, html structure is builded dynamically in code(in CheckBoxSelectionModel implementation)



private void setChecked(boolean checked) {
if (grid.isViewReady()) {
El hd = grid.getView().innerHd.child("div.x-grid3-hd-checker");
if (hd != null) {
hd.getParent().setStyleName("x-grid3-hd-checker-on", checked);
}
}
}

After this call html element checker is replaced with checke checker-on. and the new background-position value is taken from css, to display checked image.



.x-grid3-row-selected .x-grid3-row-checker,.x-grid3-hd-checker-on .x-grid3-hd-checker,.x-grid3-row-checked .x-grid3-row-checker
{
background-position: -23px 2px;
}


Now the problem is that offset my image has other value (my images are larger) so i haven't access to this css checker-on background-position to change it. So i have to change it but i don't know how. Any advice will be more than welcome.

Another question would be if my approach is correct, to change css values programmatically in the code? Unfortunately I didn't a better solution.

grandanat
14 Apr 2010, 4:55 AM
Adopted solution:



package mypackage.controls;

import com.extjs.gxt.ui.client.core.El;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.StoreEvent;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.grid.CheckBoxSelectionModel;
import com.extjs.gxt.ui.client.widget.grid.ColumnData;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;

public class CustomCheckBoxSelectionModel<M extends ModelData> extends CheckBoxSelectionModel<M> {

protected String imageURL = "url(\"/res/images/selectColumnModel.gif\")";
protected int imageSize = 24;
protected int padding = 2;
protected int leftPadding = padding;
protected int rowHeight = imageSize + padding * 2;

public CustomCheckBoxSelectionModel(String image, int size) {
super();
this.imageURL = image;
this.imageSize = size;
this.rowHeight = this.imageSize + padding * 2;
initConfig();
}

public CustomCheckBoxSelectionModel() {
super();
initConfig();
}

private void initConfig() {
this.getColumn().setId("checker");
this.getColumn().setWidth(rowHeight + 2);
this.getColumn().setRenderer(new GridCellRenderer<M>() {
public String render(M model, String property, ColumnData config, int rowIndex, int colIndex, ListStore<M> store,
Grid<M> grid) {
config.cellAttr = "rowspan='2'";
return "<div class='x-grid3-row-checker' style=' height: " + rowHeight + "px; background-image: " + imageURL
+ "; '> </div>";
}
});
}

@Override
public void init(Component component) {
super.init(component);
modifyElement();
}

private void modifyElement() {
grid.addListener(Events.ViewReady, new Listener<ComponentEvent>() {
@Override
public void handleEvent(ComponentEvent be) {
replaceBackgroundImage();
}
});
}

void replaceBackgroundImage() {

El hdc = grid.getView().getHeader().el().getChild(1).child("div.x-grid3-hd-checker");
hdc.dom.getStyle().setBackgroundImage(imageURL);
hdc.setStyleAttribute("height", this.rowHeight - 2);
hdc.setStyleAttribute("background-position", padding + "px " + padding + "px");
}

@Override
protected void onSelectChange(M model, boolean select) {
super.onSelectChange(model, select);

if (grid.isViewReady()) {
boolean change = getSelection().size() == grid.getStore().getCount();
changeHeaderOffset(change);
changeRowOffset(grid.getStore().indexOf(model), change);
}
}

@Override
protected void onClear(StoreEvent<M> se) {
super.onClear(se);
changeHeaderOffset(false);
}

private void changeHeaderOffset(boolean select) {
if (select/* && leftPadding == padding */) {
leftPadding = padding - 12 - imageSize;
} else/* if(leftPadding != padding) */{
leftPadding = padding;
}

El hdc = grid.getView().getHeader().el().getChild(1).child("div.x-grid3-hd-checker");
hdc.setStyleAttribute("background-position", leftPadding + "px " + padding + "px");
}

private void changeRowOffset(int index, boolean select) {

El hdr = El.fly(grid.getView().getRow(index)).child("div.x-grid3-row-checker");
int itemPadding = padding;
if (isSelected(grid.getStore().getAt(index))) {
itemPadding = padding - 12 - imageSize;
}

hdr.setStyleAttribute("background-position", itemPadding + "px " + padding + "px");

}

}
Please feel free to make any comments or suggestions.