package org.geogebra.common.gui.view.spreadsheet; import org.geogebra.common.awt.GPoint; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoElementSpreadsheet; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.main.App; import org.geogebra.common.util.debug.Log; public class SpreadsheetModeProcessor { private App app; private Kernel kernel; private CopyPasteCut copyPasteCut; private MyTable table; private GeoElement targetCell; public SpreadsheetModeProcessor(App app, MyTable table) { this.app = app; this.kernel = app.getKernel(); this.copyPasteCut = table.getCopyPasteCut(); this.table = table; } /** * Creates autofunction cells based on the given cell range and the current * autofunction mode. */ public void performAutoFunctionCreation(CellRange cr, boolean shiftDown) { if (cr.isColumn() || cr.isRow()) { return; } boolean isOK = true; GeoElement targetCell1 = null; CellRange targetRange; // Case 1: Partial row, targetCell created beneath the column if (cr.isPartialRow() || (!cr.isPartialColumn() && shiftDown)) { int maxColumn = getMaxUsedColumn(cr) + 1; targetRange = new CellRange(app, maxColumn, cr.getMinRow(), maxColumn, cr.getMaxRow()); for (int row = cr.getMinRow(); row <= cr.getMaxRow(); row++) { // try to clear the target cell, exit if this is not possible if (RelativeCopy.getValue(app, maxColumn, row) != null) { isOK = copyPasteCut.delete(maxColumn, row, maxColumn, row); } // create new targetCell if (isOK) { targetCell1 = new GeoNumeric(kernel.getConstruction(), 0); targetCell1.setLabel(GeoElementSpreadsheet .getSpreadsheetCellName(maxColumn, row)); createAutoFunctionCell(targetCell1, new CellRange(app, cr.getMinColumn(), row, maxColumn - 1, row)); } } app.setMoveMode(); table.setSelection(targetRange); table.repaint(); } else { int maxRow = getMaxUsedRow(cr) + 1; targetRange = new CellRange(app, cr.getMinColumn(), maxRow, cr.getMaxColumn(), maxRow); for (int col = cr.getMinColumn(); col <= cr.getMaxColumn(); col++) { // try to clear the target cell, exit if this is not possible if (RelativeCopy.getValue(app, col, maxRow) != null) { isOK = copyPasteCut.delete(col, maxRow, col, maxRow); } // create new targetCell if (isOK) { String cellName = GeoElementSpreadsheet .getSpreadsheetCellName(col, maxRow); GeoElement cell = kernel.lookupLabel(cellName); if (cell == null) { targetCell1 = new GeoNumeric(kernel.getConstruction(), 0); targetCell1.setLabel(cellName); } else { targetCell1 = cell; } createAutoFunctionCell(targetCell1, new CellRange(app, col, cr.getMinRow(), col, maxRow - 1)); } } app.setMoveMode(); table.setSelection(targetRange); table.repaint(); } } private int getMaxUsedColumn(CellRange cr) { if (cr.isRow() || cr.isColumn()) { return cr.getMaxColumn(); } for (int row = cr.getMinRow(); row <= cr.getMaxRow(); row++) { if (kernel.getGeoAt(cr.getMaxColumn(), row) != null) { return cr.getMaxColumn(); } } return cr.getMaxColumn() - 1; } private int getMaxUsedRow(CellRange cr) { if (cr.isRow() || cr.isColumn()) { return cr.getMaxRow(); } for (int col = cr.getMinColumn(); col <= cr.getMaxColumn(); col++) { if (kernel.getGeoAt(col, cr.getMaxRow()) != null) { return cr.getMaxRow(); } } return cr.getMaxRow() - 1; } /** * Creates an autofunction in the given target cell based on the current * autofunction mode and the given cell range. */ public boolean createAutoFunctionCell(GeoElement targetCell, CellRange cr) { boolean success = true; // Get the targetCell label and the selected cell range String targetCellLabel = targetCell.getLabelSimple(); String cellRangeString = table.getCellRangeProcessor() .getCellRangeString(cr); // Create a String expression for the new autofunction command geo String cmd = null; if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_SUM) { cmd = "Sum"; } else if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_COUNT) { cmd = "Length"; } else if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_AVERAGE) { cmd = "Mean"; } else if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_MAX) { cmd = "Max"; } else if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_MIN) { cmd = "Min"; } String expr = targetCellLabel + " = " + cmd + "[" + cellRangeString + "]"; Log.debug(expr); // Create the new geo if (!cr.contains(targetCell)) { kernel.getAlgebraProcessor().processAlgebraCommandNoExceptions(expr, false); } else { targetCell.setUndefined(); success = false; } return success; } /** * Stops the autofunction from updating and creates a new geo for the target * cell based on the current autofunction mode. */ public void stopAutoFunction() { table.setTableMode(MyTable.TABLE_MODE_STANDARD); if (createAutoFunctionCell(targetCell, table.getSelectedCellRanges().get(0))) { // select the new geo app.setMoveMode(); GPoint coords = targetCell.getSpreadsheetCoords(); table.changeSelection(coords.y, coords.x, false); table.repaint(); } } public void initTargetCell(int minSelectionColumn, int minSelectionRow) { targetCell = new GeoNumeric(kernel.getConstruction(), 0); targetCell.setLabel(GeoElementSpreadsheet .getSpreadsheetCellName(minSelectionColumn, minSelectionRow)); targetCell.setUndefined(); } /** * Updates the autofunction by recalculating the autofunction value as the * user drags the mouse to create a selection. The current autofunction * value is displayed in the targetCell. */ public void updateAutoFunction() { if (targetCell == null || table.getSelectedCellRanges().get(0).isEmpty() || table.getTableMode() != MyTable.TABLE_MODE_AUTOFUNCTION) { app.setMoveMode(); return; } // Get a string representation of the seleced range (e.g. A1:B3) String cellRangeString = table.getCellRangeProcessor() .getCellRangeString(table.getSelectedCellRanges().get(0)); // Build a String expression for the autofunction String cmd = null; if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_SUM) { cmd = "Sum"; } else if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_COUNT) { cmd = "Length"; } else if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_AVERAGE) { cmd = "Mean"; } else if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_MAX) { cmd = "Max"; } else if (app.getMode() == EuclidianConstants.MODE_SPREADSHEET_MIN) { cmd = "Min"; } String expr = cmd + "[" + cellRangeString + "]"; // Evaluate the autofunction and put the result in targetCell if (!table.getSelectedCellRanges().get(0).contains(targetCell)) { ((GeoNumeric) targetCell).setValue( kernel.getAlgebraProcessor().evaluateToDouble(expr)); } else { ((GeoNumeric) targetCell).setUndefined(); } } }