Created
August 29, 2017 20:40
-
-
Save branflake2267/6b375ebd7e70e335f45a6fbab9e18d77 to your computer and use it in GitHub Desktop.
GXT 4 with filter icon.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* FilterStyles.gss file with a filter.png file in the same package*/ | |
.filter { | |
gwt-sprite: "filter"; | |
width: 10px; | |
height: 10px; | |
padding-left: 20px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.Serializable; | |
import java.util.ArrayList; | |
import java.util.Date; | |
import java.util.List; | |
import com.google.gwt.core.client.EntryPoint; | |
import com.google.gwt.core.client.GWT; | |
import com.google.gwt.core.client.Scheduler; | |
import com.google.gwt.core.client.Scheduler.ScheduledCommand; | |
import com.google.gwt.dom.client.Element; | |
import com.google.gwt.dom.client.NodeList; | |
import com.google.gwt.dom.client.Style; | |
import com.google.gwt.editor.client.Editor.Path; | |
import com.google.gwt.event.logical.shared.AttachEvent; | |
import com.google.gwt.event.logical.shared.AttachEvent.Handler; | |
import com.google.gwt.resources.client.ClientBundle; | |
import com.google.gwt.resources.client.CssResource; | |
import com.google.gwt.resources.client.ImageResource; | |
import com.google.gwt.resources.client.ImageResource.ImageOptions; | |
import com.google.gwt.safehtml.shared.SafeHtml; | |
import com.google.gwt.safehtml.shared.SafeHtmlUtils; | |
import com.google.gwt.user.client.rpc.AsyncCallback; | |
import com.google.gwt.user.client.ui.RootLayoutPanel; | |
import com.google.gwt.user.client.ui.Widget; | |
import com.google.gwt.user.datepicker.client.CalendarUtil; | |
import com.sencha.gxt.core.client.GXT; | |
import com.sencha.gxt.core.client.ValueProvider; | |
import com.sencha.gxt.core.client.dom.XElement; | |
import com.sencha.gxt.data.client.loader.RpcProxy; | |
import com.sencha.gxt.data.shared.ListStore; | |
import com.sencha.gxt.data.shared.ModelKeyProvider; | |
import com.sencha.gxt.data.shared.PropertyAccess; | |
import com.sencha.gxt.data.shared.loader.FilterConfig; | |
import com.sencha.gxt.data.shared.loader.FilterPagingLoadConfig; | |
import com.sencha.gxt.data.shared.loader.FilterPagingLoadConfigBean; | |
import com.sencha.gxt.data.shared.loader.LoadResultListStoreBinding; | |
import com.sencha.gxt.data.shared.loader.PagingLoadResult; | |
import com.sencha.gxt.data.shared.loader.PagingLoader; | |
import com.sencha.gxt.widget.core.client.ContentPanel; | |
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer; | |
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer.VerticalLayoutData; | |
import com.sencha.gxt.widget.core.client.container.Viewport; | |
import com.sencha.gxt.widget.core.client.event.ColumnWidthChangeEvent; | |
import com.sencha.gxt.widget.core.client.event.ColumnWidthChangeEvent.ColumnWidthChangeHandler; | |
import com.sencha.gxt.widget.core.client.grid.ColumnConfig; | |
import com.sencha.gxt.widget.core.client.grid.ColumnHeader; | |
import com.sencha.gxt.widget.core.client.grid.ColumnHeader.Head; | |
import com.sencha.gxt.widget.core.client.grid.ColumnModel; | |
import com.sencha.gxt.widget.core.client.grid.Grid; | |
import com.sencha.gxt.widget.core.client.grid.GridView; | |
import com.sencha.gxt.widget.core.client.grid.filters.Filter; | |
import com.sencha.gxt.widget.core.client.grid.filters.GridFilters; | |
import com.sencha.gxt.widget.core.client.grid.filters.StringFilter; | |
import com.sencha.gxt.widget.core.client.toolbar.PagingToolBar; | |
public class GridWithFilteringIcon implements EntryPoint { | |
// provide the icon and css to put the icon to the left of the column header label | |
public interface MyGridResources extends ClientBundle { | |
// access to all resources | |
public static MyGridResources INSTANCE = GWT.create(MyGridResources.class); | |
// css selectors | |
interface FilterStyles extends CssResource { | |
// css style filter selector with sprite | |
String filter(); | |
} | |
// access to css selectors | |
@Source("FilterStyles.gss") | |
FilterStyles styles(); | |
@Source("Filter.png") | |
@ImageOptions(width = 16, height = 16) | |
ImageResource filter(); | |
} | |
public class GridFiltersExt<M> extends GridFilters<M> { | |
public GridFiltersExt(PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Stock>> pagingLoader) { | |
super(pagingLoader); | |
} | |
@Override | |
public void updateColumnHeadings() { | |
// sets the default style | |
super.updateColumnHeadings(); | |
GWT.log("updateColumnHeadings()"); | |
// ~~~ Find the element to add the class name | |
// copied super.updateColumnHeadings() | |
ColumnModel<M> model = grid.getColumnModel(); | |
int cols = model.getColumnCount(); | |
for (int i = 0; i < cols; i++) { | |
ColumnConfig<M, ?> config = model.getColumn(i); | |
if (!config.isHidden()) { | |
ColumnHeader<M> header = grid.getView().getHeader(); | |
if (header != null) { | |
Head h = header.getHead(i); | |
if (h != null && h.isRendered()) { | |
Filter<M, ?> f = getFilter(config.getValueProvider().getPath()); | |
if (f != null) { | |
// ~~~ - add a custom class with icon | |
NodeList<Element> nodes = h.getElement().select("span"); | |
XElement spanElement = nodes.getItem(0).cast(); | |
spanElement.setClassName(MyGridResources.INSTANCE.styles().filter(), f.isActive()); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
public int COUNTER = 0; | |
private ContentPanel panel; | |
private PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Stock>> pagingLoader; | |
private Grid<Stock> grid; | |
private GridFiltersExt<Stock> gridFilters; | |
/** | |
* This is the entry point method. | |
*/ | |
public void onModuleLoad() { | |
Viewport viewport = new Viewport(); | |
viewport.setWidget(asWidget()); | |
RootLayoutPanel.get().add(viewport); | |
} | |
public Widget asWidget() { | |
if (panel == null) { | |
// Inject resources | |
MyGridResources.INSTANCE.styles().ensureInjected(); | |
StockProperties properties = GWT.create(StockProperties.class); | |
SafeHtml label; | |
label = wrapHeaderString("col1"); | |
final ColumnConfig<Stock, String> name = new ColumnConfig<Stock, String>(properties.name(), 60, label); | |
label = wrapHeaderString("col2"); | |
ColumnConfig<Stock, Double> change = new ColumnConfig<Stock, Double>(properties.change(), 80, label); | |
label = wrapHeaderString("col3"); | |
ColumnConfig<Stock, String> industry = new ColumnConfig<Stock, String>(properties.industry(), 80, label); | |
label = wrapHeaderString("col4"); | |
ColumnConfig<Stock, Date> lastUpdated = new ColumnConfig<Stock, Date>(properties.lastTrans(), 80, label); | |
List<ColumnConfig<Stock, ?>> columns = new ArrayList<ColumnConfig<Stock, ?>>(); | |
columns.add(name); | |
columns.add(change); | |
columns.add(industry); | |
columns.add(lastUpdated); | |
ColumnModel<Stock> cm = new ColumnModel<Stock>(columns); | |
cm.addColumnWidthChangeHandler(new ColumnWidthChangeHandler() { | |
@Override | |
public void onColumnWidthChange(ColumnWidthChangeEvent event) { | |
// ~~~ workaround | |
Scheduler.get().scheduleDeferred(new ScheduledCommand() { | |
@Override | |
public void execute() { | |
Scheduler.get().scheduleDeferred(new ScheduledCommand() { | |
@Override | |
public void execute() { | |
gridFilters.updateColumnHeadings(); | |
} | |
}); | |
} | |
}); | |
} | |
}); | |
ListStore<Stock> store = new ListStore<Stock>(properties.key()); | |
final GridView<Stock> gridview = new GridView<Stock>() { | |
@Override | |
public void refresh(boolean headerToo) { | |
super.refresh(headerToo); | |
// ~~~ Workaround | |
gridFilters.updateColumnHeadings(); | |
} | |
}; | |
gridview.setAutoExpandColumn(name); | |
grid = new Grid<Stock>(store, cm, gridview); | |
grid.addAttachHandler(new Handler() { | |
@Override | |
public void onAttachOrDetach(AttachEvent event) { | |
pagingLoader.load(); | |
} | |
}); | |
grid.getView().setColumnHeader(new WordWrapColumnHeader<Stock>(grid, cm)); | |
pagingLoader = getLoader(store); | |
grid.setLoader(pagingLoader); | |
final StringFilter<Stock> nameFilter = new StringFilter<Stock>(properties.name()); | |
gridFilters = new GridFiltersExt<Stock>(pagingLoader); | |
gridFilters.initPlugin(grid); | |
gridFilters.addFilter(nameFilter); | |
VerticalLayoutContainer vlc = new VerticalLayoutContainer(); | |
vlc.add(grid, new VerticalLayoutData(1, 1)); | |
vlc.add(createPagingToolBar(), new VerticalLayoutData(1, -1)); | |
panel = new ContentPanel(); | |
panel.setHeading("Add Icon On Filter Example"); | |
panel.add(vlc); | |
} | |
return panel; | |
} | |
private PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Stock>> getLoader(ListStore<Stock> store) { | |
RpcProxy<FilterPagingLoadConfig, PagingLoadResult<Stock>> dataProxy = new RpcProxy<FilterPagingLoadConfig, PagingLoadResult<Stock>>() { | |
@Override | |
public void load(FilterPagingLoadConfig loadConfig, AsyncCallback<PagingLoadResult<Stock>> callback) { | |
getRpcStocks(loadConfig, callback); | |
} | |
}; | |
final PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Stock>> loader = new PagingLoader<FilterPagingLoadConfig, PagingLoadResult<Stock>>( | |
dataProxy); | |
loader.useLoadConfig(new FilterPagingLoadConfigBean()); | |
loader | |
.addLoadHandler(new LoadResultListStoreBinding<FilterPagingLoadConfig, Stock, PagingLoadResult<Stock>>(store)); | |
loader.setRemoteSort(true); | |
return loader; | |
} | |
public static final String START_HEADER_WRAPPER = "<span style='white-space: normal;'><b>"; | |
public static final String END_HEADER_WRAPPER = "</b></span>"; | |
public static String getHeaderContents(String hdr) { | |
String retString = null; | |
if (hdr != null) { | |
retString = hdr.replace(START_HEADER_WRAPPER, ""); | |
retString = retString.replace(END_HEADER_WRAPPER, ""); | |
} | |
return retString; | |
} | |
protected SafeHtml wrapHeaderString(String untrustedString) { | |
if (untrustedString == null) | |
return null; | |
SafeHtml escapedString = SafeHtmlUtils.fromString(untrustedString); | |
SafeHtml safeHtml = SafeHtmlUtils | |
.fromTrustedString(START_HEADER_WRAPPER + escapedString.asString() + END_HEADER_WRAPPER); | |
return safeHtml; | |
} | |
// ------------------------------------------------------------------------------------------------ | |
// Below are Utility Classes to create Data and a copy of WordWrapColumnHeader from Sencha's website | |
// ------------------------------------------------------------------------------------------------ | |
public class Stock implements Serializable, Comparable<Stock> { | |
private Integer id; | |
private Double change; | |
private Date date = new Date(); | |
private String industry = getType(); | |
private Double last; | |
private String name; | |
private Double open; | |
private String symbol; | |
private boolean split = Boolean.valueOf(Math.random() > .5); | |
public Stock() { | |
this.id = Integer.valueOf(COUNTER++); | |
} | |
public Stock(String name, String symbol, double open, double last, Date date) { | |
this(); | |
this.name = name; | |
this.symbol = symbol; | |
this.change = last - open; | |
this.open = open; | |
this.last = last; | |
this.date = date; | |
} | |
public Double getChange() { | |
return change; | |
} | |
public Integer getId() { | |
return id; | |
} | |
public String getIndustry() { | |
return industry; | |
} | |
public Double getLast() { | |
return last; | |
} | |
public Date getLastTrans() { | |
return date; | |
} | |
public String getName() { | |
return name; | |
} | |
public Double getOpen() { | |
return open; | |
} | |
public double getPercentChange() { | |
return getChange() / getOpen(); | |
} | |
public String getSymbol() { | |
return symbol; | |
} | |
public boolean isSplit() { | |
return split; | |
} | |
public void setChange(Double change) { | |
this.change = change; | |
} | |
public void setId(Integer id) { | |
this.id = id; | |
} | |
public void setIndustry(String industry) { | |
this.industry = industry; | |
} | |
public void setLast(Double last) { | |
this.last = last; | |
} | |
public void setLastTrans(Date date) { | |
this.date = date; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public void setOpen(Double open) { | |
this.open = open; | |
} | |
public void setSplit(boolean split) { | |
this.split = split; | |
} | |
public void setSymbol(String symbol) { | |
this.symbol = symbol; | |
} | |
public String toString() { | |
return getName(); | |
} | |
private String getType() { | |
double r = Math.random(); | |
if (r <= .25) { | |
return "Auto"; | |
} else if (r > .25 && r <= .50) { | |
return "Media"; | |
} else if (r > .5 && r <= .75) { | |
return "Medical"; | |
} else { | |
return "Tech"; | |
} | |
} | |
@Override | |
public int compareTo(Stock o) { | |
return (this.getLastTrans().compareTo(o.getLastTrans())); | |
} | |
} | |
public interface StockProperties extends PropertyAccess<Stock> { | |
@Path("symbol") | |
ModelKeyProvider<Stock> key(); | |
ValueProvider<Stock, String> name(); | |
ValueProvider<Stock, String> symbol(); | |
ValueProvider<Stock, Double> last(); | |
ValueProvider<Stock, Double> change(); | |
ValueProvider<Stock, Date> lastTrans(); | |
ValueProvider<Stock, String> industry(); | |
} | |
private void getRpcStocks(FilterPagingLoadConfig loadConfig, AsyncCallback<PagingLoadResult<Stock>> callback) { | |
final int offset = loadConfig.getOffset(); | |
final int limit = loadConfig.getLimit(); | |
final List<Stock> stocks = getStocks(loadConfig, offset, limit); | |
PagingLoadResult<Stock> result = new PagingLoadResult<Stock>() { | |
@Override | |
public List<Stock> getData() { | |
return stocks; | |
} | |
@Override | |
public void setTotalLength(int totalLength) { | |
} | |
@Override | |
public void setOffset(int offset) { | |
} | |
@Override | |
public int getTotalLength() { | |
return stocks.size(); | |
} | |
@Override | |
public int getOffset() { | |
return offset; | |
} | |
}; | |
callback.onSuccess(result); | |
} | |
public List<Stock> getStocks(FilterPagingLoadConfig loadConfig, int offset, int limit) { | |
List<Stock> stocks = getStocks(loadConfig); | |
if (limit > stocks.size()) { | |
limit = stocks.size() - 1; | |
} | |
List<Stock> subList; | |
try { | |
subList = stocks.subList(offset, offset + limit); | |
} catch (Exception e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
// Oops | |
subList = new ArrayList<Stock>(); | |
} | |
return subList; | |
} | |
private List<Stock> getStocks(FilterPagingLoadConfig loadConfig) { | |
Date d1 = new Date(); | |
Date d2 = new Date(); | |
CalendarUtil.addDaysToDate(d2, 2); | |
String filter = getFilter(loadConfig); | |
List<Stock> stocks = new ArrayList<Stock>(); | |
for (int i = 0; i < 1000; i++) { | |
Stock stock = new Stock("i=" + i, "ai=" + i, 125.64, 123.43, d1); | |
if (filter != null && stock.getName().contains(filter)) { | |
stocks.add(stock); | |
} else if (filter == null) { | |
stocks.add(stock); | |
} | |
} | |
return stocks; | |
} | |
private String getFilter(FilterPagingLoadConfig loadConfig) { | |
List<FilterConfig> filters = loadConfig.getFilters(); | |
if (filters == null || filters.isEmpty()) { | |
return null; | |
} | |
FilterConfig fc = filters.get(0); | |
String filter = fc.getValue(); | |
return filter; | |
} | |
private PagingToolBar createPagingToolBar() { | |
PagingToolBar toolBar = new PagingToolBar(50); | |
toolBar.bind(pagingLoader); | |
return toolBar; | |
} | |
/** | |
* A {@link Grid} {@link ColumnHeader} that supports word wrap, enabling long column headings to be displayed in | |
* multiple rows. Provides options for letting the height of the header default to the height of the tallest heading, | |
* or to be manually set to a specific pixel value. | |
* <p /> | |
* In order for a heading to word wrap, the heading must be set to HTML that enables word wrap, e.g. | |
* <code><span style='white-space: normal;'>A very long heading</span></code>. | |
*/ | |
public class WordWrapColumnHeader<M> extends ColumnHeader<M> { | |
protected class WordWrapHead extends ColumnHeader<M>.Head { | |
@SuppressWarnings({ "rawtypes" }) | |
public WordWrapHead(ColumnConfig column) { | |
super(column); | |
getElement().getStyle().setFloat(Style.Float.NONE); | |
} | |
} | |
private int fixedHeight = -1; | |
/** | |
* Constructs a new word wrap column header for the specified grid and column model. To configure the grid to use | |
* the new word wrap column header, invoke {@link GridView#setColumnHeader(ColumnHeader)}, e.g. | |
* <code>grid.getView().setColumnHeader(new WordWrapColumnHeader<T>(g, cm)</code>. | |
* | |
* @param container | |
* - the grid that contains this word wrap column header | |
* @param cm | |
* - the column model that provides the configuration for this column header | |
*/ | |
public WordWrapColumnHeader(Grid<M> container, ColumnModel<M> cm) { | |
super(container, cm); | |
} | |
/** | |
* Sets the height of the word wrap column header to a specific value. Generally this is not required as the column | |
* header sizes itself to the height of the tallest heading. However, there are some use cases where the column | |
* header height must be set (e.g. linked grids displayed side-by-side, where the column header height of one grid | |
* must match that of the other). | |
* | |
* @param newHeight | |
* the height of the column header, or -1 to resize the header to the height of it's tallest heading (i.e. | |
* it's "natural" height) | |
*/ | |
@Override | |
public void setHeight(int newHeight) { | |
if (GXT.isIE()) { | |
getElement().getOffsetParent().setScrollTop(0); | |
} | |
// Do not forward to base class... the parent element must remain unsized | |
fixedHeight = newHeight; | |
if (newHeight == -1) { | |
setNaturalHeight(); | |
} else { | |
setFixedHeight(newHeight); | |
} | |
super.checkHeaderSizeChange(); | |
} | |
@Override | |
protected void checkHeaderSizeChange() { | |
onHeaderSizeChange(); | |
super.checkHeaderSizeChange(); | |
} | |
@Override | |
@SuppressWarnings("rawtypes") | |
protected Head createNewHead(ColumnConfig config) { | |
return new WordWrapHead(config); | |
} | |
private int getContentHeight() { | |
int height = 0; | |
int columnCount = cm.getColumnCount(); | |
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { | |
if (!cm.isHidden(columnIndex)) { | |
Head head = getHead(columnIndex); | |
XElement inner = head.getElement(); | |
height = Math.max(height, inner.getOffsetHeight()); | |
} | |
} | |
// adjust to allow space for sort icon | |
height += 5; | |
return height; | |
} | |
private void onHeaderSizeChange() { | |
if (fixedHeight == -1) { | |
setNaturalHeight(); | |
} else { | |
setFixedHeight(fixedHeight); | |
} | |
} | |
private void setFixedHeight(int newHeight) { | |
int offsetHeight = getOffsetHeight(); | |
int contentHeight = getContentHeight(); | |
int deltaHeight = offsetHeight - contentHeight; | |
newHeight -= deltaHeight; | |
overrideHeaderHeight = newHeight; | |
refresh(); | |
} | |
private void setNaturalHeight() { | |
overrideHeaderHeight = -1; | |
refresh(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Icon used
![filter](https://user-images.githubusercontent.com/1326504/29843082-a54e386c-8cbf-11e7-9d9b-6f95ebc443e5.png)