Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.wiquery.plugin.antilia.grid; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; import org.apache.wicket.ResourceReference; import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.IAjaxIndicatorAware; import org.apache.wicket.feedback.IFeedback; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.RefreshingView; import org.apache.wicket.markup.repeater.RepeatingView; import org.apache.wicket.markup.repeater.data.IDataProvider; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IComponentInheritedModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.protocol.http.WebRequestCycle; import org.odlabs.wiquery.core.commons.IWiQueryPlugin; import org.odlabs.wiquery.core.commons.WiQueryResourceManager; import org.odlabs.wiquery.core.javascript.JsStatement; import org.odlabs.wiquery.ui.commons.WiQueryUIPlugin; import com.wiquery.plugin.antilia.grid.model.IColumn; import com.wiquery.plugin.antilia.grid.resources.DefaultStyle; /** * * @author Ernesto Reinaldo Barreiro (reiern70@gmail.com) */ @WiQueryUIPlugin public class Table<E extends Serializable> extends Panel implements IPageableComponent<E>, IPageableNavigationListener, IWiQueryPlugin, IAjaxIndicatorAware { private static final long serialVersionUID = 1L; public static final int AUTO = -1; private ITableModel<E> tableModel; /** * Component used to display navigation errors */ private IFeedback feedback; private FirstColumnModel firstColumnModel; private List<WebMarkupContainer> rowCheckboxes = new ArrayList<WebMarkupContainer>(); private List<IPageableNavigationListener> navigationListeners = new ArrayList<IPageableNavigationListener>(); /** * Flag to set first column re-sizable or not. */ private boolean firstColumnResizable = true; /** * Flag to set all columns re-sizable or not. */ private boolean columnsResizable = true; /** * This variable is needed t fix a problem with drag and drop not working for IE */ private int rendringCount = 0; /** * True to keep selection when navigating (the default). False to clear it. */ private boolean keepSelectionOnNavigation = true; /** * Flag to disable/enable column draggability. */ private boolean dragableColumns = true; /** * The page size. */ private int pageSize = 10; /** * The current page; */ private int currentPage = 0; private int size = -1; private int numberOfPages; /** * The data provider used to retrieve grid's data. */ private IDataProvider<E> dataProvider; private List<IModel<E>> rowModels; /** * Table height. */ private int height = AUTO; /** * Table width */ private int width = AUTO; /** * AJAX behavior used to process some of the client side event on * the server side. */ private AbstractDefaultAjaxBehavior tableEventContext; /** * Constructor. * * @param id */ public Table(String id, ITableModel<E> tableModel, IDataProvider<E> dataProvider) { super(id); this.dataProvider = dataProvider; setOutputMarkupId(true); add(tableEventContext = new AbstractDefaultAjaxBehavior() { private static final long serialVersionUID = 1L; @Override protected void respond(AjaxRequestTarget target) { if (target != null) { String targetId = WebRequestCycle.get().getRequest().getParameter("targetId"); if (targetId != null && targetId.equals("resize")) { try { int width = Integer .parseInt(WebRequestCycle.get().getRequest().getParameter("sourceId")); int column = Integer .parseInt(WebRequestCycle.get().getRequest().getParameter("number")); if (column == 0) { Table.this.getFirstColumnModel().setWidth(width); } else { Table.this.getTableModel().getColumnModel(column - 1).setWidth(width); } } catch (NumberFormatException e) { // do nothing } return; } } } }); this.tableModel = tableModel; this.firstColumnModel = newFirstColumnModel(); } /** * Factory method for the firts column. * @return */ protected FirstColumnModel newFirstColumnModel() { return new FirstColumnModel(40); } @Override protected void onBeforeRender() { rendringCount++; if (pageSize <= 0) { pageSize = 10; } if (size == -1) { size = dataProvider.size(); numberOfPages = (size / pageSize) + ((size % pageSize == 0) ? 0 : 1); } WebMarkupContainer tRoot = new WebMarkupContainer("tRoot"); addOrReplace(tRoot); tRoot.add(new AttributeModifier("style", new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { String height = "auto"; if (Table.this.height > 0) height = Table.this.height + "px;"; String width = "auto;"; if (Table.this.width > 0) width = Table.this.width + "px;"; return new StringBuilder().append("position: relative; width: ").append(width).append(";height:") .append(height).toString(); } })); WebMarkupContainer tHead = new WebMarkupContainer("tHead"); tRoot.addOrReplace(tHead); tHead.add(new AttributeModifier("style", new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { String width = "auto;"; if (Table.this.width > 0) width = Table.this.width + 2 + "px;"; return new StringBuilder().append("width:").append(width).toString(); } })); tHead.addOrReplace(newTableHeader("header")); WebMarkupContainer tBody = new WebMarkupContainer("tBody") { private static final long serialVersionUID = 1L; @Override public String getMarkupId() { return Table.this.getMarkupId() + "_tBody"; } @Override public boolean isVisible() { return size > 0; } }; tBody.setOutputMarkupId(true); tBody.add(new AttributeModifier("style", new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { String height = "auto;"; if (Table.this.height > 0) height = (Table.this.height - 28) + "px;"; String width = "auto;"; if (Table.this.width > 0) width = (Table.this.width) + "px;"; return new StringBuilder().append("position: relative; width: ").append(width) .append("; overflow: hidden; height: ").append(height).append(" vertical-align: top") .toString(); } })); tRoot.addOrReplace(tBody); WebMarkupContainer tTHeader = new WebMarkupContainer("tTHeader") { private static final long serialVersionUID = 1L; @Override public String getMarkupId() { return Table.this.getMarkupId() + "_tTH"; } }; tTHeader.setOutputMarkupId(true); tBody.add(tTHeader); WebMarkupContainer tNoRecords = new WebMarkupContainer("tNoRecords") { private static final long serialVersionUID = 1L; @Override public boolean isVisible() { return size <= 0; } }; tNoRecords.add(new AttributeModifier("style", new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { String width = "auto;"; if (Table.this.width > 0) width = Table.this.width + "px;"; return new StringBuilder().append("width: ").append(width).append(";").toString(); } })); tRoot.add(tNoRecords); WebMarkupContainer tTBody = new WebMarkupContainer("tTBody") { private static final long serialVersionUID = 1L; @Override public String getMarkupId() { return Table.this.getMarkupId() + "_tTB"; } }; tTBody.add(new AttributeModifier("onscroll", new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { return new StringBuilder().append("var t = document.getElementById('") .append(Table.this.getMarkupId() + "_tTH") .append("'); t.style.left=(-this.scrollLeft)+'px'").toString(); } })); tTBody.setOutputMarkupId(true); tBody.add(tTBody); // add table header tTHeader.addOrReplace(getHeaderRows("hcols")); // add table body tTBody.addOrReplace(getBodyRows("rows")); WebMarkupContainer tFoot = new WebMarkupContainer("tFoot"); tFoot.add(new AttributeModifier("style", new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { String width = "auto;"; if (Table.this.width > 0) width = "100%;"; return new StringBuilder().append("width:").append(width).toString(); } })); tRoot.addOrReplace(tFoot); super.onBeforeRender(); } public JsStatement statement() { String tableId = Table.this.getMarkupId() != null ? Table.this.getMarkupId() : "table"; StringBuffer sb = new StringBuffer(); sb.append("new Table('" + tableId + "','"); sb.append(tableEventContext.getCallbackUrl() + "',"); sb.append("new Array("); Iterator<IModel<E>> it = getCurrentPage(); int i = 0; while (it.hasNext()) { boolean selected = isSelected(it.next().getObject()); sb.append("new Row('"); sb.append(tableId); sb.append("',"); sb.append(i); sb.append(","); sb.append(selected); sb.append(")"); if (it.hasNext()) sb.append(","); i++; } sb.append(")"); sb.append("," + (Table.this.getTableModel().getColumns() + 1)); sb.append("," + (Table.this.getRendringCount())); sb.append("," + "false"); sb.append("," + Table.this.isDragableColumns()); sb.append(",'"); sb.append(getString("antilia.grid.loading")); sb.append("'"); sb.append(");"); JsStatement jsStatement = new JsStatement().append(sb.toString()); return jsStatement; } public void contribute(WiQueryResourceManager wiQueryResourceManager) { ResourceReference css = getTableCSS(); if (css != null) wiQueryResourceManager.addCssResource(css); wiQueryResourceManager.addJavaScriptResource(DefaultStyle.JS_TABLE); } protected ResourceReference getTableCSS() { return DefaultStyle.CSS_TABLE; } protected RefreshingView<E> getHeaderRows(String id) { return new HeaderRows(id, this); } protected RefreshingView<E> getBodyRows(String id) { return new BodyRows(id, this); } private class HeaderRows extends RefreshingView<E> { private static final long serialVersionUID = 1L; private Table<E> table; public HeaderRows(String id, Table<E> table) { super(id); this.table = table; } @Override protected Iterator<IModel<E>> getItemModels() { ITableModel<E> tableModel = getTable().getTableModel(); List<IModel<E>> models = new ArrayList<IModel<E>>(); models.add(new Model<E>(null)); Iterator<IColumn<E>> it = tableModel.getColumnModels(); while (it.hasNext()) { IModel<E> model = it.next(); models.add(model); } return models.iterator(); } @Override protected Item<E> newItem(String id, int index, final IModel<E> model) { Item<E> item = super.newItem(id, index, model); String tableId = table.getMarkupId(); if (model instanceof IColumn<?>) { final IColumn<E> column = (IColumn<E>) model; item.add(new AttributeModifier("id", new Model<String>(tableId + "_tdh_" + index))); item.add(new AttributeModifier("width", true, new Model<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { String width = column.getWidth() + "px"; return width; } })); item.add(new AttributeModifier("onmouseover", true, new Model<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { if (column.isSortable()) return "this.className='ui-state-default ui-state-hover defaultHeaderOver sortableCol';"; return "this.className='ui-state-default ui-state-hover defaultHeaderOver';"; } })); item.add(new AttributeModifier("onmouseout", true, new Model<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { if (column.isSortable()) return "this.className='ui-state-default defaultHeader sortableCol';"; return "this.className='ui-state-default defaultHeader';"; } })); //onmouseover="this.className='ui-state-default ui-state-hover defaultHeaderOver';" //onmouseout="this.className='ui-state-default defaultHeader';" } else { item.add(new AttributeModifier("id", new Model<String>(tableId + "_tdh_0"))); item.add(new AttributeModifier("width", new Model<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { String width = Table.this.getFirstColumnModel().getWidth() + "px"; return width; } })); } return item; } @Override protected void populateItem(Item<E> item) { IModel<E> model = (IModel<E>) item.getModel(); if (model instanceof IColumn<?>) { IColumn<E> column = (IColumn<E>) model; //item.add(Table.this.newHeaderCell("hcell", item.getIndex(), getTable(), columnModel, columnModel.getTableModel().getBeanClass())); //item.add(columnModel.populateHeaderCell("hcell", item.getIndex(), getTable())); column.populateHeaderCell(item, "hcell", item.getIndex(), getTable()); } else { item.add(Table.this.newFirstHeaderCell("hcell", item.getIndex(), getTable())); } } private Table<E> getTable() { return table; } } protected void addRowCheckBox(WebMarkupContainer rowCheckBox) { rowCheckboxes.add(rowCheckBox); } protected void clearRowCheckBoxes() { rowCheckboxes.clear(); } protected Iterator<WebMarkupContainer> getRowCheckBoxes() { return rowCheckboxes.iterator(); } /** * Called when a row is clicked. * @param target * @param row */ protected void onRowClickedEvent(AjaxRequestTarget target, int row, E bean, boolean selected) { } private class BodyRows extends RefreshingView<E> { private static final long serialVersionUID = 1L; private List<IModel<E>> models; private Table<E> table; public BodyRows(String id, Table<E> table) { super(id); this.table = table; } private void initializeMe() { Table.this.clearRowCheckBoxes(); models = new ArrayList<IModel<E>>(); ITableModel<E> tableModel = getTable().getTableModel(); if (tableModel == null) return; Iterator<IModel<E>> it = getTable().getCurrentPage(); while (it.hasNext()) { IModel<E> object = it.next(); models.add(tableModel.newModel(object)); } } @Override protected Item<E> newItem(String id, int index, IModel<E> model) { return new RowItem<E>(id, index, (IComponentInheritedModel<E>) model, table); } @Override protected Iterator<IModel<E>> getItemModels() { initializeMe(); return models.iterator(); } @Override protected void populateItem(Item<E> item) { ITableModel<E> tableModel = getTable().getTableModel(); if (tableModel == null) return; RepeatingView rowView = new RepeatingView("cols"); item.add(rowView); String tableId = table.getMarkupId(); RowItem<E> rowItem = (RowItem<E>) item; Iterator<IColumn<E>> it = tableModel.getColumnModels(); E bean = item.getModelObject(); Item<E> cellItem = new Item<E>(rowView.newChildId(), 1); rowView.add(cellItem); cellItem.add(newFirstBodyCell("cell", item.getIndex(), getTable(), rowItem)); if (rowItem.getIndex() == 0) { cellItem.add(new AttributeModifier("id", new Model<String>(tableId + "_tdb_0"))); cellItem.add(new AttributeModifier("width", true, new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { String width = getTable().getFirstColumnModel().getWidth() + "px"; return width; } })); } String cssClass = "ui-widget-content tbodycol"; cellItem.add(new AttributeModifier("class", new Model<String>(cssClass))); // Populate the row int column = 1; while (it.hasNext()) { final IColumn<E> columnModel = it.next(); cellItem = new Item<E>(rowView.newChildId(), 1); rowView.add(cellItem); columnModel.populateRowCell(cellItem, "cell", bean, item.getIndex(), column); if (rowItem.getIndex() == 0) { cellItem.add(new AttributeModifier("id", new Model<String>(tableId + "_tdb_" + column))); cellItem.add(new AttributeModifier("width", true, new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { String width = columnModel.getWidth() + "px"; return width; } })); } cssClass = "ui-widget-content tbodycol " + columnModel.getBodyAddionalCssClasses(); cellItem.add(new AttributeModifier("class", new Model<String>(cssClass))); //class="ui-widget-content tbodycol" column++; } } private Table<E> getTable() { return table; } } /** * Creates the table header. Override if you want to provide * a different header. * * @param id * @return */ protected Panel newTableHeader(String id) { return new DefaultTableHeader<E>(id, this); } protected WebMarkupContainer newFirstBodyCell(String id, int row, Table<E> table, RowItem<E> item) { return new FirstBodyCell<E>(id, row, table, item); } protected WebMarkupContainer newFirstHeaderCell(String id, int index, Table<E> table) { return new FirstHeaderCell<E>(id, index, table); } /** * @return the tableModel */ public ITableModel<E> getTableModel() { return tableModel; } public FirstColumnModel getFirstColumnModel() { return firstColumnModel; } public void setFirstColumnModel(FirstColumnModel firstColumnModel) { this.firstColumnModel = firstColumnModel; } public Component getUpdatableComponent() { return this; } /** * @return the rendringCount */ public int getRendringCount() { return rendringCount; } /** * @param rendringCount the rendringCount to set */ public void setRendringCount(int rendringCount) { this.rendringCount = rendringCount; } /** * @return the feedback */ public IFeedback getFeedback() { return feedback; } /** * @param feedback the feedback to set */ public void setFeedback(IFeedback feedback) { this.feedback = feedback; } public boolean isFirstColumnResizable() { return firstColumnResizable; } public void setFirstColumnResizable(boolean firstColumnResizable) { this.firstColumnResizable = firstColumnResizable; } public boolean isColumnsResizable() { return columnsResizable; } public void setColumnsResizable(boolean columnsResizable) { this.columnsResizable = columnsResizable; } public void addNavigationListener(IPageableNavigationListener listener) { navigationListeners.add(listener); } public void removeNavigationListener(IPageableNavigationListener listener) { navigationListeners.remove(listener); } public final void onFirstPage(AjaxRequestTarget target) { firstPage(target); for (IPageableNavigationListener listener : navigationListeners) { listener.onFirstPage(target); } } /** * Override this method to do something when first page button is clicked. * * @param target */ public void firstPage(AjaxRequestTarget target) { } public final void onGoToPage(AjaxRequestTarget target, int page) { gotoPage(target, page); for (IPageableNavigationListener listener : navigationListeners) { listener.onGoToPage(target, page); } } /** * Override this method to do something when an intermadiate page link is clicked. * * @param target */ public void gotoPage(AjaxRequestTarget target, int page) { } public final void onLastPage(AjaxRequestTarget target) { lastPage(target); for (IPageableNavigationListener listener : navigationListeners) { listener.onLastPage(target); } } /** * Override this method to do something when last page button is clicked. * * @param target */ public void lastPage(AjaxRequestTarget target) { } public final void onNextPage(AjaxRequestTarget target) { nextPage(target); for (IPageableNavigationListener listener : navigationListeners) { listener.onNextPage(target); } } /** * Override this method to do something when next page button is clicked. * * @param target */ public void nextPage(AjaxRequestTarget target) { } public final void onPreviousPage(AjaxRequestTarget target) { previousPage(target); for (IPageableNavigationListener listener : navigationListeners) { listener.onPreviousPage(target); } } /** * Override this method to do something when previous page button is clicked. * * @param target */ public void previousPage(AjaxRequestTarget target) { } /** * @return the keepSelectionOnNavigation */ public boolean isKeepSelectionOnNavigation() { return keepSelectionOnNavigation; } /** * @param keepSelectionOnNavigation the keepSelectionOnNavigation to set */ public void setKeepSelectionOnNavigation(boolean keepSelectionOnNavigation) { this.keepSelectionOnNavigation = keepSelectionOnNavigation; } /** * @return the dragableColumns */ public boolean isDragableColumns() { return dragableColumns; } /** * @param dragableColumns the dragableColumns to set */ public void setDragableColumns(boolean dragableColumns) { this.dragableColumns = dragableColumns; } public boolean hasNextPage() { return (currentPage + 1) < numberOfPages; } public boolean hasPreviousPage() { return currentPage > 0; } public void nextPage() { currentPage++; rowModels = null; } public void previousPage() { currentPage--; rowModels = null; } public Iterator<IModel<E>> getCurrentPage() { //TODO: delete collection after rendering if (rowModels == null || rowModels.size() == 0) { rowModels = new ArrayList<IModel<E>>(); int start = currentPage * pageSize; Iterator<? extends E> it = this.dataProvider.iterator(start, pageSize); while (it.hasNext()) { rowModels.add(dataProvider.model(it.next())); } } return rowModels.iterator(); } public boolean isSelected(E bean) { // TODO Auto-generated method stub return false; } public void firstPage() { currentPage = 0; rowModels = null; } public void lastPage() { currentPage = numberOfPages - 1; rowModels = null; } public void goToPage(int page) { if (page >= 0 && page < numberOfPages) { currentPage = page; rowModels = null; } } public boolean containsData() { return getCurrentPage().hasNext(); } public int currentPageNumber() { return currentPage; } public int getNumberOfPages() { return numberOfPages; } public int getPageSize() { return pageSize; } public void reset() { this.size = -1; firstPage(); } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public IDataProvider<E> getDataProvider() { return dataProvider; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public String getAjaxIndicatorMarkupId() { return getMarkupId() + "_loading"; } }