/*
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.
*/
/*
* MyXMLHandler.java
*
* Created on 14. Juni 2003, 12:04
*/
package org.geogebra.common.io;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.TreeMap;
import org.geogebra.common.GeoGebraConstants;
import org.geogebra.common.awt.GColor;
import org.geogebra.common.awt.GDimension;
import org.geogebra.common.awt.GFont;
import org.geogebra.common.awt.GPoint;
import org.geogebra.common.awt.GRectangle;
import org.geogebra.common.factories.AwtFactory;
import org.geogebra.common.gui.dialog.options.OptionsCAS;
import org.geogebra.common.gui.view.data.DataAnalysisModel.Regression;
import org.geogebra.common.gui.view.data.DataDisplayModel.PlotType;
import org.geogebra.common.io.layout.DockPanelData;
import org.geogebra.common.io.layout.DockSplitPaneData;
import org.geogebra.common.io.layout.Perspective;
import org.geogebra.common.javax.swing.SwingConstants;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.KernelCAS;
import org.geogebra.common.kernel.Locateable;
import org.geogebra.common.kernel.Macro;
import org.geogebra.common.kernel.MacroConstruction;
import org.geogebra.common.kernel.MacroKernel;
import org.geogebra.common.kernel.PathRegionHandling;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.algos.AlgoBarChart;
import org.geogebra.common.kernel.arithmetic.Command;
import org.geogebra.common.kernel.arithmetic.Equation;
import org.geogebra.common.kernel.arithmetic.ExpressionNode;
import org.geogebra.common.kernel.arithmetic.NumberValue;
import org.geogebra.common.kernel.arithmetic.ValidExpression;
import org.geogebra.common.kernel.arithmetic.Variable;
import org.geogebra.common.kernel.arithmetic.VectorNDValue;
import org.geogebra.common.kernel.commands.AlgebraProcessor;
import org.geogebra.common.kernel.commands.EvalInfo;
import org.geogebra.common.kernel.geos.AbsoluteScreenLocateable;
import org.geogebra.common.kernel.geos.AngleProperties;
import org.geogebra.common.kernel.geos.CasEvaluableFunction;
import org.geogebra.common.kernel.geos.GeoBoolean;
import org.geogebra.common.kernel.geos.GeoButton;
import org.geogebra.common.kernel.geos.GeoCasCell;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoElement.FillType;
import org.geogebra.common.kernel.geos.GeoFunction;
import org.geogebra.common.kernel.geos.GeoFunctionNVar;
import org.geogebra.common.kernel.geos.GeoImage;
import org.geogebra.common.kernel.geos.GeoInputBox;
import org.geogebra.common.kernel.geos.GeoList;
import org.geogebra.common.kernel.geos.GeoNumberValue;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.geos.GeoPoint;
import org.geogebra.common.kernel.geos.GeoPolyLine;
import org.geogebra.common.kernel.geos.GeoText;
import org.geogebra.common.kernel.geos.GeoVec3D;
import org.geogebra.common.kernel.geos.HasSymbolicMode;
import org.geogebra.common.kernel.geos.LimitedPath;
import org.geogebra.common.kernel.geos.PointProperties;
import org.geogebra.common.kernel.geos.TextProperties;
import org.geogebra.common.kernel.geos.Traceable;
import org.geogebra.common.kernel.implicit.GeoImplicit;
import org.geogebra.common.kernel.kernelND.CoordStyle;
import org.geogebra.common.kernel.kernelND.GeoConicND;
import org.geogebra.common.kernel.kernelND.GeoElementND;
import org.geogebra.common.kernel.kernelND.GeoLineND;
import org.geogebra.common.kernel.kernelND.GeoPointND;
import org.geogebra.common.kernel.parser.GParser;
import org.geogebra.common.kernel.parser.Parser;
import org.geogebra.common.kernel.prover.AlgoProve;
import org.geogebra.common.main.App;
import org.geogebra.common.main.App.InputPosition;
import org.geogebra.common.main.Localization;
import org.geogebra.common.main.MyError;
import org.geogebra.common.main.error.ErrorHandler;
import org.geogebra.common.main.error.ErrorHelper;
import org.geogebra.common.main.settings.ConstructionProtocolSettings;
import org.geogebra.common.main.settings.DataAnalysisSettings;
import org.geogebra.common.main.settings.DataCollectionSettings;
import org.geogebra.common.main.settings.EuclidianSettings;
import org.geogebra.common.main.settings.KeyboardSettings;
import org.geogebra.common.main.settings.ProbabilityCalculatorSettings.DIST;
import org.geogebra.common.main.settings.SpreadsheetSettings;
import org.geogebra.common.plugin.EuclidianStyleConstants;
import org.geogebra.common.plugin.GeoClass;
import org.geogebra.common.plugin.ScriptType;
import org.geogebra.common.plugin.SensorLogger.Types;
import org.geogebra.common.plugin.script.JsScript;
import org.geogebra.common.plugin.script.Script;
import org.geogebra.common.util.Assignment;
import org.geogebra.common.util.Assignment.Result;
import org.geogebra.common.util.AsyncOperation;
import org.geogebra.common.util.Exercise;
import org.geogebra.common.util.GeoAssignment;
import org.geogebra.common.util.SpreadsheetTraceSettings;
import org.geogebra.common.util.StringUtil;
import org.geogebra.common.util.Util;
import org.geogebra.common.util.debug.Log;
import org.xml.sax.SAXException;
/**
*
* @author Markus Hohenwarter
*/
// public class MyXMLHandler extends DefaultHandler {
public class MyXMLHandler implements DocHandler {
private static final double FORMAT = StringUtil
.parseDouble(GeoGebraConstants.XML_FILE_FORMAT);
private static final int MODE_INVALID = -1;
private static final int MODE_GEOGEBRA = 1;
private static final int MODE_MACRO = 50;
private static final int MODE_ASSIGNMENT = 60;
private static final int MODE_EUCLIDIAN_VIEW = 100;
/** currently parsing tags for Euclidian3D view */
protected static final int MODE_EUCLIDIAN_VIEW3D = 101; // only for 3D
private static final int MODE_SPREADSHEET_VIEW = 150;
private static final int MODE_ALGEBRA_VIEW = 151;
private static final int MODE_DATA_COLLECTION_VIEW = 152;
// private static final int MODE_CAS_VIEW = 160;
private static final int MODE_CONST_CAS_CELL = 161;
private static final int MODE_CAS_CELL_PAIR = 162;
private static final int MODE_CAS_INPUT_CELL = 163;
private static final int MODE_CAS_OUTPUT_CELL = 164;
private static final int MODE_CAS_TEXT_CELL = 165;
private static final int MODE_CAS_MAP = 166;
private static final int MODE_PROBABILITY_CALCULATOR = 170;
private static final int MODE_KERNEL = 200;
private static final int MODE_CONSTRUCTION = 300;
private static final int MODE_CONST_GEO_ELEMENT = 301;
private static final int MODE_CONST_COMMAND = 302;
private static final int MODE_GUI = 400;
private static final int MODE_GUI_PERSPECTIVES = 401; // <perspectives>
private static final int MODE_GUI_PERSPECTIVE = 402; // <perspective>
private static final int MODE_GUI_PERSPECTIVE_PANES = 403; // <perspective>
// <panes />
// </perspective>
private static final int MODE_GUI_PERSPECTIVE_VIEWS = 404; // <perspective>
// <views />
// </perspective>
private static final int MODE_DATA_ANALYSIS = 450;
private static final int MODE_DEFAULTS = 500;
private static final int MODE_DEFAULT_GEO = 501;
/**
* we used minimal text size of 4px until 4.0 for texts, because the font
* size setting was additive. Not needed with current multiplicative
* approach, just for opening old files.
*/
private static final double MIN_TEXT_SIZE = 4;
private int mode;
private int constMode; // submode for <construction>
private int casMode; // submode for <cascell>
/** currently parsed element */
protected GeoElement geo;
private GeoCasCell geoCasCell;
private Command cmd;
private Macro macro;
private Exercise exercise;
private Assignment assignment;
/** application */
protected final App app;
/** lacalization */
protected final Localization loc;
private String[] macroInputLabels, macroOutputLabels;
private GeoElementND[] cmdOutput;
private boolean startAnimation;
/**
* The point style of the document, for versions < 3.3
*/
private int docPointStyle;
// for macros we need to change the kernel, so remember the original kernel
// too
private Kernel kernel, origKernel;
/** construction */
protected Construction cons;
private Parser parser, origParser;
// List of LocateableExpPair objects
// for setting the start points at the end of the construction
// (needed for GeoText and GeoVector)
private LinkedList<LocateableExpPair> startPointList = new LinkedList<LocateableExpPair>();
// List of GeoExpPair objects
// for setting the linked geos needed for GeoTextFields
private LinkedList<GeoExpPair> linkedGeoList = new LinkedList<GeoExpPair>();
// List of GeoExpPair condition objects
// for setting the conditions at the end of the construction
// (needed for GeoText and GeoVector)
private LinkedList<GeoExpPair> showObjectConditionList = new LinkedList<GeoExpPair>();
private LinkedList<GeoExpPair> dynamicColorList = new LinkedList<GeoExpPair>();
private LinkedList<GeoExpPair> animationSpeedList = new LinkedList<GeoExpPair>();
private LinkedList<GeoExpPair> animationStepList = new LinkedList<GeoExpPair>();
private LinkedList<GeoElement> animatingList = new LinkedList<GeoElement>();
private LinkedList<GeoNumericMinMax> minMaxList = new LinkedList<GeoNumericMinMax>();
/** errors encountered during load */
ArrayList<String> errors = new ArrayList<String>();
private static class GeoExpPair {
private GeoElement geoElement;
String exp;
GeoExpPair(GeoElement g, String exp) {
setGeo(g);
this.exp = exp;
}
GeoElement getGeo() {
return geoElement;
}
void setGeo(GeoElement geo) {
this.geoElement = geo;
}
}
private static class GeoNumericMinMax {
private GeoElement geoElement;
String min;
String max;
GeoNumericMinMax(GeoElement g, String min, String max) {
setGeo(g);
this.min = min;
this.max = max;
}
GeoElement getGeo() {
return geoElement;
}
void setGeo(GeoElement geo) {
this.geoElement = geo;
}
}
private static class LocateableExpPair {
Locateable locateable;
String exp; // String with expression to create point
GeoPointND point; // free point
int number; // number of startPoint
LocateableExpPair(Locateable g, String s, int n) {
locateable = g;
exp = s;
number = n;
}
LocateableExpPair(Locateable g, GeoPointND p, int n) {
locateable = g;
point = p;
number = n;
}
}
// construction step stored in <consProtNavigation> : handled after parsing
private int consStep;
private double ggbFileFormat;
private boolean hasGuiElement = false;
/**
* The storage container for all GUI related information of the current
* document.
*/
private Perspective tmp_perspective;
/**
* A vector with all perspectives we have read in this document.
*/
private ArrayList<Perspective> tmp_perspectives = new ArrayList<Perspective>();
/**
* Array lists to store temporary panes and views of a perspective.
*/
private ArrayList<DockSplitPaneData> tmp_panes;
private ArrayList<DockPanelData> tmp_views;
/**
* Backward compatibility for version < 3.03 where no layout component was
* used. Temporary storage for the split divider location of the split panes
* #1/#2.
*/
private int tmp_sp1, tmp_sp2;
/**
* If the split divider is horizontal. (version < 3.03)
*/
private boolean tmp_spHorizontal = true;
/**
* If the algebra or spreadsheet view is visible. (version < 3.03)
*/
private boolean tmp_showAlgebra, tmp_showSpreadsheet;
/**
* flag so that we can reset EVSettings the first time we get them (for EV1
* and EV2)
*/
protected boolean resetEVsettingsNeeded = false;
/**
* Creates a new instance of MyXMLHandler
*
* @param kernel
* kernel
* @param cons
* construction
*/
public MyXMLHandler(Kernel kernel, Construction cons) {
origKernel = kernel;
origParser = new GParser(origKernel, cons);
app = origKernel.getApplication();
loc = app.getLocalization();
initKernelVars();
mode = MODE_INVALID;
constMode = MODE_CONSTRUCTION;
}
private void reset(boolean start) {
startPointList.clear();
showObjectConditionList.clear();
dynamicColorList.clear();
linkedGeoList.clear();
animatingList.clear();
minMaxList.clear();
animationStepList.clear();
animationSpeedList.clear();
errors.clear();
if (start) {
consStep = -2;
}
mode = MODE_INVALID;
constMode = MODE_CONSTRUCTION;
hasGuiElement = false;
sliderTagProcessed = false;
fontTagProcessed = false;
lineStyleTagProcessed = false;
symbolicTagProcessed = false;
tmp_spHorizontal = true;
initKernelVars();
xmin.clear();
xmax.clear();
ymin.clear();
ymax.clear();
xtick.clear();
ytick.clear();
ztick.clear();
}
private void initKernelVars() {
this.kernel = origKernel;
this.parser = origParser;
this.cons = origKernel.getConstruction();
}
@Override
public int getConsStep() {
return consStep;
}
// ===============================================
// SAX ContentHandler methods
// ===============================================
@Override
final public void text(String str) throws SAXException {
// do nothing
}
@Override
final public void startDocument() throws SAXException {
reset(true);
}
@Override
final public void endDocument() throws SAXException {
if (errors.size() > 0) {
String[] a = new String[errors.size()];
errors.toArray(a);
app.showError(new MyError(loc, a));
}
if (mode == MODE_INVALID) {
throw new SAXException(
loc.getPlain("XMLTagANotFound", "<geogebra>"));
}
}
@Override
final public void startElement(String eName,
LinkedHashMap<String, String> attrs) throws SAXException {
// final public void startElement(
// String namespaceURI,
// String sName,
// String qName,
// LinkedHashMap<String, String> attrs)
// throws SAXException {
// String eName = qName;
if (kernel.userStopsLoading()) {
kernel.setUserStopsLoading(false);
throw new SAXException("User has cancelled loading");
}
switch (mode) {
case MODE_GEOGEBRA: // top level mode
startGeoGebraElement(eName, attrs);
break;
case MODE_EUCLIDIAN_VIEW:
startEuclidianViewElement(eName, attrs);
break;
case MODE_EUCLIDIAN_VIEW3D:
startEuclidianView3DElement(eName, attrs);
break;
case MODE_SPREADSHEET_VIEW:
startSpreadsheetViewElement(eName, attrs);
break;
case MODE_DATA_COLLECTION_VIEW:
startDataCollectionViewElement(eName, attrs);
break;
case MODE_ALGEBRA_VIEW:
startAlgebraViewElement(eName, attrs);
break;
// case MODE_CAS_VIEW:
// startCASViewElement(eName, attrs);
// break;
case MODE_PROBABILITY_CALCULATOR:
startProbabilityCalculatorElement(eName, attrs);
break;
case MODE_KERNEL:
startKernelElement(eName, attrs);
break;
case MODE_MACRO:
startMacroElement(eName, attrs);
break;
case MODE_ASSIGNMENT:
startResultElement(eName, attrs);
break;
case MODE_DEFAULTS:
startDefault(eName, attrs);
break;
case MODE_CONSTRUCTION:
startConstructionElement(eName, attrs);
break;
case MODE_GUI:
startGuiElement(eName, attrs);
break;
case MODE_GUI_PERSPECTIVES:
startGuiPerspectivesElement(eName, attrs);
break;
case MODE_GUI_PERSPECTIVE:
startGuiPerspectiveElement(eName, attrs);
break;
case MODE_GUI_PERSPECTIVE_PANES:
startGuiPanesElement(eName, attrs);
break;
case MODE_GUI_PERSPECTIVE_VIEWS:
startGuiViewsElement(eName, attrs);
break;
case MODE_DATA_ANALYSIS:
startDataAnalysisElement(eName, attrs);
break;
case MODE_INVALID:
startTopLevel(eName, attrs);
break;
default:
Log.error("unknown mode: " + mode);
}
}
private void startTopLevel(String eName, LinkedHashMap<String, String> attrs) {
// is this a geogebra file?
if ("geogebra".equals(eName)) {
mode = MODE_GEOGEBRA;
// check file format version
try {
ggbFileFormat = StringUtil.parseDouble(attrs.get("format"));
ggbFileFormat = Kernel.checkDecimalFraction(ggbFileFormat);
// Allow unbounded angles when loading new files,
// not saved automatically eg. for slider min #4108
if (ggbFileFormat > FORMAT) {
Log.debug(loc.getError("FileFormatNewer") + ": "
+ ggbFileFormat); // Michael
// Borcherds
}
// removed - doesn't work over an undo
// fileFormat dependent settings for downward compatibility
// if (ggbFileFormat < 2.6) {
// kernel.arcusFunctionCreatesAngle = true;
// }
if (ggbFileFormat < 3.0) {
// before V3.0 the kernel had continuity always on
if (!(kernel instanceof MacroKernel)) {
kernel.setContinuous(true);
}
}
} catch (RuntimeException e) {
errors.add(loc.getError("FileFormatUnknown"));
}
String ggbVersion = attrs.get("version");
app.setFileVersion(ggbVersion);
String uniqueId = attrs.get("id");
if (uniqueId != null) {
app.setUniqueId(uniqueId);
}
}
}
private void startDataAnalysisElement(String eName,
LinkedHashMap<String, String> attrs) {
DataAnalysisSettings das = app.getSettings().getDataAnalysis();
if ("item".equals(eName)) {
das.addItem(attrs.get("ranges"));
}
}
private void startScriptingElement(LinkedHashMap<String, String> attrs) {
try {
String scriptingLanguage = attrs.get("language");
app.setScriptingLanguage(scriptingLanguage);
boolean blockScripting = "true".equals(attrs.get("blocked"));
app.setBlockUpdateScripts(blockScripting);
boolean scriptingDisabled = "true".equals(attrs.get("disabled"));
app.setScriptingDisabled(scriptingDisabled);
} catch (RuntimeException e) {
Log.error("error in element <scripting>");
}
}
// set mode back to geogebra mode
@Override
final public void endElement(String eName)
// public void endElement(String namespaceURI, String sName, String
// qName)
throws SAXException {
// String eName = qName;
switch (mode) {
default:
Log.debug("missing case " + mode);
break;
case MODE_EUCLIDIAN_VIEW:
// we should set the EV sizes if they were not yet set
app.ensureEvSizeSet(evSet);
if ("euclidianView".equals(eName)) {
evSet = null;
mode = MODE_GEOGEBRA;
}
break;
case MODE_EUCLIDIAN_VIEW3D:
if ("euclidianView3D".equals(eName)) {
evSet = null;
mode = MODE_GEOGEBRA;
}
break;
case MODE_ALGEBRA_VIEW:
if ("algebraView".equals(eName)) {
mode = MODE_GEOGEBRA;
}
break;
case MODE_SPREADSHEET_VIEW:
if ("spreadsheetView".equals(eName)) {
mode = MODE_GEOGEBRA;
}
break;
case MODE_DATA_COLLECTION_VIEW:
if ("dataCollectionView".equals(eName)) {
mode = MODE_GEOGEBRA;
}
break;
case MODE_PROBABILITY_CALCULATOR:
if ("probabilityCalculator".equals(eName)) {
mode = MODE_GEOGEBRA;
}
break;
// case MODE_CAS_VIEW:
// if ("casView".equals(eName))
// mode = MODE_GEOGEBRA;
// break;
case MODE_KERNEL:
if ("kernel".equals(eName)) {
mode = MODE_GEOGEBRA;
}
break;
case MODE_GUI:
if ("gui".equals(eName)) {
mode = MODE_GEOGEBRA;
}
break;
case MODE_DATA_ANALYSIS:
if ("dataAnalysis".equals(eName)) {
mode = MODE_GUI;
}
break;
case MODE_GUI_PERSPECTIVES:
if ("perspectives".equals(eName)) {
mode = MODE_GUI;
}
endGuiPerspectivesElement(); // save all perspectives
break;
case MODE_GUI_PERSPECTIVE:
if ("perspective".equals(eName)) {
mode = MODE_GUI_PERSPECTIVES;
}
endGuiPerspectiveElement(); // save views & panes of the perspective
break;
case MODE_GUI_PERSPECTIVE_PANES:
if ("panes".equals(eName)) {
mode = MODE_GUI_PERSPECTIVE;
}
break;
case MODE_GUI_PERSPECTIVE_VIEWS:
if ("views".equals(eName)) {
mode = MODE_GUI_PERSPECTIVE;
}
break;
case MODE_CONSTRUCTION:
endConstructionElement(eName);
break;
case MODE_DEFAULTS:
endDefaultElement(eName);
break;
case MODE_MACRO:
if ("macro".equals(eName)) {
endMacro();
mode = MODE_GEOGEBRA;
}
break;
case MODE_ASSIGNMENT:
endExerciseElement(eName);
break;
case MODE_GEOGEBRA:
if ("geogebra".equals(eName)) {
// start animation if necessary
if (startAnimation) {
if (app.isDesktop()) {
// start later, in initInBackground()
kernel.setWantAnimationStarted(true);
} else {
kernel.getAnimatonManager().startAnimation();
}
}
// perform tasks to maintain backward compability
if (hasGuiElement) {
if (ggbFileFormat < 3.3) {
createCompabilityLayout();
} else if (!isPreferencesXML
&& tmp_perspectives.isEmpty()) {
// a specific 4.2 ggb file needed this
createCompabilityLayout();
}
}
}
break;
}
}
// ====================================
// <geogebra>
// ====================================
private void startGeoGebraElement(String eName,
LinkedHashMap<String, String> attrs) {
if ("euclidianView".equals(eName)) {
mode = MODE_EUCLIDIAN_VIEW;
resetEVsettingsNeeded = true;
} else if ("euclidianView3D".equals(eName)) {
mode = MODE_EUCLIDIAN_VIEW3D;
resetEVsettingsNeeded = true;
} else if ("algebraView".equals(eName)) {
mode = MODE_ALGEBRA_VIEW;
} else if ("kernel".equals(eName)) {
// default value
// (make sure old files work)
kernel.setUsePathAndRegionParameters(PathRegionHandling.ON);
mode = MODE_KERNEL;
} else if ("spreadsheetView".equals(eName)) {
mode = MODE_SPREADSHEET_VIEW;
} else if ("dataCollectionView".equals(eName)) {
mode = MODE_DATA_COLLECTION_VIEW;
} else if ("scripting".equals(eName)) {
startScriptingElement(attrs);
} else if ("probabilityCalculator".equals(eName)) {
mode = MODE_PROBABILITY_CALCULATOR;
} else if ("gui".equals(eName)) {
mode = MODE_GUI;
hasGuiElement = true;
isPreferencesXML = false;
// if (ggbFileFormat < 3.3) // safe to reset every time
tmp_perspective = new Perspective("tmp");
tmp_perspectives.clear();
} else if ("macro".equals(eName)) {
mode = MODE_MACRO;
initMacro(attrs);
} else if ("assignment".equals(eName)) {
mode = MODE_ASSIGNMENT;
initExercise(attrs);
} else if ("construction".equals(eName)) {
mode = MODE_CONSTRUCTION;
handleConstruction(attrs);
} else if ("casSession".equals(eName)) {
// old <casSession> is now <cascell> in <construction>
// not used anymore after 2011-08-16
mode = MODE_CONSTRUCTION;
constMode = MODE_CONST_CAS_CELL;
} else if ("keyboard".equals(eName)) {
handleKeyboard(attrs);
} else if ("defaults".equals(eName)) {
mode = MODE_DEFAULTS;
constMode = MODE_DEFAULTS;
} else {
Log.error("unknown tag in <geogebra>: " + eName);
}
}
private void handleKeyboard(LinkedHashMap<String, String> attrs) {
// TODO what if GuiManager is null?
try {
int width = Integer.parseInt(attrs.get("width"));
KeyboardSettings kbs = app.getSettings().getKeyboard();
kbs.setKeyboardWidth(width);
int height = Integer.parseInt(attrs.get("height"));
kbs.setKeyboardHeight(height);
double opacity = Double.parseDouble(attrs.get("opacity"));
kbs.setKeyboardOpacity(opacity);
boolean showOnStart = Boolean.parseBoolean(attrs.get("show"));
kbs.setShowKeyboardOnStart(showOnStart);
kbs.setKeyboardLocale(attrs.get("language"));
} catch (RuntimeException e) {
e.printStackTrace();
Log.error("error in element <keyboard>");
}
}
private void startMacroElement(String eName,
LinkedHashMap<String, String> attrs) {
if ("macroInput".equals(eName)) {
macroInputLabels = getAttributeStrings(attrs);
} else if ("macroOutput".equals(eName)) {
macroOutputLabels = getAttributeStrings(attrs);
} else if ("construction".equals(eName)) {
mode = MODE_CONSTRUCTION;
handleConstruction(attrs);
} else {
Log.error("unknown tag in <macro>: " + eName);
}
}
private void startResultElement(String eName,
LinkedHashMap<String, String> attrs) {
if ("result".equals(eName)) {
String name = attrs.get("name");
String hint = attrs.get("hint");
String fractionS = attrs.get("fraction");
if (hint != null && !hint.isEmpty()) {
assignment.setHintForResult(Result.valueOf(name), hint);
}
if (fractionS != null && !fractionS.isEmpty()) {
assignment.setFractionForResult(Result.valueOf(name),
Float.parseFloat(fractionS));
}
} else {
Log.error("unknown tag in <assignment>: " + eName);
}
}
// ====================================
// <euclidianView3D> only used in 3D
// ====================================
/**
* only used in MyXMLHandler3D
*
* @param eName
* element name
* @param attrs
* attributes
*/
protected void startEuclidianView3DElement(String eName,
LinkedHashMap<String, String> attrs) {
Log.debug("TODO : warn that it's a 3D file");
}
// ====================================
// <euclidianView>
// ====================================
/** Euclidian settings */
protected EuclidianSettings evSet = null;
/**
* check if eName equals "viewId" and set evSet to the correct settings
* (only used for 3D)
*
* @param eName
* element name
* @param attrs
* attributes
*/
protected void startEuclidianViewElementCheckViewId(String eName,
LinkedHashMap<String, String> attrs) {
// only used in 3D
}
/**
* switch name for euclidian view element
*
* @param eName
* element name
* @param attrs
* attributes
* @param firstChar
* first character of element name
* @return true if ok
*/
protected boolean startEuclidianViewElementSwitch(String eName,
LinkedHashMap<String, String> attrs, char firstChar) {
boolean ok = true;
switch (firstChar) {
case 'a':
if ("axesColor".equals(eName)) {
ok = handleAxesColor(evSet, attrs);
break;
} else if ("axis".equals(eName)) {
ok = handleAxis(evSet, attrs);
break;
}
case 'b':
if ("bgColor".equals(eName)) {
ok = handleBgColor(evSet, attrs);
break;
}
case 'c':
if ("coordSystem".equals(eName)) {
ok = handleCoordSystem(evSet, attrs);
break;
}
case 'e':
if ("evSettings".equals(eName)) {
ok = handleEvSettings(evSet, attrs);
break;
}
case 'g':
if ("grid".equals(eName)) {
ok = handleGrid(evSet, attrs);
break;
} else if ("gridColor".equals(eName)) {
ok = handleGridColor(evSet, attrs);
break;
}
case 'l':
if ("lineStyle".equals(eName)) {
ok = handleLineStyle(evSet, attrs);
break;
} else if ("labelStyle".equals(eName)) {
ok = handleLabelStyle(evSet, attrs);
break;
}
case 's':
if ("size".equals(eName)) {
ok = handleEvSize(evSet, attrs);
break;
}
break;
case 'v':
if ("viewNumber".equals(eName)) {
/*
* moved earlier, must check first int number =
* Integer.parseInt((String) attrs.get("viewNo"));
* if(number==2){ viewNo=number; }
*/
ok = true;
break;
} else if ("viewId".equals(eName)) {
/*
* moved earlier, must check first if for EuclidianViewForPlane
*/
ok = true;
break;
}
default:
Log.error("unknown tag in <euclidianView>: " + eName);
}
return ok;
}
private boolean handleExtraTag(LinkedHashMap<String, String> attrs) {
AlgoBarChart algo = (AlgoBarChart) geo.getParentAlgorithm();
if (!"".equals(attrs.get("key")) && !"".equals(attrs.get("value"))
&& !"".equals(attrs.get("barNumber"))) {
if (attrs.get("key").equals("barAlpha")) {
algo.setBarAlpha(Float.parseFloat(attrs.get("value")),
Integer.parseInt(attrs.get("barNumber")));
return true;
} else if (attrs.get("key").equals("barHatchDistance")) {
algo.setBarHatchDistance(Integer.parseInt(attrs.get("value")),
Integer.parseInt(attrs.get("barNumber")));
return true;
} else if (attrs.get("key").equals("barFillType")) {
algo.setBarFillType(
FillType.values()[Integer.parseInt(attrs.get("value"))],
Integer.parseInt(attrs.get("barNumber")));
return true;
} else if (attrs.get("key").equals("barHatchAngle")) {
algo.setBarHatchAngle(Integer.parseInt(attrs.get("value")),
Integer.parseInt(attrs.get("barNumber")));
return true;
} else if (attrs.get("key").equals("barImage")) {
algo.setBarImage(attrs.get("value"),
Integer.parseInt(attrs.get("barNumber")));
return true;
} else if (attrs.get("key").equals("barSymbol")) {
algo.setBarSymbol(attrs.get("value"),
Integer.parseInt(attrs.get("barNumber")));
return true;
} else if (attrs.get("key").equals("barColor")) {
String[] c = attrs.get("value").split(",");
algo.setBarColor(
GColor.newColor(Integer.parseInt(c[0].substring(5)),
Integer.parseInt(c[1]), Integer.parseInt(c[2])),
Integer.parseInt(attrs.get("barNumber")));
return true;
}
}
return false;
}
private void startEuclidianViewElement(String eName,
LinkedHashMap<String, String> attrs) {
// must do this first
if ("viewNumber".equals(eName)) {
int number = Integer.parseInt(attrs.get("viewNo"));
if (number == 2) {
evSet = app.getSettings().getEuclidian(2);
} else {
evSet = app.getSettings().getEuclidian(1);
}
} else {
startEuclidianViewElementCheckViewId(eName, attrs);
}
if (evSet == null) {
evSet = app.getSettings().getEuclidian(1);
}
// make sure eg is reset the first time (for each EV) we get the
// settings
// "viewNumber" not stored for EV1 so we need to do this here
if (resetEVsettingsNeeded) {
resetEVsettingsNeeded = false;
evSet.reset();
}
if (!startEuclidianViewElementSwitch(eName, attrs, firstChar(eName))) {
Log.error("error in <euclidianView>: " + eName);
}
}
// ====================================
// <SpreadsheetView>
// ====================================
private void startSpreadsheetViewElement(String eName,
LinkedHashMap<String, String> attrs) {
boolean ok = true;
switch (firstChar(eName)) {
case 'l':
if ("layout".equals(eName)) {
ok = handleSpreadsheetLayout(attrs);
break;
}
case 'p':
if ("prefCellSize".equals(eName)) {
ok = handleSpreadsheetCellSize(attrs);
break;
}
case 's':
if ("size".equals(eName)) {
ok = handleSpreadsheetSize(attrs);
break;
}
if ("spreadsheetColumn".equals(eName)) {
ok = handleSpreadsheetColumn(attrs);
break;
}
if ("spreadsheetRow".equals(eName)) {
ok = handleSpreadsheetRow(attrs);
break;
}
if ("selection".equals(eName)) {
ok = handleSpreadsheetInitalSelection(attrs);
break;
}
if ("spreadsheetCellFormat".equals(eName)) {
ok = handleSpreadsheetFormat(attrs);
break;
}
default:
Log.error("unknown tag in <spreadsheetView>: " + eName);
}
if (!ok) {
Log.error("error in <spreadsheetView>: " + eName);
}
}
// ====================================
// <DataCollectionView>
// ====================================
private void startDataCollectionViewElement(String eName,
LinkedHashMap<String, String> attrs) {
Types type = Types.lookup(eName);
String mappedGeoLabel = attrs.get("geo");
if (type != null) {
Log.debug("found sensor mapping " + type + " = " + mappedGeoLabel);
DataCollectionSettings settings = app.getSettings()
.getDataCollection();
settings.mapSensorToGeo(type, mappedGeoLabel);
} else {
Log.error("unknown tag in <dataCollectionView>: " + eName + " = "
+ geo);
}
}
// ====================================
// <ProbabilityCalculator>
// ====================================
private void startProbabilityCalculatorElement(String eName,
LinkedHashMap<String, String> attrs) {
boolean ok = true;
switch (firstChar(eName)) {
case 'd':
if ("distribution".equals(eName)) {
if (app.isUsingFullGui()) {
ok = handleProbabilityDistribution(attrs);
}
break;
}
case 'i':
if ("interval".equals(eName)) {
if (app.isUsingFullGui()) {
ok = handleProbabilityInterval(attrs);
}
break;
}
default:
Log.error("unknown tag in <probabilityCalculator>: " + eName);
}
if (!ok) {
Log.error("error in <probabilityCalculator>: " + eName);
}
}
private boolean handleProbabilityDistribution(
LinkedHashMap<String, String> attrs) {
try {
int distributionType = Integer.parseInt(attrs.get("type"));
app.getSettings().getProbCalcSettings()
.setDistributionType(DIST.values()[distributionType]);
boolean isCumulative = parseBoolean(attrs.get("isCumulative"));
app.getSettings().getProbCalcSettings().setCumulative(isCumulative);
// get parameters from comma delimited string
String parmString = attrs.get("parameters");
String[] parmStringArray = parmString.split(",");
double[] parameters = new double[parmStringArray.length];
for (int i = 0; i < parmStringArray.length; i++) {
parameters[i] = StringUtil.parseDouble(parmStringArray[i]);
}
app.getSettings().getProbCalcSettings().setParameters(parameters);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleProbabilityInterval(
LinkedHashMap<String, String> attrs) {
try {
int probMode = Integer.parseInt(attrs.get("mode"));
app.getSettings().getProbCalcSettings().setProbMode(probMode);
app.getSettings().getProbCalcSettings()
.setLow(StringUtil.parseDouble(attrs.get("low")));
app.getSettings().getProbCalcSettings()
.setHigh(StringUtil.parseDouble(attrs.get("high")));
return true;
} catch (RuntimeException e) {
return false;
}
}
// ====================================
// <AlgebraView>
// ====================================
/**
* @param attrs
* attributes TODO create some actual attributes
*/
private void startAlgebraViewElement(String eName,
LinkedHashMap<String, String> attrs) {
boolean ok = true;
switch (firstChar(eName)) {
case 'a':
if ("auxiliary".equals(eName)) {
ok = handleAlgebraViewShowAuxiliaryObjects(attrs);
break;
}
case 'c':
if ("collapsed".equals(eName)) {
ok = handleAlgebraViewCollapsedNodes(attrs);
break;
}
case 'm':
if ("mode".equals(eName)) {
ok = handleAlgebraViewMode(attrs);
break;
}
default:
Log.error("unknown tag in <algebraView>: " + eName);
}
if (!ok) {
Log.error("error in <algebraView>: " + eName);
}
}
// ====================================
// <CASView>
// ====================================
// private void startCASViewElement(String eName, LinkedHashMap<String,
// String> attrs) {
// boolean ok = true;
//
// switch (firstChar(eName)) {
// case 's':
// if ("size".equals(eName)) {
// ok = handleCASSize(app.getGuiManager().getCasView(), attrs);
// break;
// }
//
// default:
// Log.error("unknown tag in <casView>: " + eName);
// }
//
// if (!ok)
// Log.error("error in <casView>: " + eName);
//
// }
private HashMap<EuclidianSettings, String> xmin = new HashMap<EuclidianSettings, String>(),
xmax = new HashMap<EuclidianSettings, String>(),
ymin = new HashMap<EuclidianSettings, String>(),
xtick = new HashMap<EuclidianSettings, String>(),
ytick = new HashMap<EuclidianSettings, String>(),
ztick = new HashMap<EuclidianSettings, String>(),
ymax = new HashMap<EuclidianSettings, String>();
private boolean sliderTagProcessed, fontTagProcessed;
private boolean handleCoordSystem(EuclidianSettings ev,
LinkedHashMap<String, String> attrs) {
if (xmin.keySet().size() > 1) {
xmin.clear();
xmax.clear();
ymin.clear();
ymax.clear();
}
if (attrs.get("xZero") != null) {
try {
double xZero = StringUtil.parseDouble(attrs.get("xZero"));
double yZero = StringUtil.parseDouble(attrs.get("yZero"));
double scale = StringUtil.parseDouble(attrs.get("scale"));
// new since version 2.5
double yscale = scale;
String strYscale = attrs.get("yscale");
if (strYscale != null) {
yscale = StringUtil.parseDouble(strYscale);
}
ev.setCoordSystem(xZero, yZero, scale, yscale, true);
xmin.put(ev, null);
xmax.put(ev, null);
ymin.put(ev, null);
ymax.put(ev, null);
return true;
} catch (RuntimeException e) {
return false;
}
}
try {
xmin.put(ev, attrs.get("xMin"));
xmax.put(ev, attrs.get("xMax"));
ymin.put(ev, attrs.get("yMin"));
ymax.put(ev, attrs.get("yMax"));
return true;
} catch (RuntimeException e) {
return false;
}
}
/**
* Basic ev settings like grid / axes visible
*
* @param ev
* settings
* @param attrs
* tag attributes
* @return success
*/
protected boolean handleEvSettings(EuclidianSettings ev,
LinkedHashMap<String, String> attrs) {
try {
// axes attribute was removed with V3.0, see handleAxis()
// this code is for downward compatibility
String strAxes = attrs.get("axes");
if (strAxes != null) {
boolean showAxes = parseBoolean(strAxes);
// #2534
ev.setShowAxes(showAxes, showAxes);
}
ev.showGrid(parseBoolean(attrs.get("grid")));
try {
ev.setGridIsBold(parseBoolean(attrs.get("gridIsBold"))); // Michael
// Borcherds
// 2008-04-11
} catch (RuntimeException e) {
// not a number: ignore
}
try {
if (attrs.get("lockedAxesRatio") != null) {
ev.setLockedAxesRatio(StringUtil
.parseDouble(attrs.get("lockedAxesRatio")));
}
} catch (RuntimeException e) {
// not a number: ignore
}
try {
ev.setGridType(Integer.parseInt(attrs.get("gridType"))); // Michael
// Borcherds
// 2008-04-30
} catch (RuntimeException e) {
// not a number: ignore
}
String str = attrs.get("pointCapturing");
if (str != null) {
// before GeoGebra 2.7 pointCapturing was either "true" or
// "false"
// now pointCapturing holds an int value
int pointCapturingMode;
if ("false".equals(str)) {
pointCapturingMode = 0;
} else if ("true".equals(str)) {
pointCapturingMode = 1;
} else {
// int value
pointCapturingMode = Integer.parseInt(str);
// bug: POINT_CAPTURING_STICKY_POINTS written to XML
// sometimes
if (pointCapturingMode > EuclidianStyleConstants.POINT_CAPTURING_XML_MAX) {
pointCapturingMode = EuclidianStyleConstants.POINT_CAPTURING_DEFAULT;
}
}
ev.setPointCapturing(pointCapturingMode);
} else {
ev.setPointCapturing(
EuclidianStyleConstants.POINT_CAPTURING_AUTOMATIC);
}
// if there is a point style given save it
if (ggbFileFormat < 3.3) {
String strPointStyle = attrs.get("pointStyle");
if (strPointStyle != null) {
docPointStyle = Integer.parseInt(strPointStyle);
} else {
docPointStyle = EuclidianStyleConstants.POINT_STYLE_DOT;
}
// TODO save as default construction (F.S.)
} else {
docPointStyle = -1;
}
String strBooleanSize = attrs.get("checkboxSize");
if (strBooleanSize != null) {
app.setCheckboxSize(Integer.parseInt(strBooleanSize));
}
// ev.setBooleanSize(Integer.parseInt(strBooleanSize));
boolean asm = parseBoolean(attrs.get("allowShowMouseCoords"));
ev.setAllowShowMouseCoords(asm);
String att = attrs.get("allowToolTips");
if (att != null) {
ev.setAllowToolTips(Integer.parseInt(att));
} else {
ev.setAllowToolTips(EuclidianStyleConstants.TOOLTIPS_AUTOMATIC);
}
String del = attrs.get("deleteToolSize");
if (del != null) {
ev.setDeleteToolSize(Integer.parseInt(del));
}
// v3.0: appearance of right angle
String strRightAngleStyle = attrs.get("rightAngleStyle");
if (strRightAngleStyle == null) {
// before v3.0 the default was a dot to show a right angle
// ev.setRightAngleStyle(EuclidianView.RIGHT_ANGLE_STYLE_DOT);
if (!ev.is3D()) {
app.setRightAngleStyle(
EuclidianStyleConstants.RIGHT_ANGLE_STYLE_DOT);
} else {
app.setRightAngleStyle(
app.getLocalization().getRightAngleStyle());
}
} else {
if (!ev.isViewForPlane()) {
// ev.setRightAngleStyle(Integer.parseInt(strRightAngleStyle));
app.setRightAngleStyle(
Integer.parseInt(strRightAngleStyle));
}
}
return true;
} catch (RuntimeException e) {
return false;
}
}
// is there a reason why it was static?
private boolean handleEvSize(EuclidianSettings ev,
LinkedHashMap<String, String> attrs) {
// removed, needed to resize applet correctly
// if (app.isApplet())
// return true;
try {
int width;
int height;
if (!isPreferencesXML) {
int border = 2; // TODO needs to be 0 when fullscreen, also what
// about other views?
// 2: border
width = (app.getAppletWidth() > border && !app.getUseFullGui())
? app.getAppletWidth() - border
: Integer.parseInt(attrs.get("width"));
height = (app.getAppletHeight() > border
&& !app.getUseFullGui())
? app.getAppletHeight() - border
: Integer.parseInt(attrs.get("height"));
ev.setPreferredSize(
AwtFactory.getPrototype().newDimension(width, height));
ev.setSizeFromFile(AwtFactory.getPrototype().newDimension(
Integer.parseInt(attrs.get("width")),
Integer.parseInt(attrs.get("height"))));
}
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSpreadsheetSize(LinkedHashMap<String, String> attrs) {
if (app.isApplet() && !app.isHTML5Applet()) {
return true;
}
try {
int width = Integer.parseInt(attrs.get("width"));
int height = Integer.parseInt(attrs.get("height"));
app.getSettings().getSpreadsheet().setPreferredSize(
AwtFactory.getPrototype().newDimension(width, height));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSpreadsheetColumn(
LinkedHashMap<String, String> attrs) {
try {
int col = Integer.parseInt(attrs.get("id"));
int width = Integer.parseInt(attrs.get("width"));
app.getSettings().getSpreadsheet().addWidth(col, width);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSpreadsheetCellSize(
LinkedHashMap<String, String> attrs) {
try {
int width = Integer.parseInt(attrs.get("width"));
int height = Integer.parseInt(attrs.get("height"));
app.getSettings().getSpreadsheet().setPreferredColumnWidth(width);
app.getSettings().getSpreadsheet().setPreferredRowHeight(height);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSpreadsheetFormat(
LinkedHashMap<String, String> attrs) {
try {
String cellFormat = attrs.get("formatMap");
app.getSettings().getSpreadsheet().setCellFormat(cellFormat);
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
private boolean handleSpreadsheetRow(LinkedHashMap<String, String> attrs) {
try {
int row = Integer.parseInt(attrs.get("id"));
int height = Integer.parseInt(attrs.get("height"));
app.getSettings().getSpreadsheet().addHeight(row, height);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSpreadsheetLayout(
LinkedHashMap<String, String> attrs) {
SpreadsheetSettings settings = app.getSettings().getSpreadsheet();
try {
settings.setShowFormulaBar(
parseBoolean(attrs.get("showFormulaBar")));
settings.setShowGrid(parseBoolean(attrs.get("showGrid")));
settings.setShowColumnHeader(
parseBoolean(attrs.get("showColumnHeader")));
settings.setShowRowHeader(parseBoolean(attrs.get("showRowHeader")));
settings.setShowHScrollBar(
parseBoolean(attrs.get("showHScrollBar")));
settings.setShowVScrollBar(
parseBoolean(attrs.get("showVScrollBar")));
settings.setAllowSpecialEditor(
parseBoolean(attrs.get("allowSpecialEditor")));
settings.setAllowToolTips(parseBoolean(attrs.get("allowToolTips")));
settings.setEqualsRequired(
parseBoolean(attrs.get("equalsRequired")));
settings.setEnableAutoComplete(
parseBoolean(attrs.get("autoComplete")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSpreadsheetInitalSelection(
LinkedHashMap<String, String> attrs) {
SpreadsheetSettings settings = app.getSettings().getSpreadsheet();
try {
int hScroll = Integer.parseInt(attrs.get("hScroll"));
int vScroll = Integer.parseInt(attrs.get("vScroll"));
settings.setScrollPosition(new GPoint(hScroll, vScroll));
int row = Integer.parseInt(attrs.get("row"));
int column = Integer.parseInt(attrs.get("column"));
settings.setScrollPosition(new GPoint(row, column));
return true;
} catch (RuntimeException e) {
return false;
}
}
// private boolean handleCASSize(CasManager casView, LinkedHashMap<String,
// String> attrs) {
// if (app.isApplet())
// return true;
//
// try {
// int width = Integer.parseInt((String) attrs.get("width"));
// int height = Integer.parseInt((String) attrs.get("height"));
//
// // it seems that this statement does not work, because now cas use
// // its own frame. --Quan Yuan
// ((JComponent) app.getCasView()).setPreferredSize(new Dimension(
// width, height));
// return true;
// } catch(RuntimeException e) {
// e.printStackTrace();
// return false;
// }
// }
/**
* Background color handlig for view
*
* @param evSet
* settings
* @param attrs
* tag attributes
* @return success
*/
protected static boolean handleBgColor(EuclidianSettings evSet,
LinkedHashMap<String, String> attrs) {
GColor col = handleColorAttrs(attrs);
if (col == null) {
return false;
}
evSet.setBackground(col);
return true;
}
private static boolean handleAxesColor(EuclidianSettings ev,
LinkedHashMap<String, String> attrs) {
GColor col = handleColorAttrs(attrs);
if (col == null) {
return false;
}
ev.setAxesColor(col);
return true;
}
private static boolean handleGridColor(EuclidianSettings ev,
LinkedHashMap<String, String> attrs) {
GColor col = handleColorAttrs(attrs);
if (col == null) {
return false;
}
ev.setGridColor(col);
return true;
}
private static boolean handleLineStyle(EuclidianSettings ev,
LinkedHashMap<String, String> attrs) {
try {
ev.setAxesLineStyle(Integer.parseInt(attrs.get("axes")));
ev.setGridLineStyle(Integer.parseInt(attrs.get("grid")));
return true;
} catch (RuntimeException e) {
return false;
}
}
/**
* Label style for axes
*
* @param ev
* euclidian settings
* @param attrs
* tag attributes
* @return success
*/
protected static boolean handleLabelStyle(EuclidianSettings ev,
LinkedHashMap<String, String> attrs) {
try {
ev.setAxisFontStyle(Integer.parseInt(attrs.get("axes")));
ev.setAxesLabelsSerif("true".equals(attrs.get("serif")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private static boolean handleGrid(EuclidianSettings ev,
LinkedHashMap<String, String> attrs) {
// <grid distX="2.0" distY="4.0"/>
try {
double[] dists = new double[3];
dists[0] = StringUtil.parseDouble(attrs.get("distX"));
dists[1] = StringUtil.parseDouble(attrs.get("distY"));
// in v4.0 the polar grid adds an angle step element to
// gridDistances
String theta = attrs.get("distTheta");
if (theta != null) {
dists[2] = StringUtil.parseDouble(attrs.get("distTheta"));
}
else {
dists[2] = Math.PI / 6; // default
}
ev.setGridDistances(dists);
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
/**
* <axis id="0" label="x" unitLabel="x" showNumbers="true" tickDistance=
* "2"/>
*
* @param ev
* settings
* @param attrs
* attributes of <axis> tag
* @return true iff succesful
*/
protected boolean handleAxis(EuclidianSettings ev,
LinkedHashMap<String, String> attrs) {
try {
int axis = Integer.parseInt(attrs.get("id"));
String strShowAxis = attrs.get("show");
String label = attrs.get("label");
String unitLabel = attrs.get("unitLabel");
boolean showNumbers = parseBoolean(attrs.get("showNumbers"));
// show this axis
if (strShowAxis != null) {
boolean showAxis = parseBoolean(strShowAxis);
ev.setShowAxis(axis, showAxis);
}
String selectionAllowedStr = attrs.get("selectionAllowed");
if (selectionAllowedStr != null) {
boolean selectionAllowed = parseBoolean(selectionAllowedStr);
ev.setSelectionAllowed(axis, selectionAllowed);
}
// set label
ev.setAxisLabel(axis, label);
/*
* if (label != null && label.length() > 0) { String[] labels =
* ev.getAxesLabels(); labels[axis] = label;
* ev.setAxesLabels(labels); }
*/
// set unitlabel
if (unitLabel != null && unitLabel.length() > 0) {
String[] unitLabels = ev.getAxesUnitLabels();
unitLabels[axis] = unitLabel;
ev.setAxesUnitLabels(unitLabels);
}
// set showNumbers
ev.setShowAxisNumbers(axis, showNumbers);
/*
* boolean showNums[] = ev.getShowAxesNumbers(); showNums[axis] =
* showNumbers; ev.setShowAxesNumbers(showNums);
*/
// check if tickDistance is given
String tickExpr = attrs.get("tickExpression");
if (tickExpr != null) {
if (axis == 0) {
xtick.put(evSet, tickExpr);
} else if (axis == 1) {
ytick.put(evSet, tickExpr);
} else {
ztick.put(evSet, tickExpr);
}
}
String strTickDist = attrs.get("tickDistance");
if (strTickDist != null) {
double tickDist = StringUtil.parseDouble(strTickDist);
GeoNumeric distNum = new GeoNumeric(cons, tickDist);
if (StringUtil.empty(tickExpr)
&& Kernel.isInteger(tickDist * 24 / Math.PI)) {
int num = (int) Math.round(tickDist * 24 / Math.PI);
int gcd = (int) Kernel.gcd(num, 24);
int den = 24 / gcd;
num = num / gcd;
ExpressionNode def = new ExpressionNode(kernel, Math.PI)
.multiplyR(num);
if (den != 1) {
def = def.divide(den);
}
distNum.setDefinition(def);
}
ev.setAxesNumberingDistance(distNum, axis);
}
// tick style
String strTickStyle = attrs.get("tickStyle");
if (strTickStyle != null) {
int tickStyle = Integer.parseInt(strTickStyle);
// ev.getAxesTickStyles()[axis] = tickStyle;
ev.setAxisTickStyle(axis, tickStyle);
} else {
// before v3.0 the default tickStyle was MAJOR_MINOR
// ev.getAxesTickStyles()[axis] =
// EuclidianStyleConstants.AXES_TICK_STYLE_MAJOR_MINOR;
ev.setAxisTickStyle(axis,
EuclidianStyleConstants.AXES_TICK_STYLE_MAJOR_MINOR);
}
// axis crossing
String axisCross = attrs.get("axisCross");
String axisCrossEdge = attrs.get("axisCrossEdge");
boolean acb = false;
if (axisCrossEdge != null) {
acb = parseBoolean(axisCrossEdge);
}
if (acb) {
ev.setAxisCross(axis, 0);
ev.setDrawBorderAxes(axis, true);
} else if (axisCross != null) {
double ac = StringUtil.parseDouble(axisCross);
ev.setAxisCross(axis, ac);
ev.setDrawBorderAxes(axis, false);
} else {
ev.setAxisCross(axis, 0);
ev.setDrawBorderAxes(axis, false);
}
// positive direction only
String posAxis = attrs.get("positiveAxis");
if (posAxis != null) {
boolean isPositive = Boolean.parseBoolean(posAxis);
ev.setPositiveAxis(axis, isPositive);
}
return true;
} catch (RuntimeException e) {
// e.printStackTrace();
return false;
}
}
// ====================================
// <kernel>
// ====================================
private void startKernelElement(String eName,
LinkedHashMap<String, String> attrs) {
if ("angleUnit".equals(eName)) {
handleAngleUnit(attrs);
} else if ("algebraStyle".equals(eName)) { // G.Sturr 2009-10-18
handleAlgebraStyle(attrs);
} else if ("coordStyle".equals(eName)) {
handleKernelCoordStyle(attrs);
} else if ("angleFromInvTrig".equals(eName)) {
handleKernelInvTrig(attrs);
} else if ("continuous".equals(eName)) {
handleKernelContinuous(attrs);
} else if ("usePathAndRegionParameters".equals(eName)) {
handleKernelUsePathAndRegionParameters(attrs);
} else if ("decimals".equals(eName)) {
handleKernelDecimals(attrs);
} else if ("significantfigures".equals(eName)) {
handleKernelFigures(attrs);
} else if ("startAnimation".equals(eName)) {
handleKernelStartAnimation(attrs);
} else if ("localization".equals(eName)) {
handleKernelLocalization(attrs);
} else if ("casSettings".equals(eName)) {
handleCasSettings(attrs);
} else if (!"uses3D".equals(eName)) {
Log.error("unknown tag in <kernel>: " + eName);
}
}
private boolean handleAngleUnit(LinkedHashMap<String, String> attrs) {
if (attrs == null) {
return false;
}
String angleUnit = attrs.get("val");
if (angleUnit == null) {
return false;
}
if ("degree".equals(angleUnit)) {
kernel.setAngleUnit(Kernel.ANGLE_DEGREE);
} else if ("radiant".equals(angleUnit)) {
kernel.setAngleUnit(Kernel.ANGLE_RADIANT);
} else {
return false;
}
return true;
}
private boolean handleAlgebraStyle(LinkedHashMap<String, String> attrs) {
try {
kernel.setAlgebraStyle(Integer.parseInt(attrs.get("val")));
if (attrs.containsKey("spreadsheet")) {
kernel.setAlgebraStyleSpreadsheet(
Integer.parseInt(attrs.get("spreadsheet")));
} else {
// old files only have val, use that for spreadsheet too
kernel.setAlgebraStyleSpreadsheet(
Integer.parseInt(attrs.get("val")));
}
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleKernelCoordStyle(
LinkedHashMap<String, String> attrs) {
try {
kernel.setCoordStyle(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleKernelInvTrig(LinkedHashMap<String, String> attrs) {
try {
kernel.setInverseTrigReturnsAngle(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleKernelDecimals(LinkedHashMap<String, String> attrs) {
try {
kernel.setPrintDecimals(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleKernelStartAnimation(
LinkedHashMap<String, String> attrs) {
try {
startAnimation = parseBoolean(attrs.get("val"));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleKernelLocalization(
LinkedHashMap<String, String> attrs) {
try {
boolean digits = parseBoolean(attrs.get("digits"));
loc.setUseLocalizedDigits(digits, app);
boolean labels = parseBoolean(attrs.get("labels"));
loc.setUseLocalizedLabels(labels);
return true;
} catch (RuntimeException e) {
return false;
}
}
/**
* Handle the casSettings XML element which is responsible for setting the
* Options CAS dialog
*
* @param attrs
* - mapping of attributes names and values
* @return whether the operation was successful
*/
private boolean handleCasSettings(LinkedHashMap<String, String> attrs) {
try {
boolean expRoots = parseBoolean(attrs.get("expRoots"));
app.getSettings().getCasSettings().setShowExpAsRoots(expRoots);
int timeout = Integer.parseInt(attrs.get("timeout"));
if (timeout > 0) {
app.getSettings().getCasSettings().setTimeoutMilliseconds(
OptionsCAS.getTimeoutOption(timeout) * 1000);
}
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleKernelFigures(LinkedHashMap<String, String> attrs) {
try {
kernel.setPrintFigures(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleKernelContinuous(
LinkedHashMap<String, String> attrs) {
try {
kernel.setContinuous(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleKernelUsePathAndRegionParameters(
LinkedHashMap<String, String> attrs) {
try {
kernel.setUsePathAndRegionParameters(
PathRegionHandling.parse(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
// ====================================
// <gui>
// ====================================
private void startGuiElement(String eName,
LinkedHashMap<String, String> attrs) {
boolean ok = true;
switch (firstChar(eName)) {
case 'c':
if ("consProtColumns".equals(eName)) {
ok = handleConsProtColumns(app, attrs);
} else if ("consProtocol".equals(eName)) {
ok = handleConsProtocol(attrs);
} else if ("consProtNavigationBar".equals(eName)) {
ok = handleConsProtNavigationBar(app, attrs);
}
break;
case 'd':
if ("dataAnalysis".equals(eName)) {
ok = handleDataAnalysis(attrs);
}
break;
case 'f':
if ("font".equals(eName)) {
ok = handleFont(app, attrs);
}
break;
case 'm':
if ("menuFont".equals(eName)) {
ok = handleMenuFont(app, attrs);
}
break;
case 'l':
if ("labelingStyle".equals(eName)) {
ok = handleLabelingStyle(app, attrs);
}
break;
case 'p':
if ("perspectives".equals(eName)) {
mode = MODE_GUI_PERSPECTIVES;
tmp_perspectives.clear();
}
break;
case 's':
if ("show".equals(eName)) {
ok = handleGuiShow(app, attrs);
} else if ("splitDivider".equals(eName)) {
ok = handleSplitDivider(attrs);
} else if ("settings".equals(eName)) {
ok = handleGuiSettings(app, attrs);
}
break;
case 't':
if ("toolbar".equals(eName)) {
ok = handleToolbar(attrs);
} else if ("tooltipSettings".equals(eName)) {
ok = handleTooltipSettings(app, attrs);
}
break;
case 'w':
if ("window".equals(eName)) {
ok = handleWindowSize(app, attrs);
}
break;
default:
Log.error("unknown tag in <gui>: " + eName);
}
if (!ok) {
Log.error("error in <gui>: " + eName);
}
}
private boolean handleDataAnalysis(LinkedHashMap<String, String> attrs) {
mode = MODE_DATA_ANALYSIS;
try {
app.getSettings().getDataAnalysis()
.setMode(Integer.parseInt(attrs.get("mode")));
app.getSettings().getDataAnalysis()
.setRegression(Regression.valueOf(attrs.get("regression")));
app.getSettings().getDataAnalysis().setPlotType(0,
PlotType.valueOf(attrs.get("plot1")));
app.getSettings().getDataAnalysis().setPlotType(1,
PlotType.valueOf(attrs.get("plot1")));
} catch (RuntimeException e) {
return false;
}
return true;
}
/**
* Take care of backward compatibility for the dynamic layout component
*/
private void createCompabilityLayout() {
int splitOrientation = tmp_spHorizontal
? SwingConstants.HORIZONTAL_SPLIT
: SwingConstants.VERTICAL_SPLIT;
String defEV, defSV, defAV;
// we have to create the definitions for the single views manually to
// prevent nullpointers
if (splitOrientation == SwingConstants.HORIZONTAL_SPLIT) {
if (tmp_showSpreadsheet && tmp_showAlgebra) {
defEV = "1,3";
defSV = "1,1";
defAV = "3";
} else {
if (tmp_showSpreadsheet) {
defEV = "3";
defSV = "1";
defAV = "3,3"; // not used directly
} else {
defEV = "1";
defAV = "3";
defSV = "1,1"; // not used directly
}
}
} else {
if (tmp_showSpreadsheet && tmp_showAlgebra) {
defEV = "0";
defAV = "2,0";
defSV = "2,2";
} else {
if (tmp_showSpreadsheet) {
defEV = "0";
defSV = "2";
defAV = "0,0"; // not used directly
} else {
defEV = "2";
defAV = "0";
defSV = "2,2"; // not used directly
}
}
}
GDimension evSize = app.getSettings().getEuclidian(1)
.getPreferredSize();
// calculate window dimensions
int width = evSize.getWidth();
int height = evSize.getHeight();
// minimal size for documents, necessary for GeoGebra < 3
if (width <= 100 || height <= 100) {
width = 600;
height = 440;
}
int ssize = 200;
if (tmp_showSpreadsheet) {
if (splitOrientation == SwingConstants.HORIZONTAL_SPLIT) {
ssize = app.getSettings().getSpreadsheet().preferredSize()
.getWidth();
} else {
ssize = app.getSettings().getSpreadsheet().preferredSize()
.getHeight();
}
}
// construct default xml data in case we're using an old version which
// didn't
// store the layout xml.
DockPanelData[] dpXml = new DockPanelData[] {
new DockPanelData(App.VIEW_EUCLIDIAN, null, true, false, false,
AwtFactory.getPrototype().newRectangle(400, 400), defEV,
width),
new DockPanelData(App.VIEW_ALGEBRA, null, tmp_showAlgebra,
false, false,
AwtFactory.getPrototype().newRectangle(200, 400), defAV,
(tmp_showAlgebra && tmp_sp2 > 0) ? tmp_sp2 : 200),
new DockPanelData(App.VIEW_SPREADSHEET, null,
tmp_showSpreadsheet, false, false,
AwtFactory.getPrototype().newRectangle(400, 400), defSV,
ssize) };
tmp_perspective.setDockPanelData(dpXml);
tmp_perspective.setShowToolBar(true);
if (splitOrientation == SwingConstants.HORIZONTAL_SPLIT) {
if (tmp_showSpreadsheet) {
width += 5 + ssize;
}
if (tmp_showAlgebra) {
width += 5 + tmp_sp2;
}
} else {
if (tmp_showSpreadsheet) {
height += 5 + ssize;
}
if (tmp_showAlgebra) {
height += 5 + tmp_sp2;
}
}
DockSplitPaneData[] spXml;
// use two split panes in case all three views are visible
if (tmp_showSpreadsheet && tmp_showAlgebra) {
int total = (splitOrientation == SwingConstants.HORIZONTAL_SPLIT
? width : height);
double relative1 = (double) tmp_sp2 / total;
double relative2 = (double) tmp_sp1 / (total - tmp_sp2);
spXml = new DockSplitPaneData[] {
new DockSplitPaneData("", relative1, splitOrientation),
new DockSplitPaneData(
(splitOrientation == SwingConstants.HORIZONTAL_SPLIT
? "1" : "2"),
relative2, splitOrientation) };
} else {
int total = (splitOrientation == SwingConstants.HORIZONTAL_SPLIT
? width : height);
double relative;
if (tmp_showSpreadsheet) {
relative = tmp_sp1 / (double) total;
} else {
relative = tmp_sp2 / (double) total;
}
spXml = new DockSplitPaneData[] {
new DockSplitPaneData("", relative, splitOrientation) };
}
// additional space for toolbar and others, we add this here
// as it shouldn't influence the relative positions of the
// split pane dividers above
width += 15;
height += 90;
if (tmp_perspective.getShowInputPanel()) {
height += 50;
}
tmp_perspective.setSplitPaneData(spXml);
tmp_perspectives = new ArrayList<Perspective>();
tmp_perspectives.add(tmp_perspective);
app.setPreferredSize(
AwtFactory.getPrototype().newDimension(width, height));
app.setTmpPerspectives(tmp_perspectives);
}
private static boolean handleConsProtColumns(App app,
LinkedHashMap<String, String> attrs) {
try {
/*
* TODO: iterator() function caused error in GWT. Why?
*
* //Iterator<String> it = attrs.keySet().iterator(); Set<String>
* temp = attrs.keySet(); Iterator<String> it = temp.iterator();
*
* int colCounter = 0; boolean[] colsVis = new
* boolean[attrs.keySet().size()]; while (it.hasNext()) { Object ob
* = attrs.get(it.next()); boolean isVisible = parseBoolean((String)
* ob); colsVis[colCounter++] = isVisible; }
*/
boolean[] colsVis = new boolean[attrs.keySet().size()];
ArrayList<String> keys = new ArrayList<String>(attrs.keySet());
for (String key : keys) {
int k = Integer.parseInt(key.substring(3));
colsVis[k] = Boolean.parseBoolean(attrs.get(key));
}
ConstructionProtocolSettings cpSettings = app.getSettings()
.getConstructionProtocol();
cpSettings.setColsVisibility(colsVis);
return true;
} catch (RuntimeException e) {
Log.debug(e);
return false;
}
}
private boolean handleConsProtocol(LinkedHashMap<String, String> attrs) {
try {
// boolean useColors = parseBoolean((String)
// attrs.get("useColors"));
// TODO: set useColors for consProt
boolean showOnlyBreakpoints = parseBoolean(
attrs.get("showOnlyBreakpoints"));
kernel.getConstruction()
.setShowOnlyBreakpoints(showOnlyBreakpoints);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleConsProtNavigationBar(App app1,
LinkedHashMap<String, String> attrs) {
try {
boolean playButton = parseBoolean(attrs.get("playButton"));
double playDelay = StringUtil.parseDouble(attrs.get("playDelay"));
boolean showProtButton = parseBoolean(attrs.get("protButton"));
String showStr = attrs.get("show");
if (showStr == null) { // new XML
String idStr = attrs.get("id");
for (String id : idStr.split(" ")) {
int viewId = Integer.parseInt(id);
app1.setShowConstructionProtocolNavigation(true, viewId,
playButton, playDelay, showProtButton);
}
} else { // old XML
boolean show = parseBoolean(attrs.get("show"));
// Maybe there is not guiManager yet. In this case we store the
// navigation bar's states in ConstructionProtocolSettings
app1.setShowConstructionProtocolNavigation(show,
App.VIEW_EUCLIDIAN, playButton, playDelay,
showProtButton);
}
// construction step: handled at end of parsing
String strConsStep = attrs.get("consStep");
if (strConsStep != null) {
consStep = Integer.parseInt(strConsStep);
}
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
/**
* Backward compatibility for version < 3.3
*
* @param app1
* @param attrs
* @return
*/
private boolean handleGuiShow(App app1,
LinkedHashMap<String, String> attrs) {
try {
// backward compatibility to versions without the layout component
// if (ggbFileFormat < 3.3) {// also used in some special, newer
// files
tmp_showAlgebra = parseBoolean(attrs.get("algebraView"));
// Michael Borcherds 2008-04-25
tmp_showSpreadsheet = parseBoolean(attrs.get("spreadsheetView"));
// }
String str = attrs.get("auxiliaryObjects");
boolean auxiliaryObjects = (str != null && "true".equals(str));
app1.setShowAuxiliaryObjects(auxiliaryObjects);
str = attrs.get("algebraInput");
boolean algebraInput = (str == null || "true".equals(str));
tmp_perspective.setShowInputPanel(algebraInput);
str = attrs.get("cmdList");
boolean cmdList = (str == null || "true".equals(str));
tmp_perspective.setShowInputPanelCommands(cmdList);
return true;
} catch (RuntimeException e) {
e.printStackTrace();
Log.error(e.getMessage() + ": " + e.getCause());
return false;
}
}
private static boolean isPreferencesXML = false;
/**
* Settings of the user, not saved in the file XML but for preferences XML.
*
* <settings ignoreDocument=".." showTitleBar=".." />
*
* @param app
* @param attrs
* @return
*/
private static boolean handleGuiSettings(App app,
LinkedHashMap<String, String> attrs) {
// set that XML load is a preferences settings
isPreferencesXML = true;
try {
boolean ignoreDocument = !attrs.get("ignoreDocument")
.equals("false");
app.getSettings().getLayout()
.setIgnoreDocumentLayout(ignoreDocument);
boolean showTitleBar = !attrs.get("showTitleBar").equals("false");
app.getSettings().getLayout().setShowTitleBar(showTitleBar);
if (attrs.containsKey("allowStyleBar")) {
boolean allowStyleBar = !attrs.get("allowStyleBar")
.equals("false");
app.getSettings().getLayout().setAllowStyleBar(allowStyleBar);
}
return true;
} catch (RuntimeException e) {
e.printStackTrace();
Log.warn(e.getMessage() + ": " + e.getCause());
return false;
}
}
/**
* Kept for backward compatibility with version < 3.3
*
* @param attrs
* @return
*/
private boolean handleSplitDivider(LinkedHashMap<String, String> attrs) {
try {
tmp_sp1 = 0;
tmp_sp2 = 0;
tmp_spHorizontal = !"false".equals(attrs.get("horizontal"));
// There were just two panels in GeoGebra < 3.2, therefore just one
// split divider position
// may be given. 'loc' in < 3.2 corresponds to 'loc2' in 3.2+.
if (attrs.get("loc2") == null) {
attrs.put("loc2", attrs.get("loc"));
attrs.put("loc", "0"); // prevent NP exception in
// Integer.parseInt()
}
if (tmp_spHorizontal) {
tmp_sp1 = Integer.parseInt(attrs.get("loc"));
tmp_sp2 = Integer.parseInt(attrs.get("loc2"));
} else {
String strLocVert = attrs.get("locVertical");
if (strLocVert != null) {
tmp_sp1 = Integer.parseInt(strLocVert);
} else {
tmp_sp1 = Integer.parseInt(attrs.get("loc"));
}
String strLocVert2 = attrs.get("locVertical2");
if (strLocVert2 != null) {
tmp_sp2 = Integer.parseInt(strLocVert2);
} else {
tmp_sp2 = Integer.parseInt(attrs.get("loc2"));
}
}
return true;
} catch (RuntimeException e) {
tmp_sp1 = 0;
tmp_sp2 = 0;
return false;
}
}
private boolean handleToolbar(LinkedHashMap<String, String> attrs) {
try {
String toolbarStr = attrs.get("str");
if (toolbarStr != null) {
// GeoGebra 3.2 or older
// eg 0 39 59 || 1001 5 19 | 2 15 45 18 , 7 37 | 4 3 8 9 , 13 44
// , 58 , 47 || 16 51 | 10 34 53 11 , 24 20 22 , 21 23 | 55 56
// 57 , 12 || 36 46 , 38 49 50 | 30 29 54 32 31 33 | 25 52 , 17
// 26 , 14 || 40 41 42 , 27 28 35 , 6
// substitute 1000+x to 100000+x (macro numbers)
StringBuilder converted = new StringBuilder();
for (int lv = 0; lv < toolbarStr.length(); lv++) {
char c = toolbarStr.charAt(lv);
if (Character.isDigit(c)) {
StringBuilder numStr = new StringBuilder();
char cc;
while (lv < toolbarStr.length() && Character
.isDigit(cc = toolbarStr.charAt(lv))) {
numStr.append(cc);
lv++;
}
int num = Integer.parseInt(numStr.toString());
if (num > 999) {
num = num + 100000 - 1000;
}
converted.append(num);
converted.append(" ");
} else {
// space or comma or |
converted.append(c);
}
}
toolbarStr = converted.toString();
tmp_perspective.setShowToolBar(true);
tmp_perspective.setToolbarDefinition(toolbarStr);
} else {
// GeoGebra 4.0
String showToolBar = attrs.get("show");
if (showToolBar == null) {
tmp_perspective.setShowToolBar(true);
} else {
tmp_perspective.setShowToolBar("true".equals(showToolBar));
}
String items = attrs.get("items");
tmp_perspective.setToolbarDefinition(
"null".equals(items) ? null : items);
// GeoGebra 4.2 (supports toolbar position and toggling help)
if (attrs.get("position") != null) {
Integer toolBarPosition = Integer
.parseInt(attrs.get("position"));
tmp_perspective.setToolBarPosition(toolBarPosition);
tmp_perspective.setShowToolBarHelp(
!attrs.get("help").equals("false"));
} else {
tmp_perspective.setToolBarPosition(SwingConstants.NORTH);
tmp_perspective.setShowToolBarHelp(true);
}
}
return true;
} catch (RuntimeException e) {
Log.warn(e.getMessage() + ": " + e.getCause());
return false;
}
}
/**
* Handle the window size: <window width=".." height=".." />
*
* @param app
* @param attrs
* @return
*/
private static boolean handleWindowSize(App app,
LinkedHashMap<String, String> attrs) {
try {
GDimension size = AwtFactory.getPrototype().newDimension(
Integer.parseInt(attrs.get("width")),
Integer.parseInt(attrs.get("height")));
app.setPreferredSize(size);
return true;
} catch (RuntimeException e) {
Log.warn(e.getMessage() + ": " + e.getCause());
return false;
}
}
private static boolean handleFont(App app,
LinkedHashMap<String, String> attrs) {
try {
int guiSize = Integer.parseInt(attrs.get("size"));
// old versions do just have a single font size and derive the font
// size for
// the axes / euclidian view from this single size
// if(ggbFileFormat < 3.3) {
// app.setFontSize(guiSize, false);
// app.setAxesFontSize(guiSize - 2, false); // always 2 points
// smaller than the default size
// } else {
// int axesSize = Integer.parseInt((String) attrs.get("axesSize"));
// app.setAxesFontSize(axesSize, false);
//
// int euclidianSize = Integer.parseInt((String)
// attrs.get("euclidianSize"));
// app.setEuclidianFontSize(euclidianSize, false);
// }
app.setFontSize(guiSize, true); // set gui font size and update all
// fonts
return true;
} catch (RuntimeException e) {
return false;
}
}
private static boolean handleMenuFont(App app,
LinkedHashMap<String, String> attrs) {
try {
int guiSize = Integer.parseInt(attrs.get("size"));
if (guiSize <= 0) {
app.setGUIFontSize(-1); // default
} else {
for (int i = 0; i < Util.menuFontSizesLength(); i++) {
if (Util.menuFontSizes(i) >= guiSize) {
guiSize = Util.menuFontSizes(i);
break;
}
}
if (guiSize > Util
.menuFontSizes(Util.menuFontSizesLength() - 1)) {
guiSize = Util
.menuFontSizes(Util.menuFontSizesLength() - 1);
}
app.setGUIFontSize(guiSize);
}
return true;
} catch (RuntimeException e) {
return false;
}
}
private static boolean handleTooltipSettings(App app,
LinkedHashMap<String, String> attrs) {
try {
String ttl = attrs.get("language");
if ("".equals(ttl)) {
app.setTooltipLanguage(null);
} else if (ttl != null) {
app.setTooltipLanguage(ttl);
}
int ttt = -1;
try { // "off" will be -1
ttt = Integer.parseInt(attrs.get("timeout"));
} catch (NumberFormatException e) {
// not a number, do nothing (use -1)
}
app.setTooltipTimeout(ttt);
return true;
} catch (RuntimeException e) {
return false;
}
}
private static boolean handleLabelingStyle(App app,
LinkedHashMap<String, String> attrs) {
try {
int style = Integer.parseInt(attrs.get("val"));
app.setLabelingStyle(style);
return true;
} catch (RuntimeException e) {
return false;
}
}
// ====================================
// <perspectives>
// ====================================
private void startGuiPerspectivesElement(String eName,
LinkedHashMap<String, String> attrs) {
boolean ok = true;
if ("perspective".equals(eName)) {
ok = handlePerspective(attrs);
} else {
Log.warn("unknown tag in <perspectives>: " + eName);
}
if (!ok) {
Log.warn("error in <perspectives>: " + eName);
}
}
/**
* Create a new temporary perspective for the current <perspective> element
*
* @param attrs
* @return
*/
private boolean handlePerspective(LinkedHashMap<String, String> attrs) {
try {
tmp_perspective = new Perspective(attrs.get("id"));
tmp_perspectives.add(tmp_perspective);
if (tmp_panes == null) {
tmp_panes = new ArrayList<DockSplitPaneData>();
} else {
tmp_panes.clear();
}
if (tmp_views == null) {
tmp_views = new ArrayList<DockPanelData>();
} else {
tmp_views.clear();
}
mode = MODE_GUI_PERSPECTIVE;
return true;
} catch (RuntimeException e) {
Log.debug(e.getMessage() + ": " + e.getCause());
return false;
}
}
/**
* Save all perspectives in the application.
*/
private void endGuiPerspectivesElement() {
app.setTmpPerspectives(tmp_perspectives);
}
// ====================================
// <perspective>
// ====================================
private void startGuiPerspectiveElement(String eName,
LinkedHashMap<String, String> attrs) {
boolean ok = true;
switch (firstChar(eName)) {
case 'd':
if ("dockBar".equals(eName)) {
ok = handleDockBar(attrs);
break;
}
case 'i':
if ("input".equals(eName)) {
ok = handleAlgebraInput(attrs);
break;
}
case 'p':
if ("panes".equals(eName)) {
mode = MODE_GUI_PERSPECTIVE_PANES;
break;
}
case 's':
if ("show".equals(eName)) {
ok = handleGuiShow(app, attrs);
break;
}
case 't':
if ("toolbar".equals(eName)) {
ok = handleToolbar(attrs);
break;
}
case 'v':
if ("views".equals(eName)) {
mode = MODE_GUI_PERSPECTIVE_VIEWS;
break;
}
default:
Log.debug("unknown tag in <perspective>: " + eName);
}
if (!ok) {
Log.debug("error in <perspective>: " + eName);
}
}
private boolean handleAlgebraInput(LinkedHashMap<String, String> attrs) {
try {
tmp_perspective
.setShowInputPanel(!attrs.get("show").equals("false"));
tmp_perspective.setShowInputPanelCommands(
!attrs.get("cmd").equals("false"));
InputPosition ip = attrs.get("top").equals("true")
? InputPosition.top
: ("false".equals(attrs.get("top")) ? InputPosition.bottom
: InputPosition.algebraView);
tmp_perspective.setInputPosition(ip);
return true;
} catch (RuntimeException e) {
Log.debug(e.getMessage() + ": " + e.getCause());
return false;
}
}
private boolean handleDockBar(LinkedHashMap<String, String> attrs) {
try {
tmp_perspective.setShowDockBar(!attrs.get("show").equals("false"));
tmp_perspective.setDockBarEast(!attrs.get("east").equals("false"));
return true;
} catch (RuntimeException e) {
Log.debug(e.getMessage() + ": " + e.getCause());
return false;
}
}
private void endGuiPerspectiveElement() {
DockPanelData[] dpInfo = new DockPanelData[tmp_views.size()];
DockSplitPaneData[] spInfo = new DockSplitPaneData[tmp_panes.size()];
tmp_perspective.setDockPanelData(tmp_views.toArray(dpInfo));
tmp_perspective.setSplitPaneData(tmp_panes.toArray(spInfo));
}
// ====================================
// <views>
// ====================================
private void startGuiViewsElement(String eName,
LinkedHashMap<String, String> attrs) {
boolean ok = true;
if ("view".equals(eName)) {
ok = handleView(attrs);
} else {
Log.debug("unknown tag in <views>: " + eName);
}
if (!ok) {
Log.debug("error in <views>: " + eName);
}
}
/**
* Handle a view.
* <view id=".." visible=".." inframe=".." stylebar=".." window=".."
* location=".." size=".." />
*
* @param attrs
* @return
*/
private boolean handleView(LinkedHashMap<String, String> attrs) {
try {
int viewId = Integer.parseInt(attrs.get("id"));
String toolbar = attrs.get("toolbar");
boolean isVisible = !attrs.get("visible").equals("false");
boolean openInFrame = !attrs.get("inframe").equals("false");
String showStyleBarStr = attrs.get("stylebar");
boolean showStyleBar = !"false".equals(showStyleBarStr);
// the window rectangle is given in the format "x,y,width,height"
String[] window = attrs.get("window").split(",");
GRectangle windowRect = AwtFactory.getPrototype().newRectangle(
Integer.parseInt(window[0]), Integer.parseInt(window[1]),
Integer.parseInt(window[2]), Integer.parseInt(window[3]));
String embeddedDef = attrs.get("location");
int embeddedSize = Integer.parseInt(attrs.get("size"));
String plane = attrs.get("plane");
tmp_views.add(new DockPanelData(viewId, toolbar, isVisible,
openInFrame, showStyleBar, windowRect, embeddedDef,
embeddedSize, plane));
return true;
} catch (RuntimeException e) {
Log.debug(e.getMessage() + ": " + e.getCause());
return false;
}
}
// ====================================
// <panes>
// ====================================
private void startGuiPanesElement(String eName,
LinkedHashMap<String, String> attrs) {
boolean ok = true;
if ("pane".equals(eName)) {
ok = handlePane(attrs);
} else {
Log.debug("unknown tag in <panes>: " + eName);
}
if (!ok) {
Log.debug("error in <panes>: " + eName);
}
}
/**
* Handle a pane. <pane location".." divider=".." orientation=".." />
*
* @param attrs
* @return
*/
private boolean handlePane(LinkedHashMap<String, String> attrs) {
try {
String location = attrs.get("location");
double dividerLocation = StringUtil
.parseDouble(attrs.get("divider"));
int orientation = Integer.parseInt(attrs.get("orientation"));
tmp_panes.add(new DockSplitPaneData(location, dividerLocation,
orientation));
return true;
} catch (RuntimeException e) {
Log.debug(e.getMessage() + ": " + e.getCause());
return false;
}
}
// ====================================
// <construction>
// ====================================
private void handleConstruction(LinkedHashMap<String, String> attrs) {
try {
cons.setAllowUnboundedAngles(
Kernel.isGreaterEqual(ggbFileFormat, 4.4));
String title = attrs.get("title");
String author = attrs.get("author");
String date = attrs.get("date");
if (title != null) {
cons.setTitle(title);
}
if (author != null) {
cons.setAuthor(author);
}
if (date != null) {
cons.setDate(date);
}
} catch (RuntimeException e) {
Log.error("error in <construction>");
}
}
private void initMacro(LinkedHashMap<String, String> attrs) {
try {
String cmdName = attrs.get("cmdName");
String toolName = attrs.get("toolName");
String toolHelp = attrs.get("toolHelp");
String iconFile = attrs.get("iconFile");
boolean copyCaptions = parseBoolean(attrs.get("copyCaptions"));
String strShowInToolBar = attrs.get("showInToolBar");
Integer viewId = null;
if (attrs.containsKey("viewId")) {
viewId = Integer.parseInt(attrs.get("viewId"));
}
// Make sure we don't have a macro with the same name in kernel.
// This can happen when a macro file (ggt) is loaded because
// the previous macros are not cleared in this case.
int n = 0;
String myCmdName = cmdName;
while (kernel.getMacro(myCmdName) != null) {
n++;
myCmdName = cmdName + n;
}
// create macro and a kernel for it
macro = new Macro(kernel, myCmdName);
macro.setToolName(toolName);
macro.setCopyCaptionsAndVisibility(copyCaptions);
macro.setToolHelp(toolHelp);
macro.setIconFileName(iconFile);
boolean showTool = strShowInToolBar == null || parseBoolean(strShowInToolBar);
macro.setShowInToolBar(showTool);
macro.setViewId(viewId);
MacroKernel macroKernel = kernel.newMacroKernel();
macroKernel.setContinuous(false);
// we have to change the construction object temporarily so
// everything
// is done in the macro construction from now on
kernel = macroKernel;
cons = macroKernel.getConstruction();
parser = new GParser(macroKernel, cons);
} catch (RuntimeException e) {
Log.error("error in <macro>");
}
}
private void endMacro() {
// cons now holds a reference to the macroConstruction
macro.initMacro(cons, macroInputLabels, macroOutputLabels);
// ad the newly built macro to the kernel
origKernel.addMacro(macro);
// update construction resets the nearto relations in macro, so "outer
// world" won't affect it
cons.updateConstruction();
// set kernel and construction back to the original values
initKernelVars();
}
private void initExercise(LinkedHashMap<String, String> attrs) {
if (exercise == null) {
exercise = kernel.getExercise();
exercise.reset();
}
String name = attrs.get("commandName");
if (name == null) {
name = attrs.get("toolName");
}
if (name == null) {
name = attrs.get("booleanName");
if (name != null) {
assignment = exercise.addAssignment(name);
}
} else {
Macro m = kernel.getMacro(name);
// this should not be needed but for files saved between 41946 and
// 42226
// fileloading won't work (only files created in beta, probably
// only Judith and me, but...)
if (m == null) {
m = kernel.getMacro(name.replace(" ", ""));
}
assignment = exercise.addAssignment(m);
String op = attrs.get("checkOperation");
if (op == null) {
((GeoAssignment) assignment).setCheckOperation("AreEqual");
} else {
((GeoAssignment) assignment).setCheckOperation(op);
}
}
}
private void endExerciseElement(String eName) {
if ("assignment".equals(eName)) {
mode = MODE_GEOGEBRA;
}
}
/*
* <worksheetText above="blabla" below="morebla" />
*/
private void handleWorksheetText(LinkedHashMap<String, String> attrs) {
String above = attrs.get("above");
String below = attrs.get("below");
cons.setWorksheetText(above, 0);
cons.setWorksheetText(below, 1);
}
// ====================================
// <cascell>
// ====================================
private void startCasCell(String eName,
LinkedHashMap<String, String> attrs) {
// handle cas session mode
switch (casMode) {
case MODE_CONST_CAS_CELL:
if ("cellPair".equals(eName)) {
casMode = MODE_CAS_CELL_PAIR;
startCellPair();
} else {
Log.error("unknown tag in <cellPair>: " + eName);
}
break;
case MODE_CAS_CELL_PAIR:
if ("inputCell".equals(eName)) {
casMode = MODE_CAS_INPUT_CELL;
} else if ("outputCell".equals(eName)) {
casMode = MODE_CAS_OUTPUT_CELL;
} else if ("useAsText".equals(eName)) {
casMode = MODE_CAS_TEXT_CELL;
} else {
Log.error("unknown tag in <cellPair>: " + eName);
}
break;
case MODE_CAS_TEXT_CELL:
startCellTextElement(eName, attrs);
break;
case MODE_CAS_INPUT_CELL:
startCellInputElement(eName, attrs);
break;
case MODE_CAS_OUTPUT_CELL:
startCellOutputElement(eName, attrs);
break;
default:
Log.error("unknown cas session mode:" + constMode);
}
}
private void endCasCell(String eName) {
switch (casMode) {
case MODE_CONST_CAS_CELL:
if ("cascell".equals(eName)) {
mode = MODE_CONSTRUCTION;
constMode = MODE_CONSTRUCTION;
casMode = MODE_CONST_CAS_CELL;
geoCasCell = null;
}
break;
case MODE_CAS_CELL_PAIR:
if ("cellPair".equals(eName)) {
casMode = MODE_CONST_CAS_CELL;
endCellPair(eName);
}
break;
case MODE_CAS_TEXT_CELL:
if ("useAsText".equals(eName)) {
casMode = MODE_CAS_CELL_PAIR;
}
break;
case MODE_CAS_INPUT_CELL:
if ("inputCell".equals(eName)) {
casMode = MODE_CAS_CELL_PAIR;
}
break;
case MODE_CAS_OUTPUT_CELL:
if ("outputCell".equals(eName)) {
casMode = MODE_CAS_CELL_PAIR;
}
break;
default:
casMode = MODE_CONST_CAS_CELL; // set back mode
Log.error("unknown cas session mode:" + constMode);
}
}
private void startCellPair() {
geoCasCell = new GeoCasCell(cons);
}
private void endCellPair(String eName) {
if (geoCasCell == null) {
Log.error("no element set for <" + eName + ">");
return;
}
try {
// create necessary algorithm and twinGeo
boolean independentCell = !geoCasCell.hasVariablesOrCommands();
if (independentCell) {
// free cell, e.g. m := 7 creates twinGeo m = 7
// if this is the first cell, and there is no input, we return
// sometimes saved files contain one empty cell pair, see #2469
// attachment
if (cons.getCasCell(0) == null && geoCasCell
.getInput(StringTemplate.defaultTemplate).equals("")) {
return;
}
cons.addToConstructionList(geoCasCell, true);
cons.addToGeoSetWithCasCells(geoCasCell);
if (geoCasCell.isAssignmentVariableDefined()) {
// a non-native cell may have dependent twin geo even if
// inputs are constants
// update twin GeoElement
// cas is loaded
// we need to recalculate the output
if (kernel.getConstruction()
.isUpdateConstructionRunning()) {
geoCasCell.computeOutput();
} else {
geoCasCell.updateTwinGeo(false);
}
geoCasCell.setLabelOfTwinGeo();
if (geoCasCell.hasTwinGeo() && !geoCasCell.getTwinGeo()
.isInConstructionList()) {
if (!geoCasCell.getTwinGeo().getParentAlgorithm()
.isInConstructionList()) {
geoCasCell.getTwinGeo().getParentAlgorithm()
.addToConstructionList();
}
}
} else if (geoCasCell.isOutputEmpty()
&& kernel.isGeoGebraCASready()) { // output is computed
// if it is empty
// (redefinitions
// only)
geoCasCell.computeOutput();
}
// otherwise keep loaded output and avoid unnecessary
// computation
} else {
// create algorithm for dependent cell
// this also creates twinGeo if necessary
// output is not computed again, see AlgoDependenCasCell
// constructor
KernelCAS.dependentCasCell(geoCasCell);
}
} catch (RuntimeException e) {
Log.error("error when processing <cellpair>: " + e.getMessage());
e.printStackTrace();
}
}
private void startCellOutputElement(String eName,
LinkedHashMap<String, String> attrs) {
if (geoCasCell == null) {
Log.error("no element set for <" + eName + ">");
return;
}
boolean ok = true;
switch (firstChar(eName)) {
case 'e':
if ("expression".equals(eName)) {
ok = handleCasCellOutput(attrs);
break;
}
default:
Log.error("unknown tag in <outputCell>: " + eName);
}
if (!ok) {
Log.error("error in <outputCell>: " + eName);
}
}
private void startCellInputElement(String eName,
LinkedHashMap<String, String> attrs) {
if (geoCasCell == null) {
Log.error("no element set for <" + eName + ">");
return;
}
boolean ok = true;
switch (firstChar(eName)) {
case 'e':
if ("expression".equals(eName)) {
ok = handleCasCellInput(attrs);
break;
}
// case 'c':
// if ("color".equals(eName)) {
// ok = handleCASPairColor(attrs);
// break;
// }
default:
Log.error("unknown tag in <inputCell>: " + eName);
}
if (!ok) {
Log.error("error in <inputCell>: " + eName);
}
}
private void startCellTextElement(String eName,
LinkedHashMap<String, String> attrs) {
if (geoCasCell == null) {
Log.error("no element set for <" + eName + ">");
return;
}
geoCasCell.setUseAsText(true);
boolean ok = true;
if ("FontStyle".equals(eName)) {
String style = attrs.get("value");
geoCasCell.setFontStyle(Integer.parseInt(style));
} else if ("FontSizeM".equals(eName)) {
String size = attrs.get("value");
if (StringUtil.parseDouble(size) > 0) {
geoCasCell.setFontSizeMultiplier(StringUtil.parseDouble(size));
}
} else if ("FontColor".equals(eName)) {
String r = attrs.get("r");
String b = attrs.get("b");
String g = attrs.get("g");
geoCasCell.setFontColor(GColor.newColor(Integer.parseInt(r),
Integer.parseInt(g), Integer.parseInt(b)));
} else {
Log.error("unknown tag in <useAsText>: " + eName);
}
if (!ok) {
Log.error("error in <useAsText>: " + eName);
}
}
private void startDefault(String eName,
LinkedHashMap<String, String> attrs) {
switch (constMode) {
case MODE_DEFAULTS:
if ("element".equals(eName)) {
boolean old = kernel.getElementDefaultAllowed();
kernel.setElementDefaultAllowed(true);
constMode = MODE_DEFAULT_GEO;
geo = getGeoElement(attrs);
kernel.setElementDefaultAllowed(old);
} else {
Log.error("unknown tag in <default>: " + eName);
}
break;
case MODE_DEFAULT_GEO:
startGeoElement(eName, attrs);
break;
default:
Log.error("unknown default mode:" + constMode);
}
}
private void startConstructionElement(String eName,
LinkedHashMap<String, String> attrs) {
// handle construction mode
// Application.debug("constMode = "+constMode+", eName = "+eName);
switch (constMode) {
case MODE_CONSTRUCTION:
if ("element".equals(eName)) {
cons.setOutputGeo(null);
constMode = MODE_CONST_GEO_ELEMENT;
geo = getGeoElement(attrs);
sliderTagProcessed = false;
fontTagProcessed = false;
symbolicTagProcessed = false;
lineStyleTagProcessed = false;
if (geo instanceof VectorNDValue) {
((VectorNDValue) geo)
.setMode(((VectorNDValue) geo).getDimension() == 3
? Kernel.COORD_CARTESIAN_3D
: Kernel.COORD_CARTESIAN);
} else if (geo instanceof GeoPolyLine) {
((GeoPolyLine) geo).setVisibleInView3D(false);
}
} else if ("command".equals(eName)) {
cons.setOutputGeo(null);
constMode = MODE_CONST_COMMAND;
cmd = getCommand(attrs);
} else if ("expression".equals(eName)) {
startExpressionElement(attrs);
} else if ("cascell".equals(eName)) {
constMode = MODE_CONST_CAS_CELL;
casMode = MODE_CONST_CAS_CELL;
} else if ("worksheetText".equals(eName)) {
handleWorksheetText(attrs);
} else {
Log.error("unknown tag in <construction>: " + eName);
}
break;
case MODE_CONST_GEO_ELEMENT:
startGeoElement(eName, attrs);
break;
case MODE_CONST_COMMAND:
startCommandElement(eName, attrs);
break;
case MODE_CAS_MAP:
handleMapEntry(attrs);
break;
case MODE_CONST_CAS_CELL:
startCasCell(eName, attrs);
break;
default:
Log.error("unknown construction mode:" + constMode);
}
}
private void handleMapEntry(LinkedHashMap<String, String> attrs) {
this.casMap.put(attrs.get("key"), attrs.get("val"));
}
private void endConstructionElement(String eName) {
switch (constMode) {
case MODE_CONSTRUCTION:
if ("construction".equals(eName)) {
// process start points at end of construction
processStartPointList();
processLinkedGeoList();
processShowObjectConditionList();
processDynamicColorList();
processAnimationSpeedList();
processAnimationStepList();
processMinMaxList();
processEvSizes();
processAnimatingList(); // must be after min/maxList otherwise
// GeoElement.setAnimating doesn't work
// now called from MyXMLio.doParseXML()
// if (spreadsheetTraceNeeded) {
// // don't want to initialize trace manager unless necessary
// app.getTraceManager().loadTraceGeoCollection();
// }
if (kernel == origKernel) {
mode = MODE_GEOGEBRA;
} else {
// macro construction
mode = MODE_MACRO;
}
}
break;
case MODE_CONST_GEO_ELEMENT:
if ("element".equals(eName)) {
if (!sliderTagProcessed && geo.isGeoNumeric()) {
((GeoNumeric) geo).setShowExtendedAV(false);
} else if (!fontTagProcessed && geo.isGeoText()) {
((TextProperties) geo).setFontSizeMultiplier(1);
((TextProperties) geo).setSerifFont(false);
((TextProperties) geo).setFontStyle(GFont.PLAIN);
} else if (!lineStyleTagProcessed && ((geo.isGeoFunctionNVar()
&& ((GeoFunctionNVar) geo).isFun2Var())
|| geo.isGeoSurfaceCartesian())) {
geo.setLineThickness(0);
}
if (!symbolicTagProcessed && geo.isGeoText()) {
((GeoText) geo).setSymbolicMode(false, false);
}
if (casMap != null && geo instanceof CasEvaluableFunction) {
((CasEvaluableFunction) geo).updateCASEvalMap(casMap);
}
casMap = null;
constMode = MODE_CONSTRUCTION;
}
break;
case MODE_CONST_COMMAND:
if ("command".equals(eName)) {
cons.setOutputGeo(null);
casMap = null;
constMode = MODE_CONSTRUCTION;
}
break;
case MODE_CAS_MAP:
if ("casMap".equals(eName)) {
constMode = casMapParent;
}
break;
case MODE_CONST_CAS_CELL:
endCasCell(eName);
break;
default:
constMode = MODE_CONSTRUCTION; // set back mode
Log.error("unknown construction mode:" + constMode);
}
}
private void endDefaultElement(String eName) {
switch (constMode) {
case MODE_DEFAULTS:
if ("defaults".equals(eName)) {
mode = MODE_GEOGEBRA;
constMode = MODE_CONSTRUCTION;
this.processMinMaxList();
this.processAnimationStepList();
this.processAnimationSpeedList();
}
break;
case MODE_DEFAULT_GEO:
if ("element".equals(eName)) {
constMode = MODE_DEFAULTS;
}
break;
default:
constMode = MODE_DEFAULTS; // set back mode
Log.error("unknown defaults mode:" + constMode);
}
}
// ====================================
// <element>
// ====================================
private void processEvSizes() {
// Set<EuclidianSettings> eSet0 = xmin.keySet();
ArrayList<EuclidianSettings> eSet = new ArrayList<EuclidianSettings>(
xmin.keySet());
eSet.addAll(xtick.keySet());
eSet.addAll(ytick.keySet());
eSet.addAll(ztick.keySet());
for (EuclidianSettings ev : eSet) {
if (xmin.get(ev) == null) {
ev.setXminObject(null, true);
} else {
NumberValue n = getAlgProcessor()
.evaluateToNumeric(xmin.get(ev), handler);
ev.setXminObject(n, true);
}
}
for (EuclidianSettings ev : eSet) {
if (xmax.get(ev) == null) {
ev.setXmaxObject(null, true);
} else {
NumberValue n = getAlgProcessor()
.evaluateToNumeric(xmax.get(ev), handler);
ev.setXmaxObject(n, true);
}
}
for (EuclidianSettings ev : eSet) {
if (ymin.get(ev) == null) {
ev.setYminObject(null, true);
} else {
NumberValue n = getAlgProcessor()
.evaluateToNumeric(ymin.get(ev), handler);
ev.setYminObject(n, true);
}
}
for (EuclidianSettings ev : eSet) {
if (ymax.get(ev) == null) {
ev.setYmaxObject(null, true);
} else {
NumberValue n = getAlgProcessor()
.evaluateToNumeric(ymax.get(ev), handler);
ev.setYmaxObject(n, true);
}
// ev.updateBounds();
}
for (EuclidianSettings ev : eSet) {
if (!StringUtil.empty(xtick.get(ev))) {
GeoNumberValue n = getAlgProcessor()
.evaluateToNumeric(xtick.get(ev), handler);
ev.setAxisNumberingDistance(0, n);
}
// ev.updateBounds();
}
for (EuclidianSettings ev : eSet) {
if (!StringUtil.empty(ytick.get(ev))) {
GeoNumberValue n = getAlgProcessor()
.evaluateToNumeric(ytick.get(ev), handler);
ev.setAxisNumberingDistance(1, n);
}
// ev.updateBounds();
}
for (EuclidianSettings ev : eSet) {
if (!StringUtil.empty(ztick.get(ev))) {
GeoNumberValue n = getAlgProcessor()
.evaluateToNumeric(ztick.get(ev), handler);
ev.setAxisNumberingDistance(2, n);
}
// ev.updateBounds();
}
}
// called when <element> is encountered
// e.g. for <element type="point" label="P">
private GeoElement getGeoElement(LinkedHashMap<String, String> attrs) {
GeoElement geo1 = null;
String label = attrs.get("label");
String type = attrs.get("type");
String defaultset = attrs.get("default");
if (label == null || type == null) {
Log.error("attributes missing in <element>");
return geo1;
}
if (defaultset == null || !kernel.getElementDefaultAllowed()) {
// does a geo element with this label exist?
geo1 = kernel.lookupLabel(label);
// Application.debug(label+", geo="+geo);
// needed for TRAC-2719
// if geo wasn't found in construction list
// look in cas
if (geo1 == null) {
geo1 = kernel.lookupCasCellLabel(label);
}
if (geo1 == null) {
// try to find an algo on which this label depends
// geo = cons.resolveLabelDependency(label,
// kernel.getClassType(type));
// if none, create new geo
geo1 = kernel.createGeoElement(cons, type);
geo1.setLoadedLabel(label);
// Application.debug(label+", "+geo.isLabelSet());
// independent GeoElements should be hidden by default
// (as older versions of this file format did not
// store show/hide information for all kinds of objects,
// e.g. GeoNumeric)
geo1.setEuclidianVisible(false);
}
} else {
int defset = Integer.parseInt(defaultset);
geo1 = kernel.getConstruction().getConstructionDefaults()
.getDefaultGeo(defset);
if (geo1 == null) {
// wrong default setting, act as if there were no default set
geo1 = kernel.lookupLabel(label);
if (geo1 == null) {
geo1 = kernel.createGeoElement(cons, type);
geo1.setLoadedLabel(label);
geo1.setEuclidianVisible(false);
}
}
}
// use default point style on points
if (geo1.getGeoClassType().equals(GeoClass.POINT)
&& ggbFileFormat < 3.3) {
((PointProperties) geo1).setPointStyle(docPointStyle);
}
// for downward compatibility
if (geo1.isLimitedPath()) {
LimitedPath lp = (LimitedPath) geo1;
// old default value for intersections of segments, ...
// V2.5: default of "allow outlying intersections" is now false
lp.setAllowOutlyingIntersections(true);
// old default value for geometric transforms of segments, ...
// V2.6: default of "keep type on geometric transform" is now true
lp.setKeepTypeOnGeometricTransform(false);
}
return geo1;
}
/**
* Handle start tag inside <element>
*
* @param eName
* element name
* @param attrs
* attributes
*/
protected void startGeoElement(String eName,
LinkedHashMap<String, String> attrs) {
if (geo == null) {
Log.error("no element set for <" + eName + ">");
return;
}
boolean ok = true;
ScriptType scriptType = ScriptType.getTypeWithXMLName(eName);
if (scriptType != null) {
ok = handleScript(attrs, scriptType);
} else {
switch (firstChar(eName)) {
case 'a':
if ("auxiliary".equals(eName)) {
ok = handleAuxiliary(attrs);
break;
}
if ("autocolor".equals(eName)) {
ok = handleAutocolor(attrs);
break;
} else if ("animation".equals(eName)) {
ok = handleAnimation(attrs);
break;
} else if ("arcSize".equals(eName)) {
ok = handleArcSize(attrs);
break;
} else if ("allowReflexAngle".equals(eName)) {
ok = handleAllowReflexAngle(attrs);
break;
} else if ("absoluteScreenLocation".equals(eName)) {
ok = handleAbsoluteScreenLocation(attrs);
break;
} else if ("angleStyle".equals(eName)) {
ok = handleAngleStyle(attrs);
break;
}
case 'b':
if ("breakpoint".equals(eName)) {
ok = handleBreakpoint(attrs);
break;
} else if ("bgColor".equals(eName)) {
ok = handleBgColor(attrs);
break;
}
case 'c':
if ("coords".equals(eName)) {
ok = handleCoords(attrs);
break;
} else if ("coordStyle".equals(eName)) {
ok = handleCoordStyle(attrs);
break;
} else if ("caption".equals(eName)) {
ok = handleCaption(attrs);
break;
} else if ("condition".equals(eName)) {
ok = handleCondition(attrs);
break;
} else if ("checkbox".equals(eName)) {
ok = handleCheckbox(attrs);
break;
} else if ("coefficients".equals(eName)) {
ok = handleCoefficients(attrs);
break;
} else if ("comboBox".equals(eName)) {
ok = handleComboBox(attrs);
break;
} else if ("curveParam".equals(eName)) {
ok = handleCurveParam(attrs);
break;
} else if ("casMap".equals(eName)) {
casMap = new TreeMap<String, String>();
constMode = MODE_CAS_MAP;
casMapParent = MODE_CONST_GEO_ELEMENT;
ok = true;
break;
}
case 'd':
if ("decoration".equals(eName)) {
ok = handleDecoration(attrs);
break;
} else if ("decimals".equals(eName)) {
ok = handleTextDecimals(attrs);
break;
} else if ("dimensions".equals(eName)) {
ok = handleDimensions(attrs);
break;
}
case 'e':
if ("eqnStyle".equals(eName)) {
ok = handleEqnStyle(attrs);
break;
} else if ("eigenvectors".equals(eName)) {
ok = handleEigenvectors(attrs);
break;
} else if ("emphasizeRightAngle".equals(eName)) {
ok = handleEmphasizeRightAngle(attrs);
break;
}
case 'f':
if ("fixed".equals(eName)) {
ok = handleFixed(attrs);
break;
} else if ("file".equals(eName)) {
ok = handleFile(attrs);
break;
} else if ("font".equals(eName)) {
ok = handleTextFont(attrs);
break;
}
// Michael Borcherds 2007-11-19
else if ("forceReflexAngle".equals(eName)) {
ok = handleForceReflexAngle(attrs);
break;
}
case 'i':
if ("isLaTeX".equals(eName)) {
ok = handleIsLaTeX(attrs);
break;
} else if ("inBackground".equals(eName)) {
ok = handleInBackground(attrs);
break;
} else if ("interpolate".equals(eName)) {
ok = handleInterpolate(attrs);
break;
} else if ("isShape".equals(eName)) {
ok = handleIsShape(attrs);
break;
}
case 'k':
if ("keepTypeOnTransform".equals(eName)) {
ok = handleKeepTypeOnTransform(attrs);
break;
}
case 'l':
if ("lineStyle".equals(eName)) {
ok = handleLineStyle(attrs);
break;
} else if ("labelOffset".equals(eName)) {
ok = handleLabelOffset(attrs);
break;
} else if ("labelMode".equals(eName)) {
ok = handleLabelMode(attrs);
break;
} else if ("layer".equals(eName)) {
ok = handleLayer(attrs);
break;
} else if ("linkedGeo".equals(eName)) {
ok = handleLinkedGeo(attrs);
break;
} else if ("length".equals(eName)) {
ok = handleLength(attrs);
break;
} else if ("listType".equals(eName)) {
ok = handleListType(attrs);
break;
} else if ("listener".equals(eName)) {
ok = handleListeners(attrs);
break;
}
case 'm':
if ("matrix".equals(eName)) {
ok = handleMatrix(attrs);
break;
}
case 'o':
if ("objColor".equals(eName)) {
ok = handleObjColor(attrs);
break;
} else if ("outlyingIntersections".equals(eName)) {
ok = handleOutlyingIntersections(attrs);
break;
} /*
* else if ("objCoords".equals(eName)) { ok =
* handleObjCoords(attrs); break; }
*/
case 'p':
if ("pointSize".equals(eName)) {
ok = handlePointSize(attrs);
break;
}
else if ("pointStyle".equals(eName)) {
ok = handlePointStyle(attrs);
break;
}
/*
* should not be needed else if ("pathParameter".equals(eName))
* { ok = handlePathParameter(attrs); break; }
*/
case 's':
if ("show".equals(eName)) {
ok = handleShow(attrs);
break;
} else if ("showOnAxis".equals(eName)) {
ok = handleShowOnAxis(attrs);
break;
} else if ("startPoint".equals(eName)) {
ok = handleStartPoint(attrs);
break;
} else if ("slider".equals(eName)) {
ok = handleSlider(attrs);
break;
} else if ("symbolic".equals(eName)) {
ok = handleSymbolic(attrs);
break;
} else if ("slopeTriangleSize".equals(eName)) {
ok = handleSlopeTriangleSize(attrs);
break;
} else if ("significantfigures".equals(eName)) {
ok = handleTextFigures(attrs);
break;
} else if ("spreadsheetTrace".equals(eName)) {
ok = handleSpreadsheetTrace(attrs);
break;
} else if ("showTrimmed".equals(eName)) {
ok = handleShowTrimmed(attrs);
break;
} else if ("selectionAllowed".equals(eName)) {
ok = handleSelectionAllowed(attrs);
break;
} else if ("selectedIndex".equals(eName)) {
ok = handleSelectedIndex(attrs);
break;
}
case 't':
if ("trace".equals(eName)) {
ok = handleTrace(attrs);
break;
} else if ("tooltipMode".equals(eName)) {
ok = handleTooltipMode(attrs);
break;
} else if ("tag".equals(eName)) {
ok = handleExtraTag(attrs);
break;
} else if ("tags".equals(eName)) {
ok = true;
break;
}
case 'u':
if ("userinput".equals(eName)) {
ok = handleUserInput(attrs);
break;
}
case 'v':
if ("value".equals(eName)) {
ok = handleValue(attrs);
break;
}
default:
Log.error("unknown tag in <element>: " + eName);
}
}
if (!ok) {
Log.error("error in <element>: " + eName);
}
}
private boolean handleDimensions(LinkedHashMap<String, String> attrs) {
String width = attrs.get("width");
String height = attrs.get("height");
if (width != null && height != null) {
if (width.matches("\\d{2,3}") && height.matches("\\d{2,3}")) {
if (geo.isGeoButton()) {
GeoButton button = (GeoButton) geo;
button.setWidth(Integer.parseInt(width));
button.setHeight(Integer.parseInt(height));
button.setFixedSize(true);
return true;
}
return false;
}
return true;
}
return false;
}
private static char firstChar(String eName) {
if (eName == null || eName.length() == 0) {
return '?';
}
return eName.charAt(0);
}
private boolean handleShow(LinkedHashMap<String, String> attrs) {
try {
geo.setEuclidianVisible(parseBoolean(attrs.get("object")));
geo.setLabelVisible(parseBoolean(attrs.get("label")));
// bit 0 -> display object in EV1, 0 = true (default)
// bit 1 -> display object in EV2, 0 = false (default)
int EVs = 0; // default, display in just EV1
String str = attrs.get("ev");
if (str != null) {
EVs = Integer.parseInt(str);
}
if ((EVs & 1) == 0) {
geo.addView(App.VIEW_EUCLIDIAN);
} else {
geo.removeView(App.VIEW_EUCLIDIAN);
}
if ((EVs & 2) == 2) { // bit 1
geo.addView(App.VIEW_EUCLIDIAN2);
} else {
geo.removeView(App.VIEW_EUCLIDIAN2);
}
if ((EVs & 4) == 4) { // bit 2
geo.addViews3D();
}
if ((EVs & 8) == 8) { // bit 3
geo.removeViews3D();
}
if ((EVs & 16) == 16) { // bit 4
geo.setVisibleInViewForPlane(true);
if (!(cons instanceof MacroConstruction)) {
app.addToViewsForPlane(geo);
}
}
if ((EVs & 32) == 32) { // bit 5
geo.setVisibleInViewForPlane(false);
app.removeFromViewsForPlane(geo);
}
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
private boolean handleShowOnAxis(LinkedHashMap<String, String> attrs) {
try {
if (!(geo instanceof GeoFunction)) {
return false;
}
((GeoFunction) geo).setShowOnAxis(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
private boolean handleObjColor(LinkedHashMap<String, String> attrs) {
GColor col = handleColorAttrs(attrs);
if (col == null) {
return false;
}
geo.setObjColor(col);
// Dynamic colors
// Michael Borcherds 2008-04-02
String red = attrs.get("dynamicr");
String green = attrs.get("dynamicg");
String blue = attrs.get("dynamicb");
String alpha = attrs.get("dynamica");
String colorSpace = attrs.get("colorSpace");
if (red != null && green != null && blue != null) {
try {
if (!"".equals(red) || !"".equals(green) || !"".equals(blue)) {
if ("".equals(red)) {
red = "0";
}
if ("".equals(green)) {
green = "0";
}
if ("".equals(blue)) {
blue = "0";
}
StringBuilder sb = new StringBuilder();
sb.append('{');
sb.append(red);
sb.append(',');
sb.append(green);
sb.append(',');
sb.append(blue);
if (alpha != null && !"".equals(alpha)) {
sb.append(',');
sb.append(alpha);
}
sb.append('}');
// need to to this at end of construction (dependencies!)
dynamicColorList.add(new GeoExpPair(geo, sb.toString()));
geo.setColorSpace(
colorSpace == null ? GeoElement.COLORSPACE_RGB
: Integer.parseInt(colorSpace));
}
} catch (RuntimeException e) {
e.printStackTrace();
Log.error("Error loading Dynamic Colors");
}
}
String angle = attrs.get("hatchAngle");
if (angle != null) {
geo.setHatchingAngle(Integer.parseInt(angle));
}
String inverse = attrs.get("inverseFill");
if (inverse != null) {
geo.setInverseFill(Boolean.parseBoolean(inverse));
}
String distance = attrs.get("hatchDistance");
if (angle != null) {
geo.setHatchingDistance(Integer.parseInt(distance));
// Old files don't store fillType, just fillDistance. New files
// override this below.
geo.setFillType(FillType.HATCH);
}
String fillType = attrs.get("fillType");
if (fillType != null) {
geo.setFillType(
GeoElement.FillType.values()[Integer.parseInt(fillType)]);
}
String fillSymbol = attrs.get("fillSymbol");
if (fillSymbol != null) {
geo.setFillSymbol(fillSymbol);
}
String filename = attrs.get("image");
if (filename != null) {
geo.setFillImage(filename);
geo.setFillType(GeoElement.FillType.IMAGE);
}
alpha = attrs.get("alpha");
// ignore alpha value for lists prior to GeoGebra 3.2
if (alpha != null && (!geo.isGeoList() || ggbFileFormat > 3.19)) {
geo.setAlphaValue(Float.parseFloat(alpha));
}
return true;
}
private boolean handleBgColor(LinkedHashMap<String, String> attrs) {
GColor col = handleColorAlphaAttrs(attrs);
if (col == null) {
return false;
}
geo.setBackgroundColor(col);
return true;
}
/*
* expects r, g, b attributes to build a color
*/
private static GColor handleColorAttrs(
LinkedHashMap<String, String> attrs) {
try {
int red = Integer.parseInt(attrs.get("r"));
int green = Integer.parseInt(attrs.get("g"));
int blue = Integer.parseInt(attrs.get("b"));
return GColor.newColor(red, green, blue);
} catch (RuntimeException e) {
return null;
}
}
/*
* expects r, g, b, alpha attributes to build a color
*/
private static GColor handleColorAlphaAttrs(
LinkedHashMap<String, String> attrs) {
try {
int red = Integer.parseInt(attrs.get("r"));
int green = Integer.parseInt(attrs.get("g"));
int blue = Integer.parseInt(attrs.get("b"));
int alpha = Integer.parseInt(attrs.get("alpha"));
return GColor.newColor(red, green, blue, alpha);
} catch (RuntimeException e) {
return null;
}
}
private boolean lineStyleTagProcessed;
private boolean symbolicTagProcessed;
private TreeMap<String, String> casMap;
private int casMapParent;
private boolean handleLineStyle(LinkedHashMap<String, String> attrs) {
try {
lineStyleTagProcessed = true;
geo.setLineType(Integer.parseInt(attrs.get("type")));
geo.setLineThickness(Integer.parseInt(attrs.get("thickness")));
// for 3D
String typeHidden = attrs.get("typeHidden");
if (typeHidden != null) {
geo.setLineTypeHidden(Integer.parseInt(typeHidden));
}
String opacity = attrs.get("opacity");
if (opacity != null) {
geo.setLineOpacity(Integer.parseInt(opacity));
}
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
private boolean handleDecoration(LinkedHashMap<String, String> attrs) {
try {
geo.setDecorationType(Integer.parseInt(attrs.get("type")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleEqnStyle(LinkedHashMap<String, String> attrs) {
// line
if (geo.isGeoLine()) {
GeoLineND line = (GeoLineND) geo;
String style = attrs.get("style");
if ("implicit".equals(style)) {
line.setToImplicit();
} else if ("explicit".equals(style)) {
line.setToExplicit();
} else if ("parametric".equals(style)) {
String parameter = attrs.get("parameter");
line.setToParametric(parameter);
} else if ("user".equals(style)) {
line.setToUser();
} else if ("general".equals(style)) {
line.setToGeneral();
} else {
Log.error("unknown style for line in <eqnStyle>: " + style);
return false;
}
}
// conic
else if (geo.isGeoConic()) {
GeoConicND conic = (GeoConicND) geo;
String style = attrs.get("style");
if ("implicit".equals(style)) {
conic.setToImplicit();
} else if ("specific".equals(style)) {
conic.setToSpecific();
} else if ("explicit".equals(style)) {
conic.setToExplicit();
} else if ("parametric".equals(style)) {
conic.setToParametric();
} else if ("user".equals(style)) {
conic.setToUser();
} else if ("vertex".equals(style)) {
conic.setToVertexform();
} else {
Log.error("unknown style for conic in <eqnStyle>: " + style);
return false;
}
} else {
Log.error("wrong element type for <eqnStyle>: " + geo.getClass());
return false;
}
return true;
}
private boolean handleCurveParam(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof GeoVec3D)) {
Log.debug("wrong element type for <curveParam>: " + geo.getClass());
return false;
}
GeoVec3D v = (GeoVec3D) geo;
try {
String tAttr = attrs.get("t");
if (tAttr != null) {
// AlgoPointOnPath
double t = StringUtil.parseDouble(tAttr);
((GeoPoint) v).getPathParameter().setT(t);
}
return true;
} catch (RuntimeException e) {
Log.error("problem in <curveParam>: " + e.getMessage());
return false;
}
}
private boolean handleCoords(LinkedHashMap<String, String> attrs) {
ExpressionNode def = geo.getDefinition();
boolean success = kernel.handleCoords(geo, attrs);
geo.setDefinition(def);
return success;
}
// for point or vector
private boolean handleCoordStyle(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof CoordStyle)) {
Log.error("wrong element type for <coordStyle>: " + geo.getClass());
return false;
}
CoordStyle v = (CoordStyle) geo;
String style = attrs.get("style");
if ("cartesian".equals(style)) {
v.setCartesian();
} else if ("polar".equals(style)) {
v.setPolar();
} else if ("complex".equals(style)) {
v.setComplex();
} else if ("cartesian3d".equals(style)) {
v.setCartesian3D();
} else if ("spherical".equals(style)) {
v.setSpherical();
} else {
Log.error("unknown style in <coordStyle>: " + style);
return false;
}
return true;
}
private boolean handleListeners(LinkedHashMap<String, String> attrs) {
try {
if ("objectUpdate".equals(attrs.get("type"))) {
app.getScriptManager().getUpdateListenerMap().put(geo,
JsScript.fromName(app, attrs.get("val")));
}
if ("objectClick".equals(attrs.get("type"))) {
app.getScriptManager().getClickListenerMap().put(geo,
JsScript.fromName(app, attrs.get("val")));
}
return true;
} catch (RuntimeException e) {
Log.error(e.getMessage());
return false;
}
}
private boolean handleCaption(LinkedHashMap<String, String> attrs) {
try {
geo.setCaption(attrs.get("val"));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleScript(LinkedHashMap<String, String> attrs,
ScriptType type) {
try {
String text = attrs.get("val");
if (text != null && text.length() > 0) {
Script script = app.createScript(type, text, false);
geo.setClickScript(script);
}
text = attrs.get("onUpdate");
if (text != null && text.length() > 0) {
Script script = app.createScript(type, text, false);
geo.setUpdateScript(script);
}
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleCondition(LinkedHashMap<String, String> attrs) {
try {
// condition for visibility of object
String strShowObjectCond = attrs.get("showObject");
if (strShowObjectCond != null) {
// store (geo, epxression) values
// they will be processed in processShowObjectConditionList()
// later
showObjectConditionList
.add(new GeoExpPair(geo, strShowObjectCond));
}
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleCheckbox(LinkedHashMap<String, String> attrs) {
if (!(geo.isGeoBoolean())) {
Log.error("wrong element type for <checkbox>: " + geo.getClass());
return false;
}
try {
GeoBoolean bool = (GeoBoolean) geo;
bool.setCheckboxFixed(parseBoolean(attrs.get("fixed")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleValue(LinkedHashMap<String, String> attrs) {
boolean isBoolean = geo.isGeoBoolean();
boolean isNumber = geo.isGeoNumeric();
// GGB-244 something that was formerly just a number is now a segment:
// hide it!
if (geo.isNumberValue() && !isNumber && !isBoolean) {
geo.setEuclidianVisible(false);
return true;
}
// set value even when definition exists; might be needed if value
// depends on Corner
ExpressionNode oldDef = geo.getDefinition();
if (!(isNumber || isBoolean || geo.isGeoButton())) {
Log.debug("wrong element type for <value>: " + geo.getClass());
return false;
}
try {
String strVal = attrs.get("val");
if (isNumber) {
GeoNumeric n = (GeoNumeric) geo;
n.setValue(StringUtil.parseDouble(strVal));
// random
n.setRandom("true".equals(attrs.get("random")));
n.setDefinition(oldDef);
} else if (isBoolean) {
GeoBoolean bool = (GeoBoolean) geo;
/*
* GGB-1372: use the recently computed value instead of the
* saved one for the Prove command
*/
if (!(geo.getParentAlgorithm() instanceof AlgoProve)) {
bool.setValue(parseBoolean(strVal));
}
bool.setDefinition(oldDef);
} else if (geo.isGeoButton()) {
// XXX What's this javascript doing here? (Arnaud)
GeoButton button = (GeoButton) geo;
Script script = app.createScript(ScriptType.JAVASCRIPT, strVal,
false);
button.setClickScript(script);
}
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
private boolean handlePointSize(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof PointProperties)) {
Log.debug("wrong element type for <pointSize>: " + geo.getClass());
return false;
}
try {
PointProperties p = (PointProperties) geo;
p.setPointSize(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handlePointStyle(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof PointProperties)) {
Log.debug("wrong element type for <pointStyle>: " + geo.getClass());
return false;
}
try {
PointProperties p = (PointProperties) geo;
int style = Integer.parseInt(attrs.get("val"));
if (style == -1) {
style = docPointStyle;
}
p.setPointStyle(style);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleLayer(LinkedHashMap<String, String> attrs) {
try {
geo.setLayer(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleCasCellInput(LinkedHashMap<String, String> attrs) {
try {
String input = attrs.get("value");
geoCasCell.setInput(input, true);
boolean pointList = parseBoolean(attrs.get("pointList"));
geoCasCell.setPointList(pointList);
String prefix = attrs.get("prefix");
String eval = attrs.get("eval");
String postfix = attrs.get("postfix");
if (eval != null) {
geoCasCell.setProcessingInformation(prefix, eval, postfix);
}
String evalCmd = attrs.get("evalCmd");
geoCasCell.setEvalCommand(evalCmd);
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
private boolean handleCasCellOutput(LinkedHashMap<String, String> attrs) {
if (geoCasCell.isUseAsText()) {
return true;
}
try {
String output = attrs.get("value");
boolean error = parseBoolean(attrs.get("error"));
boolean nativeOutput = parseBoolean(attrs.get("native"));
geoCasCell.setNative(nativeOutput);
if (error) {
geoCasCell.setError(output);
} else {
if (!nativeOutput) {
geoCasCell.computeOutput();
} else {
geoCasCell.setOutput(output, false);
}
}
String evalCommandComment = attrs.get("evalCommand");
if (evalCommandComment != null) {
geoCasCell.setEvalCommand(evalCommandComment);
} else {
geoCasCell.setEvalCommand("");
}
String evalComment = attrs.get("evalComment");
if (evalComment != null) {
geoCasCell.setEvalComment(evalComment);
}
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
// private boolean handleCASPairColor(LinkedHashMap<String, String> attrs) {
// Color col = handleColorAttrs(attrs);
// if (col == null)
// return false;
// // geo.setObjColor(col);
//
// return true;
// }
/*
* this should not be needed private boolean
* handlePathParameter(LinkedHashMap<String, String> attrs) { if
* (!(geo.isGeoPoint())) { Application.debug(
* "wrong element type for <handlePathParameter>: " + geo.getClass());
* return false; }
*
* try { GeoPoint p = (GeoPoint) geo; PathParameter param = new
* PathParameter(); double t = StringUtil.parseDouble((String)
* attrs.get("val")); param.setT(t);
*
* String strBranch = (String) attrs.get("branch"); if (strBranch != null) {
* param.setBranch(Integer.parseInt(strBranch)); }
*
* String strType = (String) attrs.get("type"); if (strType != null) {
* param.setPathType(Integer.parseInt(strType)); }
*
* p.initPathParameter(param); return true; } catch(RuntimeException e) {
* return false; } }
*/
private boolean handleSlider(LinkedHashMap<String, String> attrs) {
if (!(geo.isGeoNumeric())) {
Log.error("wrong element type for <slider>: " + geo.getClass());
return false;
}
try {
sliderTagProcessed = true;
// don't create sliders in macro construction
if (geo.getKernel().isMacroKernel()) {
return true;
}
GeoNumeric num = (GeoNumeric) geo;
// make sure
String strMin = attrs.get("min");
String strMax = attrs.get("max");
if (strMin != null || strMax != null) {
minMaxList.add(new GeoNumericMinMax(geo, strMin, strMax));
}
String str = attrs.get("absoluteScreenLocation");
if (str != null) {
num.setAbsoluteScreenLocActive(parseBoolean(str));
} else {
num.setAbsoluteScreenLocActive(false);
}
// null in preferences
if (attrs.get("x") != null) {
double x = StringUtil.parseDouble(attrs.get("x"));
double y = StringUtil.parseDouble(attrs.get("y"));
num.setSliderLocation(x, y, true);
}
num.setSliderWidth(StringUtil.parseDouble(attrs.get("width")));
num.setSliderFixed(parseBoolean(attrs.get("fixed")));
num.setShowExtendedAV(parseBoolean(attrs.get("showAlgebra")));
num.setSliderHorizontal(parseBoolean(attrs.get("horizontal")));
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
}
private boolean handleTrace(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof Traceable)) {
Log.error("wrong element type for <trace>: " + geo.getClass());
return false;
}
try {
Traceable t = (Traceable) geo;
t.setTrace(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSpreadsheetTrace(
LinkedHashMap<String, String> attrs) {
// G.Sturr 2010-5-30
// XML handling for new tracing code
if (!geo.isSpreadsheetTraceable()) {
Log.error("wrong element type for <trace>: " + geo.getClass());
return false;
}
try {
// set geo for tracing
geo.setSpreadsheetTrace(parseBoolean(attrs.get("val")));
SpreadsheetTraceSettings t = geo.getTraceSettings();
t.traceColumn1 = Integer.parseInt(attrs.get("traceColumn1"));
t.traceColumn2 = Integer.parseInt(attrs.get("traceColumn2"));
t.traceRow1 = Integer.parseInt(attrs.get("traceRow1"));
t.traceRow2 = Integer.parseInt(attrs.get("traceRow2"));
t.tracingRow = Integer.parseInt(attrs.get("tracingRow"));
t.numRows = Integer.parseInt(attrs.get("numRows"));
t.headerOffset = Integer.parseInt(attrs.get("headerOffset"));
t.doColumnReset = (parseBoolean(attrs.get("doColumnReset")));
t.doRowLimit = (parseBoolean(attrs.get("doRowLimit")));
t.showLabel = (parseBoolean(attrs.get("showLabel")));
t.showTraceList = (parseBoolean(attrs.get("showTraceList")));
t.doTraceGeoCopy = (parseBoolean(attrs.get("doTraceGeoCopy")));
String stringPause = attrs.get("pause");
if (stringPause == null) {
t.pause = false;
} else {
t.pause = parseBoolean(stringPause);
}
app.setNeedsSpreadsheetTableModel();
// app.getTraceManager().loadTraceGeoCollection(); is called when
// construction loaded to add geo to trace list
return true;
} catch (RuntimeException e) {
e.printStackTrace();
return false;
}
/*
* OLD CODE
*
* if (!(geo instanceof GeoPoint)) { Log.error(
* "wrong element type for <trace>: " + geo.getClass()); return false; }
*
* try { GeoPoint p = (GeoPoint) geo;
* p.setSpreadsheetTrace(parseBoolean((String) attrs.get("val")));
* return true; } catch(RuntimeException e) { return false; }
*/
// END G.Sturr
}
private boolean handleShowTrimmed(LinkedHashMap<String, String> attrs) {
try {
geo.setShowTrimmedIntersectionLines(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSelectionAllowed(
LinkedHashMap<String, String> attrs) {
try {
geo.setSelectionAllowed(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSelectedIndex(LinkedHashMap<String, String> attrs) {
try {
if (geo.isGeoList()) {
((GeoList) geo).setSelectedIndex(
Integer.parseInt(attrs.get("val")), false);
}
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleAnimation(LinkedHashMap<String, String> attrs) {
try {
String strStep = attrs.get("step");
if (strStep != null) {
// store speed expression to be processed later
animationStepList.add(new GeoExpPair(geo, strStep));
}
String strSpeed = attrs.get("speed");
if (strSpeed != null) {
// store speed expression to be processed later
animationSpeedList.add(new GeoExpPair(geo, strSpeed));
}
String type = attrs.get("type");
if (type != null) {
geo.setAnimationType(Integer.parseInt(type));
}
// doesn't work for hidden sliders now that intervalMin/Max are set
// at end of XML (dynamic slider range(
// geo.setAnimating(parseBoolean((String) attrs.get("playing")));
// replacement
if (parseBoolean(attrs.get("playing"))) {
animatingList.add(geo);
}
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleFixed(LinkedHashMap<String, String> attrs) {
try {
geo.setFixed(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleIsShape(LinkedHashMap<String, String> attrs) {
try {
geo.setIsShape(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleBreakpoint(LinkedHashMap<String, String> attrs) {
try {
geo.setConsProtocolBreakpoint(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleFile(LinkedHashMap<String, String> attrs) {
if (!(geo.isGeoImage() || geo.isGeoButton() || geo.isGeoTurtle())) {
Log.error("wrong element type for <file>: " + geo.getClass());
return false;
}
try {
geo.setImageFileName(attrs.get("name"));
return true;
} catch (RuntimeException e) {
return false;
}
}
// <font serif="false" size="12" style="0">
private boolean handleTextFont(LinkedHashMap<String, String> attrs) {
this.fontTagProcessed = true;
if (!(geo instanceof TextProperties)) {
Log.error("wrong element type for <font>: " + geo.getClass());
return false;
}
Object serif = attrs.get("serif");
Object style = attrs.get("style");
try {
TextProperties text = (TextProperties) geo;
String oldSize = attrs.get("size");
// multiplier, new from ggb42
String size = attrs.get("sizeM");
if (size == null) {
double appSize = app.getFontSize();
double oldSizeInt = Integer.parseInt(oldSize);
text.setFontSizeMultiplier(
Math.max(appSize + oldSizeInt, MIN_TEXT_SIZE)
/ appSize);
} else {
text.setFontSizeMultiplier(StringUtil.parseDouble(size));
}
if (serif != null) {
text.setSerifFont(parseBoolean((String) serif));
}
if (style != null) {
text.setFontStyle(Integer.parseInt((String) style));
}
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleTextDecimals(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof TextProperties)) {
Log.error("wrong element type for <decimals>: " + geo.getClass());
return false;
}
try {
TextProperties text = (TextProperties) geo;
text.setPrintDecimals(Integer.parseInt(attrs.get("val")), true);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleTextFigures(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof TextProperties)) {
Log.error("wrong element type for <decimals>: " + geo.getClass());
return false;
}
try {
TextProperties text = (TextProperties) geo;
text.setPrintFigures(Integer.parseInt(attrs.get("val")), true);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleInBackground(LinkedHashMap<String, String> attrs) {
if (!(geo.isGeoImage())) {
Log.error(
"wrong element type for <inBackground>: " + geo.getClass());
return false;
}
try {
((GeoImage) geo).setInBackground(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleInterpolate(LinkedHashMap<String, String> attrs) {
if (!(geo.isGeoImage())) {
Log.error(
"wrong element type for <interpolate>: " + geo.getClass());
return false;
}
try {
((GeoImage) geo).setInterpolate(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleAuxiliary(LinkedHashMap<String, String> attrs) {
try {
geo.setAuxiliaryObject(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleAutocolor(LinkedHashMap<String, String> attrs) {
try {
geo.setAutoColor(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleIsLaTeX(LinkedHashMap<String, String> attrs) {
try {
((GeoText) geo).setLaTeX(parseBoolean(attrs.get("val")), false);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleArcSize(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof AngleProperties)) {
Log.error("wrong element type for <arcSize>: " + geo.getClass());
return false;
}
try {
AngleProperties angle = (AngleProperties) geo;
angle.setArcSize(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleAbsoluteScreenLocation(
LinkedHashMap<String, String> attrs) {
if (!(geo instanceof AbsoluteScreenLocateable)) {
Log.error("wrong element type for <absoluteScreenLocation>: "
+ geo.getClass());
return false;
}
try {
AbsoluteScreenLocateable absLoc = (AbsoluteScreenLocateable) geo;
int x = Integer.parseInt(attrs.get("x"));
int y = Integer.parseInt(attrs.get("y"));
absLoc.setAbsoluteScreenLoc(x, y);
absLoc.setAbsoluteScreenLocActive(true);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleAllowReflexAngle(
LinkedHashMap<String, String> attrs) {
if (!(geo instanceof AngleProperties)) {
Log.error("wrong element type for <allowReflexAngle>: "
+ geo.getClass());
return false;
}
try {
AngleProperties angle = (AngleProperties) geo;
angle.setAllowReflexAngle(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleEmphasizeRightAngle(
LinkedHashMap<String, String> attrs) {
if (!(geo instanceof AngleProperties)) {
Log.error("wrong element type for <emphasizeRightAngle>: "
+ geo.getClass());
return false;
}
try {
AngleProperties angle = (AngleProperties) geo;
angle.setEmphasizeRightAngle(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleComboBox(LinkedHashMap<String, String> attrs) {
if (!(geo.isGeoList())) {
Log.error("wrong element type for <comboBox>: " + geo.getClass());
return false;
}
try {
GeoList list = (GeoList) geo;
list.setDrawAsComboBox(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleAngleStyle(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof AngleProperties)) {
Log.error("wrong element type for <angleStyle>: " + geo.getClass());
return false;
}
try {
AngleProperties angle = (AngleProperties) geo;
angle.setAngleStyle(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
/*
* needed for old files (4.2 and earlier)
*/
private boolean handleForceReflexAngle(
LinkedHashMap<String, String> attrs) {
if (!(geo instanceof AngleProperties)) {
Log.error("wrong element type for <forceReflexAngle>: "
+ geo.getClass());
return false;
}
try {
AngleProperties angle = (AngleProperties) geo;
angle.setForceReflexAngle(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
// Michael Borcherds 2007-11-19
private boolean handleOutlyingIntersections(
LinkedHashMap<String, String> attrs) {
if (!(geo instanceof LimitedPath)) {
Log.debug("wrong element type for <outlyingIntersections>: "
+ geo.getClass());
return false;
}
try {
LimitedPath lpath = (LimitedPath) geo;
lpath.setAllowOutlyingIntersections(parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleKeepTypeOnTransform(
LinkedHashMap<String, String> attrs) {
if (!(geo instanceof LimitedPath)) {
Log.debug("wrong element type for <outlyingIntersections>: "
+ geo.getGeoClassType());
return false;
}
try {
LimitedPath lpath = (LimitedPath) geo;
lpath.setKeepTypeOnGeometricTransform(
parseBoolean(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSymbolic(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof HasSymbolicMode)) {
Log.error("wrong element type for <symbolic>: " + geo.getClass());
return false;
}
symbolicTagProcessed = true;
try {
HasSymbolicMode num = (HasSymbolicMode) geo;
num.setSymbolicMode(parseBoolean(attrs.get("val")), false);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleSlopeTriangleSize(
LinkedHashMap<String, String> attrs) {
if (!(geo.isGeoNumeric())) {
Log.error("wrong element type for <slopeTriangleSize>: "
+ geo.getClass());
return false;
}
try {
GeoNumeric num = (GeoNumeric) geo;
num.setSlopeTriangleSize(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
/**
* Start Points have to be handled at the end of the construction, because
* they could depend on objects that are defined after this GeoElement.
*
* So we store all (geo, startpoint expression) pairs and process them at
* the end of the construction.
*
* @see processStartPointList
*/
private boolean handleStartPoint(LinkedHashMap<String, String> attrs) {
if (!(geo instanceof Locateable)) {
Log.error("wrong element type for <startPoint>: " + geo.getClass());
return false;
}
Locateable locGeo = (Locateable) geo;
// relative start point (expression or label expected)
String exp = attrs.get("exp");
if (exp == null) {
exp = attrs.get("label");
}
// for corners a number of the startPoint is given
int number = 0;
try {
number = Integer.parseInt(attrs.get("number"));
} catch (RuntimeException e) {
// do nothing
}
if (exp != null) {
// store (geo, epxression, number) values
// they will be processed in processStartPoints() later
startPointList.add(new LocateableExpPair(locGeo, exp, number));
locGeo.setWaitForStartPoint();
} else {
// absolute start point (coords expected)
try {
/*
* double x = StringUtil.parseDouble((String) attrs.get("x"));
* double y = StringUtil.parseDouble((String) attrs.get("y"));
* double z = StringUtil.parseDouble((String) attrs.get("z"));
* GeoPoint p = new GeoPoint(cons); p.setCoords(x, y, z);
*/
GeoPointND p = handleAbsoluteStartPoint(attrs);
if (number == 0) {
// set first start point right away
locGeo.setStartPoint(p);
} else {
// set other start points later
// store (geo, point, number) values
// they will be processed in processStartPoints() later
startPointList
.add(new LocateableExpPair(locGeo, p, number));
locGeo.setWaitForStartPoint();
}
} catch (Exception e) {
return false;
}
}
return true;
}
/**
* create absolute start point (coords expected)
*
* @param attrs
* tag atributes
* @return start point
*/
protected GeoPointND handleAbsoluteStartPoint(
LinkedHashMap<String, String> attrs) {
double x = Double.NaN;
double y = Double.NaN;
double z = Double.NaN;
x = StringUtil.parseDouble(attrs.get("x"));
y = StringUtil.parseDouble(attrs.get("y"));
z = StringUtil.parseDouble(attrs.get("z"));
GeoPoint p = new GeoPoint(cons);
p.setCoords(x, y, z);
return p;
}
private void processStartPointList() {
try {
Iterator<LocateableExpPair> it = startPointList.iterator();
AlgebraProcessor algProc = getAlgProcessor();
while (it.hasNext()) {
LocateableExpPair pair = it.next();
GeoPointND P = pair.point != null ? pair.point
: algProc.evaluateToPoint(pair.exp,
ErrorHelper.silent(), true);
pair.locateable.setStartPoint(P, pair.number);
}
} catch (Exception e) {
startPointList.clear();
e.printStackTrace();
errors.add("Invalid start point: " + e.toString());
}
startPointList.clear();
}
private boolean handleLength(LinkedHashMap<String, String> attrs) {
// name of linked geo
String val = attrs.get("val");
if (geo instanceof GeoInputBox) {
((GeoInputBox) geo).setLength(Integer.parseInt(val));
} else {
Log.error("Length not supported for " + geo.getGeoClassType());
}
return true;
}
private boolean handleListType(LinkedHashMap<String, String> attrs) {
// name of geo type, eg "point"
String val = attrs.get("val");
if (geo instanceof GeoList) {
((GeoList) geo).setTypeStringForXML(val);
} else {
Log.error("handleListType: expected LIST, got "
+ geo.getGeoClassType());
}
return true;
}
/**
* Linked Geos have to be handled at the end of the construction, because
* they could depend on objects that are defined after this GeoElement.
*
* So we store all (geo, expression) pairs and process them at the end of
* the construction.
*
* @see processLinkedGeoList
*/
private boolean handleLinkedGeo(LinkedHashMap<String, String> attrs) {
// name of linked geo
String exp = attrs.get("exp");
if (exp != null) {
// store (geo, epxression, number) values
// they will be processed in processLinkedGeos() later
linkedGeoList.add(new GeoExpPair(geo, exp));
} else {
return false;
}
return true;
}
private void processLinkedGeoList() {
try {
Iterator<GeoExpPair> it = linkedGeoList.iterator();
while (it.hasNext()) {
GeoExpPair pair = it.next();
((GeoInputBox) pair.getGeo())
.setLinkedGeo(kernel.lookupLabel(pair.exp));
}
} catch (RuntimeException e) {
linkedGeoList.clear();
e.printStackTrace();
errors.add("Invalid linked geo " + e.toString());
}
linkedGeoList.clear();
}
private void processShowObjectConditionList() {
Iterator<GeoExpPair> it = showObjectConditionList.iterator();
AlgebraProcessor algProc = getAlgProcessor();
while (it.hasNext()) {
try {
GeoExpPair pair = it.next();
GeoBoolean condition = algProc.evaluateToBoolean(pair.exp,
ErrorHelper.silent());
if (condition != null) {
pair.getGeo().setShowObjectCondition(condition);
} else {
errors.add("Invalid condition to show object: " + pair.exp);
}
} catch (Exception e) {
showObjectConditionList.clear();
e.printStackTrace();
errors.add("Invalid condition to show object: " + e.toString());
}
}
showObjectConditionList.clear();
}
private void processAnimationSpeedList() {
try {
Iterator<GeoExpPair> it = animationSpeedList.iterator();
AlgebraProcessor algProc = getAlgProcessor();
while (it.hasNext()) {
GeoExpPair pair = it.next();
GeoNumberValue num = algProc.evaluateToNumeric(pair.exp,
handler);
pair.getGeo().setAnimationSpeedObject(num);
}
} catch (RuntimeException e) {
animationSpeedList.clear();
e.printStackTrace();
errors.add("Invalid animation speed: " + e.toString());
}
animationSpeedList.clear();
}
private void processAnimationStepList() {
try {
Iterator<GeoExpPair> it = animationStepList.iterator();
AlgebraProcessor algProc = getAlgProcessor();
while (it.hasNext()) {
GeoExpPair pair = it.next();
NumberValue num = algProc.evaluateToNumeric(pair.exp, handler);
if (pair.getGeo().isGeoNumeric()) {
((GeoNumeric) pair.getGeo())
.setAutoStep(Double.isNaN(num.getDouble()));
}
pair.getGeo().setAnimationStep(num);
}
} catch (RuntimeException e) {
animationStepList.clear();
e.printStackTrace();
errors.add("Invalid animation step: " + e.toString());
}
animationSpeedList.clear();
}
private void processAnimatingList() {
try {
Iterator<GeoElement> it = animatingList.iterator();
while (it.hasNext()) {
GeoElement geo1 = it.next();
geo1.setAnimating(true);
}
} catch (RuntimeException e) {
errors.add("Invalid animating: " + e.toString());
}
animatingList.clear();
}
private ErrorHandler handler = new ErrorHandler() {
@Override
public void showError(String msg) {
errors.add(msg);
}
@Override
public void resetError() {
showError(null);
}
@Override
public void showCommandError(String command, String message) {
errors.add(message);
}
@Override
public String getCurrentCommand() {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean onUndefinedVariables(String string,
AsyncOperation<String[]> callback) {
// TODO Auto-generated method stub
return false;
}
};
private void processMinMaxList() {
try {
Iterator<GeoNumericMinMax> it = minMaxList.iterator();
AlgebraProcessor algProc = getAlgProcessor();
while (it.hasNext()) {
GeoNumericMinMax pair = it.next();
// the setIntervalMin and setIntervalMax methods might turn ?
// into defined
// this is intentional, but when loading a file we must override
// it for 3.2 compatibility
boolean wasDefined = pair.getGeo().isDefined();
if (pair.min != null) {
NumberValue num = algProc.evaluateToNumeric(pair.min,
handler);
((GeoNumeric) pair.getGeo()).setIntervalMin(num);
}
if (pair.max != null) {
NumberValue num2 = algProc.evaluateToNumeric(pair.max,
handler);
((GeoNumeric) pair.getGeo()).setIntervalMax(num2);
}
if (!wasDefined) {
pair.getGeo().setUndefined();
}
}
} catch (RuntimeException e) {
minMaxList.clear();
e.printStackTrace();
errors.add("Invalid min/max: " + e.toString());
}
minMaxList.clear();
}
// Michael Borcherds 2008-05-18
private void processDynamicColorList() {
try {
Iterator<GeoExpPair> it = dynamicColorList.iterator();
AlgebraProcessor algProc = getAlgProcessor();
while (it.hasNext()) {
GeoExpPair pair = it.next();
pair.getGeo()
.setColorFunction(algProc.evaluateToList(pair.exp));
}
} catch (RuntimeException e) {
dynamicColorList.clear();
e.printStackTrace();
errors.add("Invalid dynamic color: " + e.toString());
}
dynamicColorList.clear();
}
/**
* @param attrs
* attributes
* @return success
*/
protected boolean handleEigenvectors(LinkedHashMap<String, String> attrs) {
if (!(geo.isGeoConic())) {
Log.error(
"wrong element type for <eigenvectors>: " + geo.getClass());
return false;
}
try {
GeoConicND conic = (GeoConicND) geo;
// set eigenvectors, but don't classify conic now
// classifyConic() will be called in handleMatrix() by
// conic.setMatrix()
conic.setEigenvectors(StringUtil.parseDouble(attrs.get("x0")),
StringUtil.parseDouble(attrs.get("y0")),
StringUtil.parseDouble(attrs.get("z0")),
StringUtil.parseDouble(attrs.get("x1")),
StringUtil.parseDouble(attrs.get("y1")),
StringUtil.parseDouble(attrs.get("z1")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleMatrix(LinkedHashMap<String, String> attrs) {
if (!geo.isGeoConic() && !geo.isGeoQuadric()) {
Log.error("wrong element type for <matrix>: " + geo.getClass());
return false;
}
try {
handleMatrixConicOrQuadric(attrs);
return true;
} catch (Exception e) {
return false;
}
}
/**
* handler matrix for a conic or a quadric
*
* @param attrs
* attributes
* @throws Exception
* exception
*/
protected void handleMatrixConicOrQuadric(
LinkedHashMap<String, String> attrs) throws Exception {
if (geo.isGeoConic() && geo.getDefinition() == null) {
GeoConicND conic = (GeoConicND) geo;
// set matrix and classify conic now
// <eigenvectors> should have been set earlier
double[] matrix = { StringUtil.parseDouble(attrs.get("A0")),
StringUtil.parseDouble(attrs.get("A1")),
StringUtil.parseDouble(attrs.get("A2")),
StringUtil.parseDouble(attrs.get("A3")),
StringUtil.parseDouble(attrs.get("A4")),
StringUtil.parseDouble(attrs.get("A5")) };
conic.setMatrix(matrix);
}
}
private boolean handleLabelOffset(LinkedHashMap<String, String> attrs) {
try {
geo.labelOffsetX = Integer.parseInt(attrs.get("x"));
geo.labelOffsetY = Integer.parseInt(attrs.get("y"));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleLabelMode(LinkedHashMap<String, String> attrs) {
try {
geo.setLabelMode(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleTooltipMode(LinkedHashMap<String, String> attrs) {
try {
geo.setTooltipMode(Integer.parseInt(attrs.get("val")));
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleCoefficients(LinkedHashMap<String, String> attrs) {
// Application.debug(attrs.toString());
if (!(geo.isGeoImplicitCurve())) {
Log.warn(
"wrong element type for <coefficients>: " + geo.getClass());
return false;
}
try {
String rep = attrs.get("rep");
if (rep == null) {
return false;
}
if (attrs.get("rep").equals("array")) {
String data = attrs.get("data");
if (data == null) {
return false;
}
ArrayList<ArrayList<Double>> collect = new ArrayList<ArrayList<Double>>();
ArrayList<Double> newRow = new ArrayList<Double>();
int start = 0;
for (int c = 1; c < data.length(); c++) {
switch (data.charAt(c)) {
default:
// do nothing
break;
case '[':
if (newRow.size() > 0) {
return false;
}
start = c + 1;
break;
case ']':
newRow.add(StringUtil
.parseDouble(data.substring(start, c)));
start = c + 1;
collect.add(newRow);
newRow = new ArrayList<Double>();
c++; // jump over ','
break;
case ',':
newRow.add(StringUtil
.parseDouble(data.substring(start, c)));
start = c + 1;
}
}
double[][] coeff = new double[collect.size()][];
for (int i = 0; i < collect.size(); i++) {
ArrayList<Double> row = collect.get(i);
coeff[i] = new double[row.size()];
for (int j = 0; j < row.size(); j++) {
coeff[i][j] = row.get(j);
}
}
ExpressionNode def = geo.getDefinition();
/*
* Only overwrite coeff from XML when we don't have definition
* (setting coeffs explicitly kills factorization)
*/
if (def == null) {
((GeoImplicit) geo).setCoeff(coeff);
}
// geo.setDefinition(def);
return true;
}
} catch (RuntimeException e) {
return false;
}
return false;
}
private boolean handleUserInput(LinkedHashMap<String, String> attrs) {
// Application.debug(attrs.toString());
if (!(geo instanceof GeoImplicit)) {
Log.warn("wrong element type for <userinput>: " + geo.getClass());
return false;
}
try {
boolean valid = !"false".equals(attrs.get("valid"));
if (geo.isIndependent() && valid) {
String value = attrs.get("value");
if (value != null) {
ValidExpression ve = parser.parseGeoGebraExpression(value);
geo.setDefinition(ve.wrap());
if (ve.unwrap() instanceof Equation) {
((GeoImplicit) geo).fromEquation((Equation) ve.unwrap(),
null);
}
}
}
if (attrs.get("show") != null && attrs.get("show").equals("true")
&& valid) {
((GeoImplicit) geo).setInputForm();
} else {
((GeoImplicit) geo).setExtendedForm();
}
return true;
} catch (Exception e) {
Log.debug(e.getMessage());
return false;
}
}
// ====================================
// <command>
// ====================================
// called when <command> is encountered
// e.g. for <command name="Intersect">
private Command getCommand(LinkedHashMap<String, String> attrs) {
Command command = null;
String name = attrs.get("name");
String type = attrs.get("type");
if (type != null) {
cons.setOutputGeo(type);
}
String var = attrs.get("var");
if (var != null) {
Log.debug("reading var");
cons.registerFunctionVariable(var);
}
// Application.debug(name);
if (name != null) {
command = new Command(kernel, name, false); // do not translate name
} else {
errors.add("name missing in <command>");
}
return command;
}
private void startCommandElement(String eName,
LinkedHashMap<String, String> attrs) {
boolean ok = true;
if ("input".equals(eName)) {
ok = handleCmdInput(attrs);
} else if ("output".equals(eName)) {
ok = handleCmdOutput(attrs);
} else if ("outputSizes".equals(eName)) {
ok = handleCmdOutputSizes(attrs);
} else if ("casMap".equals(eName)) {
casMap = new TreeMap<String, String>();
constMode = MODE_CAS_MAP;
casMapParent = MODE_CONST_COMMAND;
ok = true;
} else {
Log.error("unknown tag in <command>: " + eName);
}
if (!ok) {
Log.error("error in <command>: " + eName);
}
}
private boolean handleCmdInput(LinkedHashMap<String, String> attrs) {
GeoElement geo1;
ExpressionNode en;
String arg = null;
if (cmd == null) {
errors.add("No command set for input");
return false;
}
// Collection<String> values = attrs.values();
// TODO: it doesn't work with GWT. why?
// Iterator<String> it = values.iterator();
// while (it.hasNext()) {
ArrayList<String> keys = new ArrayList<String>(attrs.keySet());
for (String key : keys) {
// parse argument expressions
try {
// arg = it.next();
arg = attrs.get(key);
// for downward compatibility: lookup label first
// as this could be some weird name that can't be parsed
// e.g. "1/2_{a,b}" could be a label name
// we don't want to override local variables with this fix,
// therefore we
// make exception for Sequence and CurveCartesian
if (cmd.getName().equals("Sequence")
|| cmd.getName().equals("CurveCartesian")
|| cmd.getName().equals("Surface")) {
geo1 = null;
} else {
geo1 = kernel.lookupLabel(arg);
}
// Application.debug("input : "+geo.getLabel());
// arg is a label and does not conatin $ signs (e.g. $A1 in
// spreadsheet)
if (geo1 != null && arg.indexOf('$') < 0) {
en = new ExpressionNode(kernel, geo1);
} else {
// parse argument expressions
en = parser.parseCmdExpression(arg);
}
cmd.addArgument(en);
} catch (Exception e) {
e.printStackTrace();
errors.add("unknown command input: " + arg);
} catch (Error e) {
e.printStackTrace();
errors.add("unknown command input: " + arg);
}
}
return true;
}
private boolean handleCmdOutput(LinkedHashMap<String, String> attrs) {
try {
// set labels for command processing
String label;
int countLabels = 0;
/*
* TODO Doesn't work with GWT. why? Collection<String> values =
* attrs.values(); Iterator<String> it = values.iterator(); while
* (it.hasNext()) { label = it.next();
*/
ArrayList<String> attrKeys = new ArrayList<String>(attrs.keySet());
for (String key : attrKeys) {
label = attrs.get(key);
if ("".equals(label)) {
label = null;
} else {
countLabels++;
}
cmd.addLabel(label);
}
// it is possible that we get a command that has been saved
// where NONE of its output objects had a label
// (e.g. intersection that never produced any points).
// Such a command should not be processed as it might
// use up labels that are needed later on.
// For example, since v3.0 every intersection command shows
// at least one labeled (and possibly undefined) point
// whereas in v2.7 the label was not set before an intersection
// point became defined for the first time.
// THUS: let's not process commands with no labels for their output
if (countLabels == 0) {
return true;
}
// process the command
cmdOutput = getAlgProcessor().processCommand(cmd,
new EvalInfo(true, casMap));
cons.registerFunctionVariable(null);
String cmdName = cmd.getName();
if (cmdOutput == null) {
errors.add("processing of command: " + cmd);
return false;
}
cmd = null;
// ensure that labels are set for invisible objects too
if (attrs.size() != cmdOutput.length) {
Log.debug(
"error in <output>: wrong number of labels for command "
+ cmdName);
Log.error(" cmdOutput.length = " + cmdOutput.length
+ ", labels = " + attrs.size());
return false;
}
// enforce setting of labels
// (important for invisible objects like intersection points)
// it = values.iterator();
int i = 0;
/*
* while (it.hasNext()) { label = it.next();
*/
for (String key : attrKeys) {
label = attrs.get(key);
if ("".equals(label)) {
label = null;
}
if (label != null && cmdOutput[i] != null) {
cmdOutput[i].setLoadedLabel(label);
}
i++;
}
return true;
} catch (MyError e) {
errors.add("processing of command: " + cmd);
e.printStackTrace();
return false;
} catch (RuntimeException e) {
e.printStackTrace();
errors.add("processing of command: " + cmd);
return false;
}
}
/**
* handle command output sizes (used only for some algos that have multiple
* types for output
*
* @param attrs
* @return true if proceeded
*/
private boolean handleCmdOutputSizes(LinkedHashMap<String, String> attrs) {
try {
String[] vals = attrs.get("val").split(",");
int[] sizes = new int[vals.length];
for (int i = 0; i < vals.length; i++) {
sizes[i] = Integer.parseInt(vals[i]);
}
cmd.setOutputSizes(sizes);
return true;
} catch (MyError e) {
errors.add("wrong command size for " + cmd);
} catch (RuntimeException e) {
errors.add("wrong command size for " + cmd);
}
return false;
}
/**
* Reads all attributes into a String array.
*
* @param attrs
* @return
*/
private static String[] getAttributeStrings(
LinkedHashMap<String, String> attrs) {
Collection<String> values = attrs.values();
Iterator<String> it = values.iterator();
String[] ret = new String[values.size()];
int i = 0;
while (it.hasNext()) {
ret[i] = it.next();
i++;
}
return ret;
}
// ====================================
// <expression>
// ====================================
private void startExpressionElement(LinkedHashMap<String, String> attrs) {
String label = attrs.get("label");
// ignore twinGeo expressions coming from CAS cells
// e.g. the GeoCasCell f(x) := x^2 automatically creates a twinGeo f
// where we don't want the expression of f to be processed again
GeoElement geo1 = kernel.lookupLabel(label);
if (geo1 != null && geo1.getCorrespondingCasCell() != null) {
return;
}
String exp = attrs.get("exp");
if (exp == null) {
errors.add("exp missing in <expression>");
return;
}
// type may be vector or point, this is important to distinguish between
// them
String type = attrs.get("type");
// parse expression and process it
try {
ValidExpression ve = parser.parseGeoGebraExpression(exp);
if (label != null) {
if ("X".equals(ve.getLabel())
&& cons.getRegisteredFunctionVariable() == null) {
ve = new Equation(kernel, new Variable(kernel, "X"), ve);
}
ve.setLabel(label);
}
// enforce point or vector or line or plane type if it was given in
// attribute type
if (type != null) {
if ("point".equals(type) && ve instanceof ExpressionNode) {
((ExpressionNode) ve).setForcePoint();
} else if ("vector".equals(type)
&& ve instanceof ExpressionNode) {
((ExpressionNode) ve).setForceVector();
// we must check that we have Equation here as xAxis
// has also type "line" but is parsed as ExpressionNode
} else if (ve instanceof Equation) {
if ("line".equals(type)) {
((Equation) ve).setForceLine();
} else if ("plane".equals(type)) {
((Equation) ve).setForcePlane();
} else if ("conic".equals(type)) {
((Equation) ve).setForceConic();
} else if ("quadric".equals(type)) {
((Equation) ve).setForceQuadric();
} else if ("implicitpoly".equals(type)) {
((Equation) ve).setForceImplicitPoly();
} else if ("implicitPoly".equals(type)) {
((Equation) ve).setForceImplicitPoly();
} else if ("implicitsurface".equals(type)) {
((Equation) ve).setForceSurface();
}
}
}
// Application.debug(""+getAlgProcessor());
GeoElementND[] result = getAlgProcessor()
.processValidExpression(ve);
cons.registerFunctionVariable(null);
// ensure that labels are set for invisible objects too
if (result != null && label != null && result.length == 1) {
result[0].setLoadedLabel(label);
} else {
Log.error(
"error in <expression>: " + exp + ", label: " + label);
}
} catch (Exception e) {
String msg = "error in <expression>: label=" + label + ", exp= "
+ exp;
Log.error(msg);
e.printStackTrace();
errors.add(msg);
} catch (Error e) {
String msg = "error in <expression>: label = " + label + ", exp = "
+ exp;
Log.error(msg);
e.printStackTrace();
errors.add(msg);
}
}
private AlgebraProcessor getAlgProcessor() {
return kernel.getAlgebraProcessor();
}
private boolean handleAlgebraViewMode(LinkedHashMap<String, String> attrs) {
try {
int val = Integer.parseInt(attrs.get("val"));
app.getSettings().getAlgebra().setTreeMode(val);
app.getSettings().getAlgebra().setModeChanged(true);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleAlgebraViewShowAuxiliaryObjects(
LinkedHashMap<String, String> attrs) {
try {
boolean b = parseBoolean(attrs.get("show"));
app.getSettings().getAlgebra().setShowAuxiliaryObjects(b);
return true;
} catch (RuntimeException e) {
return false;
}
}
private boolean handleAlgebraViewCollapsedNodes(
LinkedHashMap<String, String> attrs) {
try {
String[] strings = attrs.get("val").split(",");
int[] vals = new int[strings.length];
for (int i = 0; i < strings.length; i++) {
vals[i] = Integer.parseInt(strings[i]);
}
app.getSettings().getAlgebra().setCollapsedNodes(vals);
return true;
} catch (RuntimeException e) {
return false;
}
}
// ====================================
// UTILS
// ====================================
/**
* Parse string to boolean
*
* @param str
* input string
* @return true for "true", false otherwise
*/
protected boolean parseBoolean(String str) {
return "true".equals(str);
}
/**
* Parse string to boolean
*
* @param str
* input string
* @return false for "fale", true otherwise
*/
protected boolean parseBooleanRev(String str) {
return !"false".equals(str);
}
}