/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ package org.geogebra.common.kernel.statistics; import java.util.Iterator; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoElementSpreadsheet; import org.geogebra.common.kernel.geos.GeoNumberValue; /** * Returns the GeoElement from an object's coordinates in the spreadsheet. * * @author Michael, Markus */ public class AlgoCell extends AlgoElement { private GeoElement geo; // output private GeoNumberValue a, b; // input private String currentLabel; private GeoElement refObject; // referenced object private GeoElement[] inputForUpdateSetPropagation; /** * @param cons * construction * @param label * label for output * @param a * column * @param b * row */ public AlgoCell(Construction cons, String label, GeoNumberValue a, GeoNumberValue b) { super(cons); this.a = a; this.b = b; setInputOutput(); // for AlgoElement // compute value of dependent number compute(); // register as rename listener algorithm kernel.registerRenameListenerAlgo(this); geo.setLabel(label); } @Override public Commands getClassName() { return Commands.Cell; } // for AlgoElement @Override protected void setInputOutput() { // input is the text input = new GeoElement[2]; input[0] = a.toGeoElement(); input[1] = b.toGeoElement(); // input for updateSet propagation is text and reference object inputForUpdateSetPropagation = new GeoElement[3]; inputForUpdateSetPropagation[0] = input[0]; inputForUpdateSetPropagation[1] = input[1]; // get referenced object updateReferencedObject(); // create output object as copy of referenced object if (refObject != null) { geo = refObject.copyInternal(cons); geo.setVisualStyle(refObject); geo.setUseVisualDefaults(false); } else { geo = cons.getOutputGeo(); geo.setUndefined(); } // output is a copy of the referenced object super.setOutputLength(1); super.setOutput(0, geo); setDependencies(); } /** * * @return cell at given position */ public GeoElement getResult() { return geo; } @Override public final void compute() { if (input[0].isDefined() && input[1].isDefined()) { updateReferencedObject(); // } // check if updateInput has same type if (refObject != null && refObject.getGeoClassType() == geo.getGeoClassType()) { geo.set(refObject); } else { geo.setUndefined(); } } else { geo.setUndefined(); } } private void updateReferencedObject() { // get new object currentLabel = GeoElementSpreadsheet.getSpreadsheetCellName( (int) a.getDouble() - 1, (int) b.getDouble() - 1); /* * Do not remove this algorithm from update set of old referenced * object: This will speed up the calls to * refObject.addToUpdateSetOnly() below, because it will always stop * propagating up at refObject. * * if (refObject != null) { refObject.getAlgoUpdateSet().remove(this); } */ // lookup new object for new label refObject = kernel.lookupLabel(currentLabel); inputForUpdateSetPropagation[2] = refObject; // change dependencies for this newly referenced object if (refObject != null) { // add this algorithm and all its dependent algos to the update set // of the newly referenced geo refObject.addToUpdateSetOnly(this); if (geo != null) { Iterator<AlgoElement> it = geo.getAlgoUpdateSet().getIterator(); while (it.hasNext()) { refObject.addToUpdateSetOnly(it.next()); } } } } /** * Returns an input array with the text and the referenced geo */ @Override public GeoElement[] getInputForUpdateSetPropagation() { if (refObject == null) { return input; } return inputForUpdateSetPropagation; } }