/** * Copyright 2008-2016 Qualogy Solutions B.V. * * Licensed 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.qualogy.qafe.gwt.client.component; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.gwt.mosaic.ui.client.MessageBox.MessageBoxType; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.gen2.event.dom.client.ScrollEvent; import com.google.gwt.gen2.event.dom.client.ScrollHandler; import com.google.gwt.gen2.table.client.ColumnDefinition; import com.google.gwt.gen2.table.client.DefaultTableDefinition; import com.google.gwt.gen2.table.client.FixedWidthFlexTable; import com.google.gwt.gen2.table.client.FixedWidthGrid; import com.google.gwt.gen2.table.client.PagingScrollTable; import com.google.gwt.gen2.table.client.TableDefinition; import com.google.gwt.gen2.table.client.TableModel; import com.google.gwt.gen2.table.client.TableModel.Callback; import com.google.gwt.gen2.table.client.TableModelHelper.Request; import com.google.gwt.gen2.table.client.TableModelHelper.Response; import com.google.gwt.gen2.table.event.client.RowSelectionEvent; import com.google.gwt.gen2.table.event.client.RowSelectionHandler; import com.google.gwt.gen2.table.event.client.TableEvent.Row; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.UIObject; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.qualogy.qafe.gwt.client.context.ClientApplicationContext; import com.qualogy.qafe.gwt.client.ui.renderer.AbstractComponentRenderer.MessageBox; import com.qualogy.qafe.gwt.client.ui.renderer.DataGridFactory; import com.qualogy.qafe.gwt.client.util.QAMLConstants; import com.qualogy.qafe.gwt.client.util.QAMLUtil; import com.qualogy.qafe.gwt.client.vo.functions.DataContainerGVO; import com.qualogy.qafe.gwt.client.vo.functions.SetValueGVO; import com.qualogy.qafe.gwt.client.vo.functions.execute.SetValueExecute; import com.qualogy.qafe.gwt.client.vo.ui.DataGridColumnGVO; import com.qualogy.qafe.gwt.client.vo.ui.DataGridGVO; public class QPagingScrollTable extends PagingScrollTable<DataContainerGVO> implements HasDataGridMethods, RowSelectionHandler, ResultHandler, ScrollHandler, HasRowSelectionChangeHandlers { private static final Logger logger = Logger.getLogger(QPagingScrollTable.class.getName()); public static final String MSG_LAST_PAGE = "You reached the last page"; protected int qCurrentPage = 0; protected Boolean hasPredefinedPageSize = false; private List<Integer> rememberSelectedRows = null; private List<DataContainerGVO> initialData = new ArrayList<DataContainerGVO>(); private boolean resetInitialData = true; private String uuid; private String parent; private QPagingOptions pagingOptions; private QPagingScrollTableOperation pagingScrollTableOperations; private Widget overflow; private DataGridGVO source = null; private boolean autoGeneratedColumns = false; private int scrollPosition; private boolean scrollEvent = false; private final Map<String, List<String>> groupedColumns = new HashMap<String, List<String>>(); private final Map<String, SetValueGVO> dropDownColumnAndValues = new HashMap<String, SetValueGVO>(); private Element qHeaderWrapper; private boolean refreshingExistingRows = false; private final List<RowSelectionChangeHandler> rowSelectionChangeHandlers = new ArrayList<RowSelectionChangeHandler>(); @Override public void setVisible(final boolean visible) { super.setVisible(visible); if (pagingOptions!=null){ pagingOptions.setVisible(visible && !source.getPageScroll()); } if (pagingScrollTableOperations!=null){ pagingScrollTableOperations.setVisible(visible); } if (overflow!=null){ overflow.setVisible(visible); } } public DataGridGVO getSource() { return source; } public boolean hasOverflow() { return (overflow != null); } public QPagingScrollTable(final TableModel<DataContainerGVO> tableModel, final FixedWidthGrid dataTable, final FixedWidthFlexTable headerTable, final TableDefinition<DataContainerGVO> tableDefinition, final DataGridGVO vo, final String uuid, final String parent) { super(tableModel, dataTable, headerTable, tableDefinition); initParameters(vo, uuid, parent); // Listen for selection events dataTable.addRowSelectionHandler(this); } public QPagingScrollTable(final TableModel<DataContainerGVO> tableModel, final TableDefinition<DataContainerGVO> tableDefinition, final DataGridGVO vo, final String uuid, final String parent) { super(tableModel, tableDefinition); initParameters(vo, uuid, parent); } private void initParameters(final DataGridGVO vo, final String uuid, final String parent) { this.source = vo; this.uuid = uuid; this.parent = parent; if (this.source != null) { this.autoGeneratedColumns = (this.source.getColumns() == null) || (this.source.getColumns().length == 0); } // SpreadsheetCell needs to know the parentContainer. So after the constructor is executed we have to // create tableDefinition with this object as parent for later use and pass the tableDefinition to super class. createTableDefinition(); // WORKAROUND: // In IE, when a datagrid has only one visible column (including the rowNumber column), // that column will shrink each time data is set to the datagrid, // so changing the width from "100%" to "1px", overflow from "hidden" to "visible" will avoid this problem final String userAgent = Window.Navigator.getUserAgent(); final boolean isIE = userAgent.toUpperCase().contains("MSIE"); if (isIE && (source != null)) { final DataGridColumnGVO[] columns = source.getColumns(); if (columns != null) { int numVisibleColumns = 0; for (final DataGridColumnGVO column : columns) { if (column.getVisible()) { numVisibleColumns++; } } if ((numVisibleColumns == 1) && (qHeaderWrapper != null)) { qHeaderWrapper.getStyle().setPropertyPx("width", 1); qHeaderWrapper.getStyle().setProperty("overflow", "visible"); } } } } @Override public void onRowSelection(final RowSelectionEvent event) { if (hasOverflow()) { final Set<Row> selected = event.getSelectedRows(); for (final Row row : selected) { final DataContainerGVO dm = getRowValue(row.getRowIndex()); final SetValueGVO setValue = new SetValueGVO(); setValue.setDataContainer(dm); if (overflow instanceof HasWidgets){ SetValueExecute.processWidgets((HasWidgets)overflow,setValue); } } } handleRowSelection(event); } private void handleRowSelection(final RowSelectionEvent event) { final int rowIndex = getLastSelectedIndex(event); Object rowValue = null; if(rowIndex >= 0) { rowValue = getRowValue(rowIndex); } fireRowSelectionChange(rowIndex, rowValue); } private int getLastSelectedIndex(final RowSelectionEvent event) { int rowIndex = -1; final Object[] selected = event.getSelectedRows().toArray(); if(selected.length == 0) { return rowIndex; } if(selected[selected.length - 1] instanceof Row) { final Row lastRowSelected = (Row) selected[selected.length - 1]; rowIndex = lastRowSelected.getRowIndex(); } return rowIndex; } // method checking is columns are defined for datagrid explicitly in qaml. public Boolean isAutoGeneratedColumns() { return autoGeneratedColumns; } public void clearData() { if (getDataTable() != null) { getDataTable().clearAll(); while (getDataTable().getRowCount() > 0) { getDataTable().removeRow(0); } } cleanRows(); } private void cleanRows() { final List<DataContainerGVO> rowValues = getRowValues(); if (rowValues == null) { return; } final List<ColumnDefinition<DataContainerGVO, ?>> visibleColumns = getVisibleColumnDefinitions(); for (int i=0; i<rowValues.size(); i++) { cleanRowImpl(i, visibleColumns); } } private void cleanRowImpl(final int rowIndex, final List<ColumnDefinition<DataContainerGVO, ?>> visibleColumns) { if (visibleColumns == null) { return; } for (int i=0; i<visibleColumns.size(); i++) { final ColumnDefinition<DataContainerGVO, ?> columnDefinition = visibleColumns.get(i); if (columnDefinition instanceof QColumnDefinition) { final QColumnDefinition qColumnDefinition = (QColumnDefinition)columnDefinition; final CellCleaner cellCleaner = qColumnDefinition.getCellCleaner(); if (cellCleaner != null) { cellCleaner.cleanRow(rowIndex, columnDefinition); } } } } @Override public Integer getMaxRows() { // TODO Auto-generated method stub return null; } public void setData(final Request request, final Response<DataContainerGVO> response) { if (hasMatchedColumns(response.getRowValues())) { setData(getAbsoluteFirstRowIndex(), response.getRowValues()); } } // checking any columns are matched with existing columns and columns from new data to set. private boolean hasMatchedColumns(final Iterator<DataContainerGVO> rows) { boolean columnMatched = false; final Iterator<DataContainerGVO> itr = rows; if ((itr != null) && itr.hasNext()) { final DataContainerGVO row = itr.next(); if (row != null) { final List<ColumnDefinition<DataContainerGVO, ?>> columnDefinitionList = getTableDefinition().getVisibleColumnDefinitions(); for (final ColumnDefinition<DataContainerGVO, ?> columnDefinition : columnDefinitionList) { if (columnDefinition instanceof QColumnDefinition) { final QColumnDefinition qColumnDefinition = (QColumnDefinition)columnDefinition; if (row.getDataMap().containsKey(qColumnDefinition.getField())) { columnMatched = true; break; } } } } } return columnMatched; } private int getColumnIndex(final String name) { boolean columnFound = false; int col = -1; if (source != null && name != null && name.length() > 0 && source.getColumns() != null) { for (int column = 0; column < source.getColumns().length && !columnFound; column++) { if (name.equalsIgnoreCase(source.getColumns()[column].getFieldName())) { columnFound = true; col = column; } } } return col; } /** * inserts data to the datagrid, note that to prevent rows from getting * modified status, we always set append to false. We just make sure we have the complete * dataset/rows before setting them to the datagrid * * @param listOfDataMap data to set to the datagrid */ public void insertImportedData(final List<DataContainerGVO> listOfDataMap) { List<DataContainerGVO> rows = new ArrayList<DataContainerGVO>(); final String importAction = source.getImportAction(); if (ComponentConstants.ADD.equals(importAction)) { List<DataContainerGVO> currentRows = getRowValues(); // done to make sure we wont get "null" rows since null is a valid list entry if (currentRows != null) { rows.addAll(currentRows); } rows.addAll(listOfDataMap); } else if (ComponentConstants.SET.equals(importAction)) { rows = listOfDataMap; } else { logger.log(Level.INFO, "No import action found, using set as default"); rows = listOfDataMap; } insertData(rows, false, null, null); } // CHECKSTYLE.OFF: CyclomaticComplexity @Override public void insertData(final List<DataContainerGVO> listOfDataMap, final Boolean append, final String senderId, final String listenerType) { boolean makeRowSelected = false; int rowToSelect = 0; if(!append && !isPageScrollEvent(senderId, listenerType)) { // This will make sure scrollbar is placed on top, and so the browser scroll event will not get executed when user set the data. getDataWrapper().setScrollTop(0); makeRowSelected = getSource().getSelectFirstRow(); } if (canProcessEmptyDataSet(listOfDataMap, senderId, listenerType)) { // check is paging action and the resulted data is empty processEmptyDataSet(listOfDataMap, senderId, listenerType); } else if(isEmptyDataSet(listOfDataMap, senderId, listenerType)){ // not a paging action but result is empty if (!append) { clearData(); this.initialData = new ArrayList<DataContainerGVO>(); clearSelection(); getRowValues().clear(); if(isAutoGeneratedColumns()) { getHeaderTable().clearAll(); } } } else { // result not empty List<DataContainerGVO> data = listOfDataMap; int existingDataSize = 0; if(append){ existingDataSize = getRowValues().size(); } else { if(resetInitialData){ initialData = makeClone(listOfDataMap); } } if(source.getAdd() || source.getDelete() || source.getEditable()){ final boolean noPaging = !isPagingEvent(senderId, listenerType); for(final DataContainerGVO dm : listOfDataMap){ ++existingDataSize; if(append && noPaging){ dm.getDataMap().put(DataContainerGVO.ROW_STATUS_KEY, new DataContainerGVO(DataContainerGVO.ROW_STATUS_NEW)); dm.getDataMap().put(DataContainerGVO.ROW_NUMBER, new DataContainerGVO(QAMLConstants.TOKEN_NEW + (existingDataSize))); makeRowSelected = true; rowToSelect = existingDataSize - 1; } else { dm.getDataMap().put(DataContainerGVO.ROW_STATUS_KEY, new DataContainerGVO(DataContainerGVO.ROW_STATUS_UNMODIFIED)); dm.getDataMap().put(DataContainerGVO.ROW_NUMBER, new DataContainerGVO("" + (existingDataSize))); } } } else if(!source.getEditable()) { // ROW_NUMBER is maintained so that when $SELECTED_INDEX is used, it picks the right row. for(final DataContainerGVO dm : listOfDataMap){ ++existingDataSize; dm.getDataMap().put(DataContainerGVO.ROW_NUMBER, new DataContainerGVO("" + (existingDataSize))); } } if (append) { data = getRowValues(); data.addAll(listOfDataMap); } else { clearData(); } checkColumns(data); final boolean pageScrollEvent = isPageScrollEvent(senderId, listenerType); if (pageScrollEvent) { rememberSelection(); } ((QTableModel) getTableModel()).processData(data); if (pageScrollEvent) { restoreSelection(); } if (makeRowSelected) { this.selectRow(rowToSelect); } } } // CHECKSTYLE.ON: CyclomaticComplexity private void checkColumns(final List<DataContainerGVO> listOfDataMap) { if ((listOfDataMap != null) && (listOfDataMap.size() > 0)) { if (isAutoGeneratedColumns()) { // So there are no columns from the QAML, we make the grid data-driven // create an array of the datagridcolumns final List<DataGridColumnGVO> listOfColumns = new ArrayList<DataGridColumnGVO>(); final DataContainerGVO map = listOfDataMap.get(0); for (final String key : map.getDataMap().keySet()) { final DataGridColumnGVO dcg = new DataGridColumnGVO(); dcg.setFieldName(key); dcg.setSortable(dcg.getSortable()); dcg.setStaticField(false); dcg.setDisplayname(key); dcg.setContainerName(source.getId()); if (key.equals(DataMap.ROW_STATUS_KEY) || key.equals(DataMap.ROW_NUMBER)) { dcg.setVisible(false); } listOfColumns.add(dcg); } setTableDefinition(DataGridFactory.createTableDefinition(source, listOfColumns.toArray(new DataGridColumnGVO[]{}), uuid, parent, this)); refreshColumnHeaders(); } } } @Override public void insertDataRow(final List<String> listOfDataMap, final Boolean append, final String senderId, final String listenerType) { if (canProcessEmptyDataSet(listOfDataMap, senderId, listenerType)) { processEmptyDataSet(listOfDataMap, senderId, listenerType); } else { if (!append) { clearData(); } } } @Override public void setTableDefinition(final TableDefinition<DataContainerGVO> tableDefinition) { if (tableDefinition != null) { super.setTableDefinition(tableDefinition); } } public void createTableDefinition() { // If no columns are specified, show an empty column DataGridColumnGVO[] dataGridColumns = source.getColumns(); if ((dataGridColumns == null) || (dataGridColumns.length == 0)) { final DataGridColumnGVO dataGridColumn = new DataGridColumnGVO(); dataGridColumn.setFieldName(""); dataGridColumns = new DataGridColumnGVO[1]; dataGridColumns[0] = dataGridColumn; } else { aggregateGroupedColumns(); } final TableDefinition<DataContainerGVO> tableDefinition = DataGridFactory.createTableDefinition(source, dataGridColumns, uuid, parent, this); setTableDefinition(tableDefinition); } private void aggregateGroupedColumns() { for(final DataGridColumnGVO column : source.getColumns()){ if(column.getGroup() != null){ String[] groupNames = null; if(column.getGroup().contains(",")){ // When column belong to multiple groups. groupNames = column.getGroup().split(","); } else { groupNames = new String[]{column.getGroup()}; } for(String groupName: groupNames){ groupName = groupName.trim(); if(groupedColumns.containsKey(groupName)){ groupedColumns.get(groupName).add(column.getFieldName()); } else { final List<String> columnNames = new ArrayList<String>(); columnNames.add(column.getFieldName()); groupedColumns.put(groupName, columnNames); } } } } } @Override public void processActions(final DataGridGVO gvo, final String uuid, final String parent) { // TODO Auto-generated method stub } @Override public void setAdd(final Boolean bool) { // TODO Auto-generated method stub } @Override public void setDelete(final Boolean bool) { // TODO Auto-generated method stub } @Override public boolean isEditable() { // TODO Auto-generated method stub return false; } @Override public void setEditable(final boolean value) { // TODO Auto-generated method stub } @Override public void setExport(final Boolean bool) { // TODO Auto-generated method stub } public void setMaxRows(final Integer maxRows) { // TODO Auto-generated method stub } @Override public void setModified(final boolean modified, final int row, final int column, final String value) { // TODO Auto-generated method stub } @Override public void setModified(final ColumnDefinition<DataContainerGVO, String> columnDefinition, final UIObject uiObject, final DataContainerGVO rowValue, final Object newValue) { setModified(columnDefinition, uiObject, rowValue, newValue, false); } @Override public void setModified(final ColumnDefinition<DataContainerGVO, String> columnDefinition, final UIObject uiObject, final DataContainerGVO rowValue, final Object newValue, final boolean changedByUser) { if (columnDefinition instanceof QColumnDefinition) { if(rowValue != null && rowValue.isMap()) { final QColumnDefinition colDefinition = (QColumnDefinition)columnDefinition; final String columnName = colDefinition.getField(); DataContainerGVO dataContainerGVO = rowValue.getDataMap().get(columnName); if (dataContainerGVO == null) { dataContainerGVO = new DataContainerGVO(); dataContainerGVO.setKind(DataContainerGVO.KIND_STRING); rowValue.getDataMap().put(columnName, dataContainerGVO); } Object oldValue = null; if (newValue instanceof Date) { oldValue = dataContainerGVO.getDateData(); dataContainerGVO.setDateData((Date)newValue); dataContainerGVO.setStringDataType(DataContainerGVO.TYPE_DATE); } else if(newValue instanceof Double) { dataContainerGVO.setStringDataType(DataContainerGVO.TYPE_DOUBLE); } final String newValueOfStr = (newValue == null) ? null : newValue.toString(); dataContainerGVO.setDataString(newValueOfStr); doColumnDataChange(columnDefinition, uiObject, rowValue.getDataMap(), oldValue, newValue, changedByUser); } } } @Override public void setOverflow(final Widget overflow) { this.overflow = overflow; } @Override public void setPageSize(final Integer pageSize) { setPageSize(pageSize, false); } public void setPageSize(final Integer pageSize, final Boolean init) { if (pageSize != null) { if ((init) && (pageSize != -1)) { hasPredefinedPageSize = true; } setPageSize((int)pageSize); } } @Override public void setPageSize(final int pageSize) { if (hasPredefinedPageSize) { // pageSize is specified in QAML code super.setPageSize(pageSize); } } @Override public void setShowAll(final Boolean bool) { // TODO Auto-generated method stub } @Override public void setup() { refreshColumnHeaders(); if (source.getColumns()!=null){ initColumnWidths(); setEmptyTableWidgetVisible(false); final DataMap dummy = new DataMap(); final DataContainerGVO dummydcg = new DataContainerGVO(); dummydcg.setDataString(""); final List<DataMap> dummylistOfDataMap = new ArrayList<DataMap>(); for(int i=0;i<source.getColumns().length;i++){ dummy.put(""+i,dummydcg ); } for (int i=0;i<15;i++){ dummylistOfDataMap.add(dummy); } } } private void refreshColumnHeaders() { refreshColumnHeaders(false); } private void refreshColumnHeaders(final boolean force) { if ((source != null) && (source.getColumns() != null)) { if (getHeaderTable() != null) { if (force || isColumnHeadersChanged()) { clearColumnHeaders(); buildColumnHeaders(); } } } } public void initColumnWidths() { int visibleColIndex = 0; final DataGridColumnGVO[] columns = source.getColumns(); for (final DataGridColumnGVO columnGVO : columns) { if (!columnGVO.getVisible()) { continue; } final String width = columnGVO.getWidth(); if (width != null) { setColumnWidth(visibleColIndex, Integer.parseInt(width)); } visibleColIndex++; } } private void clearColumnHeaders() { final FixedWidthFlexTable headerTable = getHeaderTable(); if (headerTable == null) { return; } if (headerTable.getColumnCount() > 0) { headerTable.removeRow(0); headerTable.clearAll(); } } private void buildColumnHeaders() { int visibleColIndex = 0; final DataGridColumnGVO[] columns = source.getColumns(); for (final DataGridColumnGVO columnGVO : columns) { if (!columnGVO.getVisible()) { continue; } final Widget columnHeader = createColumnHeader(columnGVO); if (columnHeader == null) { continue; } getHeaderTable().setWidget(0, visibleColIndex, columnHeader); visibleColIndex++; } } private Widget createColumnHeader(final DataGridColumnGVO columnGVO) { if ((columnGVO == null) || columnGVO.isQafeChecksum()) { return null; } String displayName = columnGVO.getDisplayname(); if (displayName == null) { displayName = columnGVO.getFieldName(); } final Label label = new Label(displayName); label.setHeight("20px"); if (columnGVO.getStyleClass() != null) { label.setStylePrimaryName(columnGVO.getStyleClass()); } return label; } private boolean isColumnHeadersChanged() { final DataGridColumnGVO[] dataGridColumns = source.getColumns(); // Number of columns has been changed, so the columnHeaders if (getHeaderTable().getColumnCount() != dataGridColumns.length) { return true; } // Fill map with columnNames for faster processing final Map <String,String> map = new HashMap<String,String>(); for (int i=0; i<dataGridColumns.length; i++) { final DataGridColumnGVO dataGridColumn = dataGridColumns[i]; if (dataGridColumn != null) { String displayName = dataGridColumn.getDisplayname(); if (displayName == null) { displayName = dataGridColumn.getFieldName(); } if (displayName != null) { map.put(displayName, null); } } } // Check existence of all columnNames final Iterator<Widget> itrWidget = getHeaderTable().iterator(); while (itrWidget.hasNext()) { final Widget widget = itrWidget.next(); if (widget instanceof Label) { final Label label = (Label)widget; if (!map.containsKey(label.getText())) { return true; } } } return false; } /** * Reload the current page. */ @Override public void reloadPage() { if (qCurrentPage >= 0) { gotoPage(qCurrentPage, true); } else { gotoPage(0, true); } } @Override public int getCurrentPage() { return qCurrentPage; } @Override public void setCurrentPage(final int currentPage) { if (hasPredefinedPageSize) { // pageSize is specified in QAML code qCurrentPage = Math.max(0, currentPage); if ((pagingOptions != null) && (qCurrentPage != Integer.MAX_VALUE)) { pagingOptions.getCurPageBox().setText(String.valueOf(qCurrentPage + 1)); } } } @Override public int getAbsoluteFirstRowIndex() { int rowIndex = getCurrentPage(); if (rowIndex != Integer.MAX_VALUE) { rowIndex = rowIndex * getPageSize(); } return rowIndex; } @Override public int getAbsoluteLastRowIndex() { if (getPageSize() > 0) { int rowIndex = getAbsoluteFirstRowIndex(); if (rowIndex != Integer.MAX_VALUE) { rowIndex = rowIndex + getPageSize() - 1; } return rowIndex; } return Math.max(getTableModel().getRowCount(), 0) - 1; } public void onDelete() { //remember the selected rows, after the event body is executed success selected rows needs to be removed in onResult callback. rememberSelection(); setSenderId(QPagingScrollTableOperation.CONTROLS_DELETE); gotoPage(getCurrentPage(), true); } private void rememberSelection() { if (rememberSelectedRows == null) { rememberSelectedRows = new ArrayList<Integer>(); } rememberSelectedRows.clear(); final Iterator<Integer> itr = getDataTable().getSelectedRows().iterator(); while (itr.hasNext()) { final Integer rowIndex = itr.next(); rememberSelectedRows.add(rowIndex); } } private void restoreSelection() { if (rememberSelectedRows == null) { return; } for (final Integer rowIndex : rememberSelectedRows){ getDataTable().selectRow(rowIndex, false); } rememberSelectedRows.clear(); } private void clearSelection() { getDataTable().deselectAllRows(); getSelectedRowValues().clear(); if(rememberSelectedRows != null){ rememberSelectedRows.clear(); } } private void performDelete() { for(final Integer rowIndex : rememberSelectedRows){ getRowValues().remove(rowIndex.intValue()); getDataTable().removeRow(rowIndex.intValue()); } clearSelection(); } public void onAdd() { setSenderId(QPagingScrollTableOperation.CONTROLS_ADD); gotoPage(getCurrentPage(), true); } public void onSave() { setSenderId(QPagingScrollTableOperation.CONTROLS_SAVE); gotoPage(getCurrentPage(), true); updateQafeChecksum(); } private void updateQafeChecksum() { final Collection<DataContainerGVO> rows = getRowValuesToProcess(DataContainerGVO.ROW_STATUS_MODIFIED); for (final DataContainerGVO row : rows) { final DataMap dataMap = row.getDataMap(); final DataContainerGVO checksumContainer = dataMap.get(DataContainerGVO.QAFE_CHECKSUM); if (checksumContainer != null) { int checksum = 0; for (final Map.Entry<String, DataContainerGVO> field : dataMap.entrySet()) { if (!isMetaData(field.getKey())) { Object value = null; if (field.getValue() != null) { value = field.getValue().createType(); } checksum += QAMLUtil.calculateChecksum(field.getKey(), value); } } checksumContainer.setDataString("" + checksum); } } } private boolean isMetaData(final String key) { return DataContainerGVO.ROW_STATUS_KEY.equals(key) || DataContainerGVO.ROW_NUMBER.equals(key) || DataContainerGVO.QAFE_CHECKSUM.equals(key); } public void onRefresh() { setSenderId(QPagingScrollTableOperation.CONTROLS_REFRESH); gotoPage(getCurrentPage(), true); } public void onCancel() { setSenderId(QPagingScrollTableOperation.CONTROLS_CANCEL); gotoPage(getCurrentPage(), true); } @Override public void gotoFirstPage() { setSenderId(QPagingOptions.PAGING_FIRSTPAGE); gotoPage(0, true); } @Override public void gotoLastPage() { setSenderId(QPagingOptions.PAGING_LASTPAGE); gotoPage(Integer.MAX_VALUE, true); } @Override public void gotoNextPage() { setSenderId(QPagingOptions.PAGING_NEXTPAGE); gotoPage(getCurrentPage() + 1, true); } @Override public void gotoPreviousPage() { setSenderId(QPagingOptions.PAGING_PREVIOUSPAGE); gotoPage(Math.max(0, getCurrentPage() - 1), true); } @Override public void gotoPage(final int page, final boolean forced) { final int currPage = getCurrentPage(); if (currPage != page || forced) { setCurrentPage(page); final FixedWidthGrid dataTable = getDataTable(); if ((currPage != page) && (!hasPageScroll())) { // Deselect rows when switching pages if it is standard pagination dataTable.deselectAllRows(); } // Request the new data from the table model final int firstRow = getAbsoluteFirstRowIndex(); final int lastRow = getAbsoluteLastRowIndex(); final Request request = new Request(firstRow, lastRow, dataTable.getColumnSortList()); final Callback callback = new Callback<DataContainerGVO>(){ @Override public void onFailure(final Throwable caught) { ClientApplicationContext.getInstance().log("Setting datagrid values failed", caught); } @Override public void onRowsReady(final Request request, final Response<DataContainerGVO> response) { setData(request, response); } }; if (getTableModel() instanceof QTableModel) { ((QTableModel)getTableModel()).requestRows(request, callback, this); } } } private boolean hasPageScroll() { if ((getSource() != null) && getSource().getPageScroll()) { return true; } return false; } private void setSenderId(final String sender) { final TableModel<DataContainerGVO> m = getTableModel(); if (m instanceof QTableModel) { final QTableModel qm = (QTableModel) m; if (QPagingOptions.PAGING_FIRSTPAGE.equals(sender)) { qm.setSender(pagingOptions.getFirstImage()); } else if (QPagingOptions.PAGING_NEXTPAGE.equals(sender)) { qm.setSender(pagingOptions.getNextImage()); } else if (QPagingOptions.PAGING_LASTPAGE.equals(sender)) { qm.setSender(pagingOptions.getLastImage()); } else if (QPagingOptions.PAGING_PREVIOUSPAGE.equals(sender)) { qm.setSender(pagingOptions.getPrevImage()); } else if (QPagingScrollTableOperation.CONTROLS_DELETE.equals(sender)) { qm.setSender(pagingScrollTableOperations.getDeleteImage()); } else if (QPagingScrollTableOperation.CONTROLS_ADD.equals(sender)) { qm.setSender(pagingScrollTableOperations.getAddImage()); } else if (QPagingScrollTableOperation.CONTROLS_SAVE.equals(sender)) { qm.setSender(pagingScrollTableOperations.getSaveImage()); } else if (QPagingScrollTableOperation.CONTROLS_REFRESH.equals(sender)) { qm.setSender(pagingScrollTableOperations.getRefreshImage()); } else if (QPagingScrollTableOperation.CONTROLS_CANCEL.equals(sender)) { qm.setSender(pagingScrollTableOperations.getCancelImage()); } } } public void setPagingOptions(final QPagingOptions pagingOptions) { this.pagingOptions = pagingOptions; } public void resetCurrentPage(){ if (getCurrentPage()<0){ gotoPage(0,true); } } @Override public void selectRow(final int rowNr) { if (rowNr>=0 && rowNr< getDataTable().getRowCount()){ getDataTable().selectRow(rowNr, true); final Element rowToShow = getDataTable().getRowFormatter().getElement(rowNr); scrollIntoView(rowToShow, this.getElement()); } else { //TODO: call clearSelection to remove the existing selections. //This will allow end user to remove all selections by passing -1 in set-property } } /** * * This method is copied from com.google.gwt.dom.client.DOMImpl class and modified to add an extra check at the end. * ADDED CODE AT END: if(cur == containerElement) {break;} * When user add a new record or use set-property to set a row selected we need to show that row in the view. * When we are using scrollIntoView method of GWT(getDataTable().getRowFormatter().getElement(rowNr).scrollIntoView()) * we got issue after zooming in(CTr+) and then setting the first row as selected. * Issue is that the entire browser window moves up after , making top part of the screen invisible. * Now we added extra check tp stop the operation of making the new view position when it reaches the parent(in this case the pagingScrollTable) */ protected native void scrollIntoView(Element elem, Element containerElement) /*-{ var left = elem.offsetLeft, top = elem.offsetTop; var width = elem.offsetWidth, height = elem.offsetHeight; if (elem.parentNode != elem.offsetParent) { left -= elem.parentNode.offsetLeft; top -= elem.parentNode.offsetTop; } var cur = elem.parentNode; while (cur && (cur.nodeType == 1)) { if (left < cur.scrollLeft) { cur.scrollLeft = left; } if (left + width > cur.scrollLeft + cur.clientWidth) { cur.scrollLeft = (left + width) - cur.clientWidth; } if (top < cur.scrollTop) { cur.scrollTop = top; } if (top + height > cur.scrollTop + cur.clientHeight) { cur.scrollTop = (top + height) - cur.clientHeight; } var offsetLeft = cur.offsetLeft, offsetTop = cur.offsetTop; if (cur.parentNode != cur.offsetParent) { offsetLeft -= cur.parentNode.offsetLeft; offsetTop -= cur.parentNode.offsetTop; } left += offsetLeft - cur.scrollLeft; top += offsetTop - cur.scrollTop; cur = cur.parentNode; //added check to stop iteration when the container is datagrid if(cur == containerElement) { break; } } }-*/; public Object getData(final String fetchForRowStatus, final String groupName) { final Collection<DataContainerGVO> rowValuesToProcess = getRowValuesToProcess(fetchForRowStatus); List<DataContainerGVO> data = new ArrayList<DataContainerGVO>(); for (final DataContainerGVO row : makeClone(rowValuesToProcess)) { row.getDataMap().remove(DataContainerGVO.ROW_STATUS_KEY); if (row.getDataMap().get(DataContainerGVO.ROW_NUMBER) != null) { final String rowNumber = row.getDataMap().get(DataContainerGVO.ROW_NUMBER).getDataString().replaceAll("[" + QAMLConstants.TOKEN_NEW + QAMLConstants.TOKEN_MODIFIED + QAMLConstants.TOKEN_DELETED + "]", ""); row.getDataMap().get(DataContainerGVO.ROW_NUMBER).setDataString(rowNumber); } data.add(row); } if (groupName != null) { final List<DataContainerGVO> filteredRows = new ArrayList<DataContainerGVO>(); final List<String> columnsOfThisGroup = groupedColumns.get(groupName); if (columnsOfThisGroup != null) { for (final DataContainerGVO row : makeClone(data)) { final DataContainerGVO dgvo = new DataContainerGVO(new DataMap()); dgvo.getDataMap().put(DataContainerGVO.ROW_NUMBER, row.getDataMap().get(DataContainerGVO.ROW_NUMBER)); for (final String key : columnsOfThisGroup) { dgvo.getDataMap().put(key, row.getDataMap().get(key)); } filteredRows.add(dgvo); } data = filteredRows; } } return data; } private Collection<DataContainerGVO> getRowValuesToProcess(final String fetchForRowStatus) { if (fetchForRowStatus == null) { return getSelectedRowValues(); } else if (DataContainerGVO.ROW_STATUS_ALL.equals(fetchForRowStatus)) { return getRowValues(); } else if (DataContainerGVO.ROW_STATUS_UNSELECTED.equals(fetchForRowStatus)) { final Collection<DataContainerGVO> rowValuesToProcess = new ArrayList<DataContainerGVO>(getRowValues()); rowValuesToProcess.removeAll(getSelectedRowValues()); return rowValuesToProcess; } else { final Collection<DataContainerGVO> rowValuesToProcess; rowValuesToProcess = new ArrayList<DataContainerGVO>(); for (final DataContainerGVO row : getRowValues()) { if ((row.getDataMap().get(DataContainerGVO.ROW_STATUS_KEY).getDataString()).equals(fetchForRowStatus)) { rowValuesToProcess.add(row); } } return rowValuesToProcess; } } public void setScrollTableOperations(final QPagingScrollTableOperation qPagingScrollTableOperation) { pagingScrollTableOperations = qPagingScrollTableOperation; } protected Boolean isPagingEvent(final String senderId, final String listenerType) { if (isPageEvent(senderId, listenerType)) { return true; } if (isPageScrollEvent(senderId, listenerType)) { return true; } return false; } private boolean isPageEvent(final String senderId, final String listenerType) { if (QAMLConstants.EVENT_ONCLICK.equals(listenerType)) { final String dataGridId = this.source.getId().toString(); if (senderId.startsWith((dataGridId + "." + QPagingOptions.PAGING_FIRSTPAGE)) || senderId.startsWith((dataGridId + "." + QPagingOptions.PAGING_PREVIOUSPAGE)) || senderId.startsWith((dataGridId + "." + QPagingOptions.PAGING_NEXTPAGE)) || senderId.startsWith((dataGridId + "." + QPagingOptions.PAGING_LASTPAGE))) { return true; } } return false; } private boolean isPageScrollEvent(final String senderId, final String listenerType) { if (QAMLConstants.EVENT_ONSCROLL_BOTTOM.equals(listenerType)) { final String dataGridId = this.source.getId().toString(); if (senderId.startsWith(dataGridId)) { return true; } } return false; } protected Boolean canProcessEmptyDataSet(final Object data, final String senderId, final String listenerType) { boolean result = false; if (data == null) { result = true; } else if ((data instanceof List) && ((List)data).isEmpty()) { result = true; } result = result ? isPagingEvent(senderId, listenerType) : result; return result; } protected Boolean isEmptyDataSet(final Object data, final String senderId, final String listenerType) { boolean result = false; if ((data == null) || ((data instanceof List) && ((List)data).isEmpty()) ) { result = true; } return result; } protected void processEmptyDataSet(final Object data, final String senderId, final String listenerType) { // qCurrentPage should be decrement by 1, // because it's incremented by 1 already before sending to the back-end final int currPage = getCurrentPage(); setCurrentPage(currPage - 1); if ((senderId != null) && (listenerType != null)) { final String dataGridId = this.source.getId().toString(); if ( (listenerType.equals("onscroll-bottom")) || (listenerType.equals("onclick") && (senderId.startsWith((dataGridId + "." + QPagingOptions.PAGING_NEXTPAGE))))) { // show a fading message fadeMessage(MSG_LAST_PAGE); } } } protected void fadeMessage(final String message) { setEmptyTableWidgetVisible(true); final Widget widget = getEmptyTableWidget(); if (widget instanceof MessageBox){ final MessageBox messageBox = (MessageBox)widget; messageBox.getElement().getStyle().setProperty("width", "100%"); Utils.setWidgetPosition(messageBox, 0, 0); Utils.fadeMessage(messageBox, message); } } @Override protected void setEmptyTableWidgetVisible(final boolean visible) { super.setEmptyTableWidgetVisible(visible); // when calling super.setEmptyTableWidgetVisible(true), // data are shown, so set the visibility back to true getDataWrapper().getStyle().setProperty("display", ""); } @Override protected Element createWrapper(final String cssName) { final Element wrapper = super.createWrapper(cssName); if ("headerWrapper".equals(cssName)) { // This will be used in method initParameters qHeaderWrapper = wrapper; } return wrapper; } private String getSenderIdOnly(String senderId) { if ((senderId != null) && (senderId.indexOf("|") > -1)) { senderId = senderId.substring(0, senderId.indexOf("|")); } return senderId; } // call back to handle anything to be done after the event body processing. @Override public void onResult(String senderId, final String listenerType) { if (QAMLConstants.EVENT_ONCLICK.equals(listenerType)) { senderId = getSenderIdOnly(senderId); if (senderId.endsWith(QPagingScrollTableOperation.CONTROLS_DELETE)) { handleDeleteRecord(); } else if (senderId.endsWith(QPagingScrollTableOperation.CONTROLS_ADD)) { handleAddRecord(); } else if (senderId.endsWith(QPagingScrollTableOperation.CONTROLS_SAVE)) { int rowIndex = 0; final ArrayList<DataContainerGVO> rowsToRemove = new ArrayList<DataContainerGVO>(); for (final DataContainerGVO row : getRowValues()) { if (!row.getDataMap().get(DataContainerGVO.ROW_STATUS_KEY).getDataString().equals(DataContainerGVO.ROW_STATUS_DELETED)) { row.getDataMap().get(DataContainerGVO.ROW_STATUS_KEY).setDataString(DataContainerGVO.ROW_STATUS_UNMODIFIED); final String rowNumber = row.getDataMap().get(DataContainerGVO.ROW_NUMBER).getDataString().replaceAll("[" + QAMLConstants.TOKEN_NEW + QAMLConstants.TOKEN_MODIFIED + QAMLConstants.TOKEN_DELETED + "]", ""); row.getDataMap().get(DataContainerGVO.ROW_NUMBER).setDataString(rowNumber); } else { rowsToRemove.add(row); } rowIndex++; } for (final DataContainerGVO removeRow : rowsToRemove) { getRowValues().remove(removeRow); } //datagridRendered = false; resetInitialData = true; insertData(getRowValues(), false, senderId, listenerType); clearSelection(); } else if (senderId.endsWith(QPagingScrollTableOperation.CONTROLS_REFRESH)) { ClientApplicationContext.getInstance().log("performRefresh (senderId) : " + senderId); } else if (senderId.endsWith(QPagingScrollTableOperation.CONTROLS_CANCEL)) { if (containsModifiedData()) { showPrompt(senderId, listenerType); } } } } private void handleAddRecord() { int newRowIndex = -1; final DataMap dummy = new DataMap(); List<DataContainerGVO> rowValues = getRowValues(); if (rowValues == null) { rowValues = new ArrayList<DataContainerGVO>(); } if (rowValues.size() > 0) { // Add the newly record as last with column names from data newRowIndex = rowValues.size(); final DataContainerGVO dm = rowValues.get(0); final Set<String> keys = dm.getDataMap().keySet(); for(final String column: keys) { final DataContainerGVO dummydcg = new DataContainerGVO(""); dummy.put(column, dummydcg); } } else if (source.getColumns() != null) { // Add the newly record as first with column names from datagrid columns newRowIndex = 0; for (final DataGridColumnGVO columnGVO: source.getColumns()) { final DataContainerGVO dummydcg = new DataContainerGVO(""); dummy.put(columnGVO.getFieldName(), dummydcg); } } // Add the newly record after the selection, if present final Set<DataContainerGVO> selectedRowValues = getSelectedRowValues(); if ((selectedRowValues != null) && (selectedRowValues.size() > 0)) { DataContainerGVO selectedRow = null; final Iterator<DataContainerGVO> itrRow = selectedRowValues.iterator(); while (itrRow.hasNext()) { selectedRow = itrRow.next(); } if (selectedRow != null) { newRowIndex = getRowNumber(selectedRow); int offset = 1; final List<DataContainerGVO> newRowValues = new ArrayList<DataContainerGVO>(); for (int i=0; i<rowValues.size(); i++) { final DataContainerGVO rowValue = rowValues.get(i); if (i == newRowIndex) { newRowValues.add(null); offset++; } if (i >= newRowIndex) { updateRowNumber(rowValue, i + offset); } newRowValues.add(rowValue); } rowValues.clear(); rowValues.addAll(newRowValues); } } if (newRowIndex > -1) { dummy.put(DataContainerGVO.ROW_STATUS_KEY, new DataContainerGVO(DataContainerGVO.ROW_STATUS_NEW)); dummy.put(DataContainerGVO.ROW_NUMBER, new DataContainerGVO(QAMLConstants.TOKEN_NEW + (newRowIndex + 1))); final DataContainerGVO newRecord = new DataContainerGVO(dummy); if (newRowIndex < rowValues.size()) { rowValues.set(newRowIndex, newRecord); } else { rowValues.add(newRecord); } try { refreshingExistingRows = true; ((QTableModel) getTableModel()).processData(rowValues); } finally { refreshingExistingRows = false; } selectRow(newRowIndex); } } private void handleDeleteRecord() { final Collection<DataContainerGVO> selectedRowValues = getSelectedRowValues(); if (selectedRowValues == null) { return; } final List<DataContainerGVO> newlyRowValues = new ArrayList<DataContainerGVO>(); for (final DataContainerGVO rowValue : selectedRowValues) { final DataContainerGVO statusKeyGVO = rowValue.getDataMap().get(DataContainerGVO.ROW_STATUS_KEY); final String statusKey = statusKeyGVO.getDataString(); if (DataContainerGVO.ROW_STATUS_DELETED.equals(statusKey)) { continue; } else if (DataContainerGVO.ROW_STATUS_NEW.equals(statusKey)) { newlyRowValues.add(rowValue); } else { final DataContainerGVO rowNumberGVO = rowValue.getDataMap().get(DataContainerGVO.ROW_NUMBER); final String rowNumber = rowNumberGVO.getDataString().replaceAll("[" + QAMLConstants.TOKEN_NEW + QAMLConstants.TOKEN_MODIFIED + QAMLConstants.TOKEN_DELETED + "]", ""); rowNumberGVO.setDataString(QAMLConstants.TOKEN_DELETED + rowNumber); statusKeyGVO.setDataString(DataContainerGVO.ROW_STATUS_DELETED); final QLabel label = new QLabel(QAMLConstants.TOKEN_DELETED + rowNumber); getDataTable().setElement(Integer.parseInt(rowNumber)-1, 0, label.getElement()); } } if (newlyRowValues.size() > 0) { final List<DataContainerGVO> newRowValues = new ArrayList<DataContainerGVO>(); final List<DataContainerGVO> rowValues = getRowValues(); for (int i=0; i<rowValues.size(); i++) { final DataContainerGVO rowValue = rowValues.get(i); if (newlyRowValues.contains(rowValue)) { continue; } updateRowNumber(rowValue, newRowValues.size() + 1); newRowValues.add(rowValue); } rowValues.clear(); rowValues.addAll(newRowValues); try { refreshingExistingRows = true; if (rowValues.isEmpty()) { clearData(); } else { ((QTableModel)getTableModel()).processData(rowValues); } } finally { refreshingExistingRows = false; } } clearSelection(); } private int getRowNumber(final DataContainerGVO rowValue) { int rowNumber = -1; if (rowValue != null) { final DataContainerGVO rowNumberGVO = rowValue.getDataMap().get(DataContainerGVO.ROW_NUMBER); final String strRowNumber = rowNumberGVO.getDataString().replaceAll("[" + QAMLConstants.TOKEN_NEW + QAMLConstants.TOKEN_MODIFIED + QAMLConstants.TOKEN_DELETED + "]", ""); rowNumber = Integer.valueOf(strRowNumber); } return rowNumber; } private void updateRowNumber(final DataContainerGVO rowValue, final int newRowNumber) { if (rowValue == null) { return; } String status = ""; final String statusKey = rowValue.getDataMap().get(DataContainerGVO.ROW_STATUS_KEY).getDataString(); if (DataContainerGVO.ROW_STATUS_NEW.equals(statusKey)) { status = QAMLConstants.TOKEN_NEW; } else if (DataContainerGVO.ROW_STATUS_MODIFIED.equals(statusKey)) { status = QAMLConstants.TOKEN_MODIFIED; } else if (DataContainerGVO.ROW_STATUS_DELETED.equals(statusKey)) { status = QAMLConstants.TOKEN_DELETED; } final DataContainerGVO rowNumberGVO = new DataContainerGVO(status + newRowNumber); rowValue.getDataMap().put(DataContainerGVO.ROW_NUMBER, rowNumberGVO); } /** * Insert a row into the table relative to the total number of rows. * This is exact the same as defined in the super class, * except the row removal based on the pagesize * * @param beforeRow the row index */ @Override protected void insertAbsoluteRow(final int beforeRow) { // Physically insert the row final int lastRow = getAbsoluteLastRowIndex() + 1; if (beforeRow <= lastRow) { final int firstRow = getAbsoluteFirstRowIndex(); if (beforeRow >= firstRow) { // Insert row in the middle of the page getDataTable().insertRow(beforeRow - firstRow); } else { // Insert zero row because row is before this page getDataTable().insertRow(0); } } } private boolean containsModifiedData() { for(final DataContainerGVO row : getRowValues()){ if(!((row.getDataMap().get(DataContainerGVO.ROW_STATUS_KEY).toString()).equals(DataContainerGVO.ROW_STATUS_UNMODIFIED))) { return true; } } return false; } private void showPrompt(final String senderId, final String listenerType) { final org.gwt.mosaic.ui.client.MessageBox prompt = new org.gwt.mosaic.ui.client.MessageBox(MessageBoxType.PROMPT, "Confirm") { @Override public void onClose(final boolean result) { } }; final Label message = new Label(); message.setText("Click ok to reset the data to initial value."); final Button ok = new Button("Ok"); ok.addClickHandler(new ClickHandler() { @Override public void onClick(final ClickEvent event) { resetInitialData = false; //datagridRendered = false; getRowValues().clear(); getDataTable().clear(); final List<DataContainerGVO> cloneOfInitialData = makeClone(initialData); insertData(cloneOfInitialData, false, senderId, listenerType); prompt.removeFromParent(); clearSelection(); } }); final Button cancel = new Button("Cancel"); cancel.addClickHandler(new ClickHandler() { @Override public void onClick(final ClickEvent event) { prompt.removeFromParent(); } }); final HorizontalPanel hp = new HorizontalPanel(); hp.add(ok); hp.add(cancel); final VerticalPanel vp = new VerticalPanel(); vp.add(message); vp.add(hp); prompt.add(vp); final int width = Window.getClientWidth() - 10; final int height = Window.getClientHeight() - 10; prompt.setSize(width+"", height+""); prompt.showModal(); } private static List<DataContainerGVO> makeClone(final Collection<DataContainerGVO> data) { final List<DataContainerGVO> cloneData = new ArrayList<DataContainerGVO>(); if(data != null) { for(final DataContainerGVO row : data){ if (row.isMap()){ final DataContainerGVO newMap = new DataContainerGVO(new DataMap()); for(final String key : row.getDataMap().keySet()){ final DataContainerGVO value = row.getDataMap().get(key); final DataContainerGVO gvo = new DataContainerGVO(value != null? value.getDataString() : null); if(value != null){ gvo.setStringDataType(value.getStringDataType()); gvo.setDateData(value.getDateData()); } newMap.getDataMap().put(key, gvo); } cloneData.add(newMap); } } } return cloneData; } private void doColumnDataChange(final ColumnDefinition<DataContainerGVO, String> columnDefinition, final UIObject uiObject, final DataMap rowValue, final Object oldValue, final Object newValue, final boolean changedByUser) { if ((source != null) && (source.getColumns() != null) && (columnDefinition instanceof QColumnDefinition)) { final QColumnDefinition qColumnDefinition = (QColumnDefinition)columnDefinition; DataGridColumnGVO dataGridColumnGVO = null; for (final DataGridColumnGVO columnGVO: source.getColumns()) { final String fieldName = columnGVO.getFieldName(); if ((fieldName != null) && (fieldName.equals(qColumnDefinition.getField()))) { dataGridColumnGVO = columnGVO; break; } } ComponentRendererHelper.handleDataChange(dataGridColumnGVO, uiObject, oldValue, newValue); if (changedByUser) { changeRowStatus(rowValue, DataMap.ROW_STATUS_MODIFIED); } } } private void changeRowStatus(final DataMap rowValue, final String changeStatusTo) { if (refreshingExistingRows) { return; } if (rowValue == null) { return; } final DataContainerGVO rowStatusGVO = rowValue.get(DataContainerGVO.ROW_STATUS_KEY); if (rowStatusGVO == null) { return; } // Changes row status only if row is unmodified final String rowStatus = rowStatusGVO.getDataString(); if (DataContainerGVO.ROW_STATUS_UNMODIFIED.equals(rowStatus) && !DataContainerGVO.ROW_STATUS_NEW.equals(rowStatus)) { final String rowNumber = rowValue.get(DataContainerGVO.ROW_NUMBER).getDataString(); final int rowIndex = Integer.parseInt(rowNumber) - 1; final int rowCount = getDataTable().getRowCount(); // Update only the status if rowCount > rowIndex, in this case value is changed by user, // otherwise the datagrid is being constructed so no need to update if (rowCount > rowIndex ) { rowStatusGVO.setDataString(changeStatusTo); rowValue.get(DataContainerGVO.ROW_NUMBER).setDataString("*" + rowNumber); getDataTable().setElement(Integer.parseInt(rowNumber)-1, 0, new QLabel("*"+rowNumber).getElement()); } } } @Override public void onScroll(final ScrollEvent event) { if (scrollPosition == getDataWrapper().getScrollTop()) { return; } final int clientHeight = getDataWrapper().getClientHeight(); final int scrollHeight = getDataWrapper().getScrollHeight(); scrollPosition = getDataWrapper().getScrollTop(); final boolean scrollBarHitsBottom = (scrollPosition + clientHeight) >= scrollHeight; final boolean scrollBarIsOnTop = scrollPosition == 0; if (!scrollBarIsOnTop && scrollBarHitsBottom) { scrollEvent = true; gotoNextPage(); } } public boolean isScrollEvent() { return scrollEvent; } public void setScrollEvent(final boolean scrollEvent) { this.scrollEvent = scrollEvent; } @Override public void setDataToCell(final DataContainerGVO valueToSet, final boolean b, final String senderId, final String cellOnRowToSet) { final String[] inputRef = cellOnRowToSet.split("[.]"); final int rowIndex = getRowIndex(inputRef[0].toString().substring(inputRef[0].indexOf("[")+1, inputRef[0].indexOf("]"))); final String column = inputRef[1]; setColumnValue(rowIndex, column, valueToSet); } @Override public void setColumnValue(final String columnName, final DataContainerGVO value) { final int rowIndex = getSelectedRowIndex(); setColumnValue(rowIndex, columnName, value); } @Override @SuppressWarnings({"deprecation"}) public void setColumnValue(final int rowIndex, final String columnName, final DataContainerGVO value) { if (rowIndex < 0) { return; } final DataContainerGVO rowValue = getRowValue(rowIndex); if (rowValue == null) { return; } final DataMap dataMap = rowValue.getDataMap(); if (hasColumnName(columnName, dataMap)) { final DataContainerGVO currentValue = dataMap.get(columnName); if (isChanged(currentValue, value)) { dataMap.put(columnName, value); changeRowStatus(dataMap, DataMap.ROW_STATUS_MODIFIED); setRowValue(rowIndex, rowValue); } } } @SuppressWarnings("rawtypes") private boolean hasColumnName(final String columnName, final DataMap dataMap) { if (dataMap.containsKey(columnName)) { return true; } final DefaultTableDefinition tableDefinition = (DefaultTableDefinition) getTableDefinition(); final int numCols = tableDefinition.getColumnDefinitionCount(); for (int i = 0; i < numCols; i++) { final QColumnDefinition columnDefinition = (QColumnDefinition) tableDefinition.getColumnDefinition(i); final String fieldName = columnDefinition.getField(); if (fieldName.equals(columnName)) { return true; } } return false; } private boolean isChanged(final DataContainerGVO oldValue, final DataContainerGVO newValue) { if ((oldValue == null) && (newValue != null)) { return true; } if ((oldValue != null) && (newValue == null)) { return true; } if ((oldValue == null) && (newValue == null)) { return false; } return !oldValue.equalsValue(newValue); } /* * The following method returns the row number when setting or getting data is done on a data grid cell. * Setting and getting of datagrid cell can be done either by using the row index directly or by mentioning the change to be on the selected row. * */ @Override public int getRowIndex(final String rowIndex){ if (rowIndex.equals(DataMap.SELECTED_INDEX)) { return getSelectedRowIndex(); } return Integer.parseInt(rowIndex); } private int getSelectedRowIndex() { final Set<DataContainerGVO> selectedRowValues = getSelectedRowValues(); if (selectedRowValues != null) { for (final DataContainerGVO row: selectedRowValues) { final DataContainerGVO rowNumberColumn = row.getDataMap().get(DataMap.ROW_NUMBER); if (rowNumberColumn != null) { String rowIndex = rowNumberColumn.getDataString(); rowIndex = rowIndex.replaceAll("[" + QAMLConstants.TOKEN_NEW + QAMLConstants.TOKEN_MODIFIED + QAMLConstants.TOKEN_DELETED + "]", ""); return Integer.parseInt(rowIndex) - 1; } break; } } return -1; } @Override public void addToDropDownValuesForColumnList(final String dropDownColumnName, final SetValueGVO setValue) { dropDownColumnAndValues.put(dropDownColumnName, setValue); } public Map<String, SetValueGVO> getDropDownColumnAndValues() { return dropDownColumnAndValues; } @Override public void setColumnVisible(final String column, final boolean value) { final DataGridColumnGVO columnGVO = getColumn(column); if (columnGVO == null) { return; } columnGVO.setVisible(value); setTableDefinition(DataGridFactory.createTableDefinition(source, source.getColumns(), uuid, parent, this)); refreshColumnHeaders(true); ((QTableModel) getTableModel()).processData(getRowValues()); redraw(); } @Override public void setColumnLabel(final String column, final String value) { final DataGridColumnGVO columnGVO = getColumn(column); if (columnGVO == null) { return; } columnGVO.setDisplayname(value); refreshColumnHeaders(true); } private DataGridColumnGVO getColumn(final String column) { if ((source != null) && (source.getColumns() != null)) { final DataGridColumnGVO[] columns = source.getColumns(); for (final DataGridColumnGVO columnGVO : columns) { if (columnGVO == null) { continue; } final String columnId = columnGVO.getId(); if ((columnId != null) && columnId.equals(column)) { return columnGVO; } } } return null; } @Override public void addRowSelectionChangeHandler(final RowSelectionChangeHandler handler) { if (handler != null) { rowSelectionChangeHandlers.add(handler); } } private void fireRowSelectionChange(final int rowIndex, final Object rowValue) { for (int i=0; i<rowSelectionChangeHandlers.size(); i++) { final RowSelectionChangeHandler handler = rowSelectionChangeHandlers.get(i); final RowSelectionChangeEvent event = new RowSelectionChangeEvent(this, rowIndex, rowValue); event.dispatch(handler); } } }