Java tutorial
package com.vaadin.addon.spreadsheet; /* * #%L * Vaadin Spreadsheet * %% * Copyright (C) 2013 - 2015 Vaadin Ltd * %% * This program is available under Commercial Vaadin Add-On License 3.0 * (CVALv3). * * See the file license.html distributed with this software for more * information about licensing. * * You should have received a copy of the CVALv3 along with this program. * If not, see <http://vaadin.com/license/cval-3>. * #L% */ import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeUtil; import org.apache.poi.ss.util.CellReference; import com.vaadin.addon.spreadsheet.Spreadsheet.SelectionChangeEvent; import com.vaadin.addon.spreadsheet.client.MergedRegion; import com.vaadin.addon.spreadsheet.client.MergedRegionUtil; /** * CellSelectionManager is an utility class for Spreadsheet, which handles * details of which cells are selected. * * @author Vaadin Ltd. */ @SuppressWarnings("serial") public class CellSelectionManager implements Serializable { private final Spreadsheet spreadsheet; private CellReference selectedCellReference; private CellRangeAddress paintedCellRange; private SelectionChangeEvent latestSelectionEvent; private final ArrayList<CellRangeAddress> cellRangeAddresses = new ArrayList<CellRangeAddress>(); private final ArrayList<CellReference> individualSelectedCells = new ArrayList<CellReference>(); /** * Creates a new CellSelectionManager and ties it to the given Spreadsheet * * @param spreadsheet */ public CellSelectionManager(Spreadsheet spreadsheet) { this.spreadsheet = spreadsheet; } /** * Clears all selection data */ public void clear() { selectedCellReference = null; paintedCellRange = null; cellRangeAddresses.clear(); individualSelectedCells.clear(); latestSelectionEvent = null; } /** * Returns reference to the currently selected single cell OR in case of * multiple selections the last cell clicked OR in case of area select the * cell from which the area selection was started. * * @return CellReference to selection */ public CellReference getSelectedCellReference() { return selectedCellReference; } /** * Returns the currently selected area in case there is only one area * selected. * * @return Single selected area */ public CellRangeAddress getSelectedCellRange() { return paintedCellRange; } /** * Returns references to all individually selected cells. * * @return List of references to single cell selections */ public List<CellReference> getIndividualSelectedCells() { return individualSelectedCells; } /** * Returns all selected areas. * * @return Selected areas */ public List<CellRangeAddress> getCellRangeAddresses() { return cellRangeAddresses; } /** * Returns the latest selection event. May be null if no selections have * been done, or clear() has been called prior to calling this method. * * @return Latest SelectionChangeEvent */ public SelectionChangeEvent getLatestSelectionEvent() { return latestSelectionEvent; } boolean isCellInsideSelection(int row, int column) { CellReference cellReference = new CellReference(row - 1, column - 1); boolean inside = cellReference.equals(selectedCellReference) || individualSelectedCells.contains(cellReference); if (!inside) { for (CellRangeAddress cra : cellRangeAddresses) { if (cra.isInRange(row - 1, column - 1)) { inside = true; break; } } } return inside; } /** * Reloads the current selection, but does not take non-coherent selection * into account - discards multiple cell ranges and individually selected * cells. */ protected void reloadCurrentSelection() { cellRangeAddresses.clear(); individualSelectedCells.clear(); if (paintedCellRange != null) { if (selectedCellReference != null) { if (paintedCellRange.isInRange(selectedCellReference.getRow(), selectedCellReference.getCol())) { handleCellRangeSelection(selectedCellReference, paintedCellRange, true); } else { paintedCellRange = null; handleCellAddressChange(selectedCellReference.getRow() + 1, selectedCellReference.getCol() + 1, false); } } else { handleCellRangeSelection( new CellReference(paintedCellRange.getFirstRow(), paintedCellRange.getFirstColumn()), paintedCellRange, true); } } else if (selectedCellReference != null) { handleCellAddressChange(selectedCellReference.getRow() + 1, selectedCellReference.getCol() + 1, false); } else { handleCellAddressChange(1, 1, false); } } /** * Sets/adds the cell at the given coordinates as/to the current selection. * * @param row * Row index, 1-based * @param column * Column index, 1-based * @param discardOldRangeSelection * true to discard previous selections, false to add to the * current selection */ protected void onCellSelected(int row, int column, boolean discardOldRangeSelection) { CellReference cellReference = new CellReference(row - 1, column - 1); CellReference previousCellReference = selectedCellReference; if (!cellReference.equals(previousCellReference) || discardOldRangeSelection && (!cellRangeAddresses.isEmpty() || !individualSelectedCells.isEmpty())) { handleCellSelection(row, column); selectedCellReference = cellReference; spreadsheet.loadCustomEditorOnSelectedCell(); if (discardOldRangeSelection) { cellRangeAddresses.clear(); individualSelectedCells.clear(); paintedCellRange = spreadsheet.createCorrectCellRangeAddress(row, column, row, column); } ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } } /** * This is called when the sheet's address field has been changed and the * sheet selection and function field must be updated. * * @param value * New value of the address field */ protected void onSheetAddressChanged(String value, boolean initialSelection) { try { if (value.contains(":")) { CellRangeAddress cra = spreadsheet.createCorrectCellRangeAddress(value); // need to check the range for merged regions MergedRegion region = MergedRegionUtil.findIncreasingSelection( spreadsheet.getMergedRegionContainer(), cra.getFirstRow() + 1, cra.getLastRow() + 1, cra.getFirstColumn() + 1, cra.getLastColumn() + 1); if (region != null) { cra = new CellRangeAddress(region.row1 - 1, region.row2 - 1, region.col1 - 1, region.col2 - 1); } handleCellRangeSelection(cra); selectedCellReference = new CellReference(cra.getFirstRow(), cra.getFirstColumn()); paintedCellRange = cra; cellRangeAddresses.clear(); cellRangeAddresses.add(cra); } else { final CellReference cellReference = new CellReference(value); MergedRegion region = MergedRegionUtil.findIncreasingSelection( spreadsheet.getMergedRegionContainer(), cellReference.getRow() + 1, cellReference.getRow() + 1, cellReference.getCol() + 1, cellReference.getCol() + 1); if (region != null && (region.col1 != region.col2 || region.row1 != region.row2)) { CellRangeAddress cra = spreadsheet.createCorrectCellRangeAddress(region.row1, region.col1, region.row2, region.col2); handleCellRangeSelection(cra); selectedCellReference = new CellReference(cra.getFirstRow(), cra.getFirstColumn()); paintedCellRange = cra; cellRangeAddresses.clear(); cellRangeAddresses.add(cra); } else { handleCellAddressChange(cellReference.getRow() + 1, cellReference.getCol() + 1, initialSelection); paintedCellRange = spreadsheet.createCorrectCellRangeAddress(cellReference.getRow() + 1, cellReference.getCol() + 1, cellReference.getRow() + 1, cellReference.getCol() + 1); selectedCellReference = cellReference; cellRangeAddresses.clear(); } } individualSelectedCells.clear(); spreadsheet.loadCustomEditorOnSelectedCell(); ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } catch (Exception e) { spreadsheet.getRpcProxy().invalidCellAddress(); } } /** * Reports the correct cell selection value (formula/data) and selection. * This method is called when the cell selection has changed via the address * field. * * @param rowIndex * Index of row, 1-based * @param columnIndex * Index of column, 1-based */ private void handleCellAddressChange(int rowIndex, int colIndex, boolean initialSelection) { if (rowIndex >= spreadsheet.getState().rows) { rowIndex = spreadsheet.getState().rows; } if (colIndex >= spreadsheet.getState().cols) { colIndex = spreadsheet.getState().cols; } MergedRegion region = MergedRegionUtil.findIncreasingSelection(spreadsheet.getMergedRegionContainer(), rowIndex, rowIndex, colIndex, colIndex); if (region.col1 != region.col2 || region.row1 != region.row2) { handleCellRangeSelection( new CellRangeAddress(region.row1 - 1, region.row2 - 1, region.col1 - 1, region.col2 - 1)); } else { rowIndex = region.row1; colIndex = region.col1; Workbook workbook = spreadsheet.getWorkbook(); final Row row = workbook.getSheetAt(workbook.getActiveSheetIndex()).getRow(rowIndex - 1); if (row != null) { final Cell cell = row.getCell(colIndex - 1); if (cell != null) { String value = ""; boolean formula = cell.getCellType() == Cell.CELL_TYPE_FORMULA; if (!spreadsheet.isCellHidden(cell)) { if (formula) { value = cell.getCellFormula(); } else { value = spreadsheet.getCellValue(cell); } } spreadsheet.getRpcProxy().showSelectedCell(colIndex, rowIndex, value, formula, spreadsheet.isCellLocked(cell), initialSelection); } else { spreadsheet.getRpcProxy().showSelectedCell(colIndex, rowIndex, "", false, spreadsheet.isCellLocked(cell), initialSelection); } } else { spreadsheet.getRpcProxy().showSelectedCell(colIndex, rowIndex, "", false, spreadsheet.isActiveSheetProtected(), initialSelection); } } } /** * Reselects the currently selected single cell */ protected void reSelectSelectedCell() { if (selectedCellReference != null) { handleCellSelection(selectedCellReference); } } /** * Selects a single cell from the active sheet * * @param cellReference * Reference to the cell to be selected */ protected void handleCellSelection(CellReference cellReference) { handleCellSelection(cellReference.getRow() + 1, cellReference.getCol() + 1); } /** * Reports the selected cell formula value, if any. This method is called * when the cell value has changed via sheet cell selection change. * * This method can also be used when the selected cell has NOT changed but * the value it displays on the formula field might have changed and needs * to be updated. * * @param rowIndex * 1-based * @param columnIndex * 1-based */ private void handleCellSelection(int rowIndex, int columnIndex) { Workbook workbook = spreadsheet.getWorkbook(); final Row row = workbook.getSheetAt(workbook.getActiveSheetIndex()).getRow(rowIndex - 1); if (row != null) { final Cell cell = row.getCell(columnIndex - 1); if (cell != null) { String value = ""; boolean formula = cell.getCellType() == Cell.CELL_TYPE_FORMULA; if (!spreadsheet.isCellHidden(cell)) { if (formula) { value = cell.getCellFormula(); } else { value = spreadsheet.getCellValue(cell); } } spreadsheet.getRpcProxy().showCellValue(value, columnIndex, rowIndex, formula, spreadsheet.isCellLocked(cell)); } else { spreadsheet.getRpcProxy().showCellValue("", columnIndex, rowIndex, false, spreadsheet.isCellLocked(cell)); } } else { spreadsheet.getRpcProxy().showCellValue("", columnIndex, rowIndex, false, spreadsheet.isActiveSheetProtected()); } } /** * Handles the new cell range that was given in the address field, returns * the range and new selected cell formula/value (if any) * * @param cra * Range of cells to select */ protected void handleCellRangeSelection(CellRangeAddress cra) { int row1 = cra.getFirstRow(); int row2 = cra.getLastRow(); int col1 = cra.getFirstColumn(); int col2 = cra.getLastColumn(); Workbook workbook = spreadsheet.getWorkbook(); final Row row = workbook.getSheetAt(workbook.getActiveSheetIndex()).getRow(row1); if (row != null) { final Cell cell = row.getCell(col1); if (cell != null) { String value = ""; boolean formula = cell.getCellType() == Cell.CELL_TYPE_FORMULA; if (!spreadsheet.isCellHidden(cell)) { if (formula) { value = cell.getCellFormula(); } else { value = spreadsheet.getCellValue(cell); } } spreadsheet.getRpcProxy().showSelectedCellRange(col1 + 1, col2 + 1, row1 + 1, row2 + 1, value, formula, spreadsheet.isCellLocked(cell)); } else { spreadsheet.getRpcProxy().showSelectedCellRange(col1 + 1, col2 + 1, row1 + 1, row2 + 1, "", false, spreadsheet.isCellLocked(cell)); } } else { spreadsheet.getRpcProxy().showSelectedCellRange(col1 + 1, col2 + 1, row1 + 1, row2 + 1, "", false, spreadsheet.isActiveSheetProtected()); } } /** * Sets the given range and starting point as the current selection. * * @param startingPoint * Reference to starting point * @param cellsToSelect * Selection area */ protected void handleCellRangeSelection(CellReference startingPoint, CellRangeAddress cellsToSelect, boolean scroll) { int row1 = cellsToSelect.getFirstRow(); int row2 = cellsToSelect.getLastRow(); int col1 = cellsToSelect.getFirstColumn(); int col2 = cellsToSelect.getLastColumn(); Workbook workbook = spreadsheet.getWorkbook(); final Row row = workbook.getSheetAt(workbook.getActiveSheetIndex()).getRow(startingPoint.getRow()); if (row != null) { final Cell cell = row.getCell(startingPoint.getCol()); if (cell != null) { String value = ""; boolean formula = cell.getCellType() == Cell.CELL_TYPE_FORMULA; if (!spreadsheet.isCellHidden(cell)) { if (formula) { value = cell.getCellFormula(); } else { value = spreadsheet.getCellValue(cell); } } spreadsheet.getRpcProxy().setSelectedCellAndRange(startingPoint.getCol() + 1, startingPoint.getRow() + 1, col1 + 1, col2 + 1, row1 + 1, row2 + 1, value, formula, spreadsheet.isCellLocked(cell), scroll); } else { spreadsheet.getRpcProxy().setSelectedCellAndRange(startingPoint.getCol() + 1, startingPoint.getRow() + 1, col1 + 1, col2 + 1, row1 + 1, row2 + 1, "", false, spreadsheet.isCellLocked(cell), scroll); } } else { spreadsheet.getRpcProxy().setSelectedCellAndRange(startingPoint.getCol() + 1, startingPoint.getRow() + 1, col1 + 1, col2 + 1, row1 + 1, row2 + 1, "", false, spreadsheet.isActiveSheetProtected(), scroll); } selectedCellReference = startingPoint; cellRangeAddresses.clear(); individualSelectedCells.clear(); paintedCellRange = cellsToSelect; if (col1 != col2 || row1 != row2) { cellRangeAddresses.add(cellsToSelect); } ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } /** * Sets the given range as the current selection * * @param cra * New cell range to be selected */ protected void cellRangeSelected(CellRangeAddress cra) { onCellRangeSelected(cra.getFirstRow() + 1, cra.getFirstColumn() + 1, cra.getLastRow() + 1, cra.getLastColumn() + 1); } /** * Sets the given range as the current selection. * * @param row1 * Starting row index, 1-based * @param col1 * Starting column index, 1-based * @param row2 * Ending row index, 1-based * @param col2 * Ending column index, 1-based */ protected void onCellRangeSelected(int row1, int col1, int row2, int col2) { cellRangeAddresses.clear(); individualSelectedCells.clear(); CellRangeAddress cra = spreadsheet.createCorrectCellRangeAddress(row1, col1, row2, col2); paintedCellRange = cra; if (col1 != col2 || row1 != row2) { cellRangeAddresses.add(cra); } ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } /** * Sets the given range and starting point as the current selection. * * @param selectedCellRow * Index of the row where the paint was started, 1-based * @param selectedCellColumn * Index of the column where the paint was started, 1-based * @param row1 * Starting row index, 1-based * @param col1 * Starting column index, 1-based * @param row2 * Ending row index, 1-based * @param col2 * Ending column index, 1-based */ protected void onCellRangePainted(int selectedCellRow, int selectedCellColumn, int row1, int col1, int row2, int col2) { cellRangeAddresses.clear(); individualSelectedCells.clear(); selectedCellReference = new CellReference(selectedCellRow - 1, selectedCellColumn - 1); handleCellSelection(selectedCellRow, selectedCellColumn); CellRangeAddress cra = spreadsheet.createCorrectCellRangeAddress(row1, col1, row2, col2); paintedCellRange = cra; cellRangeAddresses.add(cra); ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } /** * Adds the cell at the given coordinates to the current selection. * * @param row * Row index, 1-based * @param column * Column index, 1-based */ protected void onCellAddToSelectionAndSelected(int row, int column) { boolean oldSelectedCellInRange = false; for (CellRangeAddress range : cellRangeAddresses) { if (range.isInRange(selectedCellReference.getRow(), selectedCellReference.getCol())) { oldSelectedCellInRange = true; break; } } boolean oldSelectedCellInIndividual = false; for (CellReference cell : individualSelectedCells) { if (cell.equals(selectedCellReference)) { // it shouldn't be there yet(!) oldSelectedCellInIndividual = true; break; } } if (!oldSelectedCellInRange && !oldSelectedCellInIndividual) { individualSelectedCells.add(selectedCellReference); } handleCellSelection(row, column); selectedCellReference = new CellReference(row - 1, column - 1); spreadsheet.loadCustomEditorOnSelectedCell(); if (individualSelectedCells.contains(selectedCellReference)) { individualSelectedCells.remove(individualSelectedCells.indexOf(selectedCellReference)); } paintedCellRange = null; ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } /** * This is called when a cell range has been added to the current selection. * * @param row1 * Starting row index, 1-based * @param col1 * Starting column index, 1-based * @param row2 * Ending row index, 1-based * @param col2 * Ending column index, 1-based */ protected void onCellsAddedToRangeSelection(int row1, int col1, int row2, int col2) { CellRangeAddress newRange = spreadsheet.createCorrectCellRangeAddress(row1, col1, row2, col2); for (Iterator<CellReference> i = individualSelectedCells.iterator(); i.hasNext();) { CellReference cell = i.next(); if (newRange.isInRange(cell.getRow(), cell.getCol())) { i.remove(); } } cellRangeAddresses.add(newRange); paintedCellRange = null; ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } /** * This is called when a row has been made the current selection * * @param row * Index of target row, 1-based * @param firstColumnIndex * Index of first column, 1-based */ protected void onRowSelected(int row, int firstColumnIndex) { handleCellSelection(row, firstColumnIndex); selectedCellReference = new CellReference(row - 1, firstColumnIndex - 1); spreadsheet.loadCustomEditorOnSelectedCell(); cellRangeAddresses.clear(); individualSelectedCells.clear(); CellRangeAddress cra = spreadsheet.createCorrectCellRangeAddress(row, 1, row, spreadsheet.getColumns()); paintedCellRange = cra; cellRangeAddresses.add(cra); ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } /** * This is called when a row has been added to the current selection * * @param row * Index of target row, 1-based * @param firstColumnIndex * Index of first column, 1-based */ protected void onRowAddedToRangeSelection(int row, int firstColumnIndex) { boolean oldSelectedCellInRange = false; for (CellRangeAddress range : cellRangeAddresses) { if (range.isInRange(selectedCellReference.getRow(), selectedCellReference.getCol())) { oldSelectedCellInRange = true; break; } } if (!oldSelectedCellInRange) { individualSelectedCells.add(selectedCellReference); } handleCellSelection(row, firstColumnIndex); selectedCellReference = new CellReference(row - 1, firstColumnIndex - 1); spreadsheet.loadCustomEditorOnSelectedCell(); cellRangeAddresses.add(spreadsheet.createCorrectCellRangeAddress(row, 1, row, spreadsheet.getColumns())); paintedCellRange = null; ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } /** * This is called when a column has made the current selection * * @param firstRowIndex * Index of first row, 1-based * @param column * Index of target column, 1-based */ protected void onColumnSelected(int firstRowIndex, int column) { handleCellSelection(firstRowIndex, column); selectedCellReference = new CellReference(firstRowIndex - 1, column - 1); spreadsheet.loadCustomEditorOnSelectedCell(); cellRangeAddresses.clear(); individualSelectedCells.clear(); CellRangeAddress cra = spreadsheet.createCorrectCellRangeAddress(1, column, spreadsheet.getRows(), column); paintedCellRange = cra; cellRangeAddresses.add(cra); ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } /** * This is called when a column has been added to the current selection * * @param firstRowIndex * Index of first row, 1-based * @param column * Index of target column, 1-based */ protected void onColumnAddedToSelection(int firstRowIndex, int column) { boolean oldSelectedCellInRange = false; for (CellRangeAddress range : cellRangeAddresses) { if (range.isInRange(selectedCellReference.getRow(), selectedCellReference.getCol())) { oldSelectedCellInRange = true; break; } } if (!oldSelectedCellInRange) { individualSelectedCells.add(selectedCellReference); } handleCellSelection(firstRowIndex, column); selectedCellReference = new CellReference(firstRowIndex - 1, column - 1); spreadsheet.loadCustomEditorOnSelectedCell(); cellRangeAddresses.add(spreadsheet.createCorrectCellRangeAddress(1, column, spreadsheet.getRows(), column)); paintedCellRange = null; ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } /** * This is called when a merged region has been added, since the selection * may need to be updated. * * @param region * Merged region that was added */ protected void mergedRegionAdded(CellRangeAddress region) { if (selectedCellReference == null) { return; } boolean fire = false; if (region.isInRange(selectedCellReference.getRow(), selectedCellReference.getCol())) { if (selectedCellReference.getCol() != region.getFirstColumn() || selectedCellReference.getRow() != region.getFirstRow()) { handleCellAddressChange(region.getFirstRow() + 1, region.getFirstColumn() + 1, false); } selectedCellReference = new CellReference(region.getFirstRow(), region.getFirstColumn()); fire = true; } for (Iterator<CellRangeAddress> i = cellRangeAddresses.iterator(); i.hasNext();) { CellRangeAddress cra = i.next(); if (CellRangeUtil.contains(region, cra)) { i.remove(); fire = true; } } for (Iterator<CellReference> i = individualSelectedCells.iterator(); i.hasNext();) { CellReference cr = i.next(); if (region.isInRange(cr.getRow(), cr.getCol())) { i.remove(); fire = true; } } if (fire) { fireNewSelectionChangeEvent(); } } /** * This is called when a merged region is removed, since the selection may * need to be updated. * * @param region * Merged region that was removed */ protected void mergedRegionRemoved(CellRangeAddress region) { if (selectedCellReference == null) { return; } if (region.isInRange(selectedCellReference.getRow(), selectedCellReference.getCol())) { cellRangeAddresses.add(region); ensureClientHasSelectionData(); fireNewSelectionChangeEvent(); } } /** * Make sure that the selected ranges are available on the client side. */ private void ensureClientHasSelectionData() { // Make sure data for the selection has been loaded so it can be copied for (CellRangeAddress cellRangeAddress : cellRangeAddresses) { spreadsheet.loadCells(cellRangeAddress.getFirstRow() + 1, cellRangeAddress.getFirstColumn() + 1, cellRangeAddress.getLastRow() + 1, cellRangeAddress.getLastColumn() + 1); } } /** * Fires a new SelectionChangeEvent based on the internal selection state. */ private void fireNewSelectionChangeEvent() { CellRangeAddress selectedCellMergedRegion = null; MergedRegion region = spreadsheet.getMergedRegionContainer().getMergedRegionStartingFrom( selectedCellReference.getCol() + 1, selectedCellReference.getRow() + 1); if (region != null) { selectedCellMergedRegion = new CellRangeAddress(region.row1 - 1, region.row2 - 1, region.col1 - 1, region.col2 - 1); // if the only range is the merged region, clear ranges if (cellRangeAddresses.size() == 1 && cellRangeAddresses.get(0).formatAsString() .equals(selectedCellMergedRegion.formatAsString())) { cellRangeAddresses.clear(); } } if (latestSelectionEvent != null) { boolean changed = false; if (!latestSelectionEvent.getSelectedCellReference().equals(selectedCellReference)) { changed = true; } if (!changed) { if (latestSelectionEvent.getIndividualSelectedCells().size() != individualSelectedCells.size()) { changed = true; } else { for (CellReference cr : latestSelectionEvent.getIndividualSelectedCells()) { if (!individualSelectedCells.contains(cr)) { changed = true; break; } } } } if (!changed) { if (latestSelectionEvent.getCellRangeAddresses().size() != cellRangeAddresses.size()) { changed = true; } else { for (CellRangeAddress cra : latestSelectionEvent.getCellRangeAddresses()) { if (!cellRangeAddresses.contains(cra)) { changed = true; break; } } } } if (!changed) { CellRangeAddress previouSelectedCellMergedRegion = latestSelectionEvent .getSelectedCellMergedRegion(); if ((previouSelectedCellMergedRegion == null && selectedCellMergedRegion != null) || (previouSelectedCellMergedRegion != null && !previouSelectedCellMergedRegion.equals(selectedCellMergedRegion))) { changed = true; } } if (!changed) { return; } } ArrayList<CellReference> cellRefCopy = new ArrayList<CellReference>(individualSelectedCells); ArrayList<CellRangeAddress> rangeCopy = new ArrayList<CellRangeAddress>(cellRangeAddresses); latestSelectionEvent = new SelectionChangeEvent(spreadsheet, selectedCellReference, cellRefCopy, selectedCellMergedRegion, rangeCopy); spreadsheet.fireEvent(latestSelectionEvent); } }