package org.geogebra.common.main; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; import java.util.Random; import java.util.Vector; import org.geogebra.common.GeoGebraConstants; import org.geogebra.common.GeoGebraConstants.Versions; import org.geogebra.common.awt.GBufferedImage; import org.geogebra.common.awt.GDimension; import org.geogebra.common.awt.GFont; import org.geogebra.common.awt.MyImage; import org.geogebra.common.cas.singularws.SingularWebService; import org.geogebra.common.euclidian.DrawEquation; import org.geogebra.common.euclidian.Drawable; import org.geogebra.common.euclidian.EuclidianConstants; import org.geogebra.common.euclidian.EuclidianController; import org.geogebra.common.euclidian.EuclidianView; import org.geogebra.common.euclidian.draw.DrawDropDownList; import org.geogebra.common.euclidian.event.AbstractEvent; import org.geogebra.common.euclidian.event.PointerEventType; import org.geogebra.common.euclidian.smallscreen.AdjustScreen; import org.geogebra.common.euclidian.smallscreen.AdjustViews; import org.geogebra.common.euclidian3D.EuclidianView3DInterface; import org.geogebra.common.euclidian3D.Input3DConstants; import org.geogebra.common.export.pstricks.GeoGebraToAsymptote; import org.geogebra.common.export.pstricks.GeoGebraToPgf; import org.geogebra.common.export.pstricks.GeoGebraToPstricks; import org.geogebra.common.factories.AwtFactory; import org.geogebra.common.factories.CASFactory; import org.geogebra.common.factories.Factory; import org.geogebra.common.geogebra3D.util.CopyPaste3D; import org.geogebra.common.gui.menubar.MenuFactory; import org.geogebra.common.gui.menubar.OptionsMenu; import org.geogebra.common.gui.view.algebra.AlgebraView; import org.geogebra.common.gui.view.properties.PropertiesView; import org.geogebra.common.io.MyXMLio; import org.geogebra.common.io.layout.Perspective; import org.geogebra.common.javax.swing.GImageIcon; import org.geogebra.common.kernel.AnimationManager; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.ConstructionDefaults; import org.geogebra.common.kernel.GeoGebraCasInterface; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.Macro; import org.geogebra.common.kernel.ModeSetter; import org.geogebra.common.kernel.Relation; import org.geogebra.common.kernel.UndoManager; import org.geogebra.common.kernel.View; import org.geogebra.common.kernel.commands.CommandDispatcher; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.commands.CommandsConstants; import org.geogebra.common.kernel.geos.GeoBoolean; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoElementGraphicsAdapter; 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.GeoNumeric; import org.geogebra.common.kernel.kernelND.GeoElementND; import org.geogebra.common.kernel.parser.cashandlers.ParserFunctions; 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.EuclidianSettings; import org.geogebra.common.main.settings.Settings; import org.geogebra.common.move.ggtapi.operations.LogInOperation; import org.geogebra.common.plugin.EuclidianStyleConstants; import org.geogebra.common.plugin.Event; import org.geogebra.common.plugin.EventDispatcher; import org.geogebra.common.plugin.EventType; import org.geogebra.common.plugin.GeoScriptRunner; import org.geogebra.common.plugin.GgbAPI; import org.geogebra.common.plugin.ScriptManager; import org.geogebra.common.plugin.ScriptType; import org.geogebra.common.plugin.SensorLogger; import org.geogebra.common.plugin.script.GgbScript; import org.geogebra.common.plugin.script.Script; import org.geogebra.common.sound.SoundManager; import org.geogebra.common.util.CopyPaste; import org.geogebra.common.util.GTimer; import org.geogebra.common.util.GTimerListener; import org.geogebra.common.util.ImageManager; import org.geogebra.common.util.LowerCaseDictionary; import org.geogebra.common.util.NormalizerMinimal; import org.geogebra.common.util.StringUtil; import org.geogebra.common.util.Util; import org.geogebra.common.util.debug.Log; import org.geogebra.common.util.lang.Unicode; /** * Represents an application window, gives access to views and system stuff */ @SuppressWarnings("javadoc") public abstract class App implements UpdateSelection { /** Url for wiki article about functions */ public static final String WIKI_OPERATORS = "Predefined Functions and Operators"; /** Url for main page of manual */ public static final String WIKI_MANUAL = "Manual"; /** Url for wiki article about CAS */ public static final String WIKI_CAS_VIEW = "CAS_View"; /** Url for wiki tutorials */ public static final String WIKI_TUTORIAL = "Tutorial:Main Page"; /** Url for Intel RealSense tutorials */ public static final String REALSENSE_TUTORIAL = "https://www.geogebra.org/b/OaGmb7LE"; /** * Url for wiki article about exporting to HTML changed to GeoGebra * Materials upload from ggb44 */ public static final String WIKI_EXPORT_WORKSHEET = "Upload_to_GeoGebra_Materials"; /** * Url for wiki article about advanced features (layers, cond. visibility * etc.) */ public static final String WIKI_ADVANCED = "Advanced Features"; /** Url for wiki article about functions */ public static final String WIKI_TEXT_TOOL = "Text Tool"; /** id for dummy view */ public static final int VIEW_NONE = 0; /** id for euclidian view */ public static final int VIEW_EUCLIDIAN = 1; /** id for algebra view */ public static final int VIEW_ALGEBRA = 2; /** id for Spreadsheet view */ public static final int VIEW_SPREADSHEET = 4; /** id for CAS view */ public static final int VIEW_CAS = 8; /** id for second euclidian view */ public static final int VIEW_EUCLIDIAN2 = 16; /** id for construction protocol view */ public static final int VIEW_CONSTRUCTION_PROTOCOL = 32; /** id for probability calculator view */ public static final int VIEW_PROBABILITY_CALCULATOR = 64; /** * id for data analysis view, ie multi/single/two variable analysisis tools */ public static final int VIEW_DATA_ANALYSIS = 70; /** id for function inspector */ public static final int VIEW_FUNCTION_INSPECTOR = 128; /** id for 3D view */ public static final int VIEW_EUCLIDIAN3D = 512; /** id for 2nd 3D view */ public static final int VIEW_EUCLIDIAN3D_2 = 513; /** let us break the pattern */ public static final int VIEW_EVENT_DISPATCHER = 42; /** * id for view created from plane; also 1025 to 2047 might be used for this * purpose */ public static final int VIEW_EUCLIDIAN_FOR_PLANE_START = 1024; /** maximal ID of view for plane */ public static final int VIEW_EUCLIDIAN_FOR_PLANE_END = 2047; /** * id for plot panels (small EVs eg in regression analysis tool) */ public static final int VIEW_PLOT_PANEL = 2048; /** * id for text preview in text tool */ public static final int VIEW_TEXT_PREVIEW = 4096; /** * id for properties view */ public static final int VIEW_PROPERTIES = 4097; // please let 1024 to 2047 empty /** id for spreadsheet table model */ public static final int VIEW_TABLE_MODEL = 9000; /** data collection view (web only) */ public static final int VIEW_DATA_COLLECTION = 43; public static final int DEFAULT_THRESHOLD = 3; /** * minimal font size */ public static final int MIN_FONT_SIZE = 10; /** * initial number of columns for spreadsheet */ public static final int SPREADSHEET_INI_COLS = 10; /** * initial number of rows for spreadsheet */ public static final int SPREADSHEET_INI_ROWS = 100; // used by PropertyDialogGeoElement and MenuBarImpl // for the Rounding Menus /** * Rounding menu options (not internationalized) */ final private static String[] strDecimalSpacesAC = { "0 decimals", "1 decimals", "2 decimals", "3 decimals", "4 decimals", "5 decimals", "10 decimals", "15 decimals", "", "3 figures", "5 figures", "10 figures", "15 figures" }; public static String[] getStrDecimalSpacesAC() { return strDecimalSpacesAC; } /** Singular web service (CAS) */ private SingularWebService singularWS; private static String CASVersionString = ""; private static boolean CASViewEnabled = true; private static boolean _3DViewEnabled = true; /** * whether axes should be visible when EV is created first element of this * array is for x-axis, second for y-axis */ protected final boolean[] showAxes = { true, true }; /** whether axes should be logarithmic when EV is created */ protected final boolean[] logAxes = { false, false }; /** * Whether we are running applet in frame. Not possible with 4.2+ (we need * this to hide reset icon from EV) */ public boolean runningInFrame = false; public Vector<GeoImage> images = new Vector<GeoImage>(); /** * Whether AV should show auxiliary objects stored here rather than in * algebra view so that it can be set without creating an AV (compatibility * with 3.2) */ public boolean showAuxiliaryObjects = false; /** flag to test whether to draw Equations full resolution */ public ExportType exportType = ExportType.NONE; /** * right angle style * * @see EuclidianStyleConstants#RIGHT_ANGLE_STYLE_SQUARE * @see EuclidianStyleConstants#RIGHT_ANGLE_STYLE_DOT * @see EuclidianStyleConstants#RIGHT_ANGLE_STYLE_L * @see EuclidianStyleConstants#RIGHT_ANGLE_STYLE_NONE */ public int rightAngleStyle = EuclidianStyleConstants.RIGHT_ANGLE_STYLE_SQUARE; private AlgoKimberlingWeightsInterface kimberlingw = null; private AlgoCubicSwitchInterface cubicw = null; /** * whether transparent cursor should be used while dragging */ private boolean useTransparentCursorWhenDragging = false; /** * Script manager */ protected ScriptManager scriptManager = null; /** whether current construction was saved after last changes */ protected boolean isSaved = true; /** * object is hit if mouse is within this many pixels (more for points, see * geogebra.common.euclidian.DrawPoint) */ protected int capturingThreshold = DEFAULT_THRESHOLD; /** on touch devices we want larger threshold for point hit testing */ protected int capturingThresholdTouch = 3 * DEFAULT_THRESHOLD; /* Font settings */ /** * where to show the inputBar (respective inputBox) */ protected InputPosition showInputTop = InputPosition.algebraView; /** * Whether input bar should be visible */ protected boolean showAlgebraInput = true; // For eg Hebrew and Arabic. /** * Whether toolbar help should appear */ protected boolean showToolBarHelp = false; /** * Toolbar position */ protected int toolbarPosition = 1; /** * Whether input help toggle button should be visible */ protected boolean showInputHelpToggle = true; /** * whether righ click is enabled */ protected boolean rightClickEnabled = true; /** * whether righ click is enabled for Algebra View */ protected boolean rightClickEnabledForAV = true; /** * User Sign in handling */ protected LogInOperation loginOperation = null; /** XML input / output handler */ private MyXMLio myXMLio; /** gui / menu fontsize (-1 = use appFontSize) */ protected int guiFontSize = -1; /** kernel */ protected Kernel kernel; /** whether points can be created by other tools than point tool */ protected boolean isOnTheFlyPointCreationActive = true; /** Settings object */ protected Settings settings; /** Selections in this app */ protected SelectionManager selection; /** whether grid should be visible when EV is created */ protected boolean showGrid = false; /** * this flag is true during initialization phase (until GUI is built and * command line args handled, incl. file loading) or when we are opening a * file */ protected boolean initing = false; /** Euclidian view */ protected EuclidianView euclidianView; /** Euclidian view's controller */ protected EuclidianController euclidianController; /** selection listener */ protected GeoElementSelectionListener currentSelectionListener; /** * whether menubar should be visible */ protected boolean showMenuBar = true; protected String uniqueId; protected ArrayList<Perspective> tmpPerspectives = new ArrayList<Perspective>(); /** * whether toolbar should be visible */ protected boolean showToolBar = true; /** * whether shift, drag and zoom features are enabled */ protected boolean shiftDragZoomEnabled = true; protected int appletWidth = 0; protected int appletHeight = 0; protected boolean useFullGui = false; protected int appCanvasHeight; protected int appCanvasWidth; protected boolean needsSpreadsheetTableModel = false; protected HashMap<Integer, Boolean> showConstProtNavigationNeedsUpdate = null; protected HashMap<Integer, Boolean> showConsProtNavigation = null; protected AppCompanion companion; protected boolean prerelease; protected boolean canary; private boolean showResetIcon = false; private ParserFunctions pf; private SpreadsheetTraceManager traceManager; private ExamEnvironment exam; // currently used application fonts private int appFontSize = 16; // moved to Application from EuclidianView as the same value is used across // multiple EVs private int maxLayerUsed = 0; /** * size of checkboxes, default in GeoGebraPreferencesXML.java * checkboxSize="26" */ private int booleanSize = EuclidianConstants.DEFAULT_CHECKBOX_SIZE; private boolean labelDragsEnabled = true; private boolean undoRedoEnabled = true; // command dictionary private LowerCaseDictionary commandDict; private LowerCaseDictionary commandDictCAS; // array of dictionaries corresponding to the sub command tables private LowerCaseDictionary[] subCommandDict; private String scriptingLanguage; /** * flag for current state */ private StoreUndoInfoForSetCoordSystem storeUndoInfoForSetCoordSystem = StoreUndoInfoForSetCoordSystem.NONE; private boolean blockUpdateScripts = false; private boolean useBrowserForJavaScript = true; private EventDispatcher eventDispatcher; private int[] versionArray = null; private List<SavedStateListener> savedListeners = new ArrayList<SavedStateListener>(); private Macro macro; private int labelingStyle = ConstructionDefaults.LABEL_VISIBLE_POINTS_ONLY; /** * says that a labeling style is selected in menu (i.e. all default geos use * the selected labeling style) */ private boolean labelingStyleSelected = true; private boolean scriptingDisabled = false; private double exportScale = 1; private PropertiesView propertiesView; private Random random = new Random(); private GeoScriptRunner geoScriptRunner; private GeoElement geoForCopyStyle; private OptionsMenu optionsMenu; private boolean isErrorDialogsActive = true; private ArrayList<OpenFileListener> openFileListener; // whether to allow perspective and login popups private boolean allowPopUps = false; private Versions version; // TODO: move following methods somewhere else private int tubeID = 0; /** * Please call setVersion right after this */ public App() { companion = newAppCompanion(); resetUniqueId(); } /** * constructor */ public App(Versions version) { this(); this.version = version; } /** * Changes version; should be called only once, right after the constructor * * @param version */ public void setVersion(Versions version) { this.version = version; } /** * @return CAS version */ public static final String getCASVersionString() { return CASVersionString; } /** * @param string * CAS version string */ public static final void setCASVersionString(String string) { CASVersionString = string; } /** * Initializes SingularWS */ public void initializeSingularWS() { singularWS = new SingularWebService(); singularWS.enable(); if (singularWS.isAvailable()) { Log.info("SingularWS is available at " + singularWS.getConnectionSite()); // debug(singularWS.directCommand("ring r=0,(x,y),dp;ideal // I=x^2,x;groebner(I);")); } else { Log.info("No SingularWS is available at " + singularWS.getConnectionSite() + " (yet)"); } } public SingularWebService getSingularWS() { return singularWS; } /* selection handling */ /** * @param version * string version, eg 4.9.38.0 * @return version as list of ints, eg [4,9,38,0] */ static final public int[] getSubValues(String version) { String[] values = version.split("\\."); int[] ret = new int[values.length]; for (int i = 0; i < values.length; i++) { ret[i] = Integer.parseInt(values[i]); } return ret; } /** * Disables CAS View. */ public static void disableCASView() { CASViewEnabled = false; } // Rounding Menus end /** * Disables 3D View. */ public static void disable3DView() { _3DViewEnabled = false; } /** * Gets max scale based on EV size; scale down if EV too big to avoid * clipboard errors * * @param ev * view * @return maximum scale for clipboard images; default 2 */ public static double getMaxScaleForClipBoard(EuclidianView ev) { double size = ev.getExportWidth() * ev.getExportHeight(); // Windows XP clipboard has trouble with images larger than this // at double scale (with scale = 2d) if (size > 500000) { return 2.0 * Math.sqrt(500000 / size); } return 2d; } /** * * @param id * view id * @return true if id is a 3D view id */ public static final boolean isView3D(int id) { if (id == App.VIEW_EUCLIDIAN3D) { return true; } if (id == App.VIEW_EUCLIDIAN3D_2) { return true; } return false; } /** * @return global checkbox size 13 or 26 (all checkboxes, both views) */ public int getCheckboxSize() { return booleanSize; } /** * * set global checkbox size (all checkboxes, both views) * * @param b * new size for checkboxes (either 13 or 26) */ public void setCheckboxSize(int b) { booleanSize = (b == 13) ? 13 : 26; } /** * @param type * mouse or touch * @return capturing threshold */ public int getCapturingThreshold(PointerEventType type) { return type == PointerEventType.TOUCH ? this.capturingThresholdTouch : this.capturingThreshold; } /** * @param i * capturing threshold */ public void setCapturingThreshold(int i) { this.capturingThreshold = i; this.capturingThresholdTouch = 3 * i; } /** * We need this method so that we can override it using more powerful * normalizer * * @return new lowercase dictionary */ public LowerCaseDictionary newLowerCaseDictionary() { return new LowerCaseDictionary(new NormalizerMinimal()); } /** * Fills CAS command dictionary and translation table. Must be called before * we start using CAS view. */ public void fillCasCommandDict() { // this method might get called during initialization, when we're not // yet // ready to fill the casCommandDict. In that case, we will fill the // dict during fillCommandDict :) if (!getLocalization().isCommandChanged() && ((commandDictCAS != null) || getLocalization().isCommandNull())) { return; } GeoGebraCasInterface cas = kernel.getGeoGebraCAS(); if (cas == null || subCommandDict == null) { return; } getLocalization().setCommandChanged(false); commandDictCAS = newLowerCaseDictionary(); subCommandDict[CommandsConstants.TABLE_CAS].clear(); // get all commands from the commandDict and write them to the // commandDictCAS // the keySet contains all commands of the dictionary; see // LowerCaseDictionary.addEntry(String s) for more Collection<String> commandDictContent = commandDict.values(); // write them to the commandDictCAS for (String cmd : commandDictContent) { commandDictCAS.addEntry(cmd); } // iterate through all available CAS commands, add them (translated if // available, otherwise untranslated) for (String cmd : cas.getAvailableCommandNames()) { try { String local = getLocalization().getCommand(cmd); putInTranslateCommandTable(Commands.valueOf(cmd), local); if (local != null) { commandDictCAS.addEntry(local); subCommandDict[CommandsConstants.TABLE_CAS].addEntry(local); } else { commandDictCAS.addEntry(cmd); subCommandDict[CommandsConstants.TABLE_CAS].addEntry(cmd); } } catch (Exception mre) { commandDictCAS.addEntry(cmd); subCommandDict[CommandsConstants.TABLE_CAS].addEntry(cmd); } } } /** * @return command dictionary for CAS */ public final LowerCaseDictionary getCommandDictionaryCAS() { fillCommandDict(); fillCasCommandDict(); return commandDictCAS; } /** * Returns an array of command dictionaries corresponding to the categorized * sub command sets created in CommandDispatcher. * * @return command dictionaries corresponding to the categories */ public final LowerCaseDictionary[] getSubCommandDictionary() { if (subCommandDict == null) { initTranslatedCommands(); } if (getLocalization().isCommandChanged()) { updateCommandDictionary(); } return subCommandDict; } /** * Initializes the translated command names for this application. Note: this * will load the properties files first. */ final public void initTranslatedCommands() { if (getLocalization().isCommandNull() || subCommandDict == null) { getLocalization().initCommand(); fillCommandDict(); kernel.updateLocalAxesNames(); } } /** * @return command dictionary */ public final LowerCaseDictionary getCommandDictionary() { fillCommandDict(); return commandDict; } /** * Fill command dictionary and translation table. Must be called before we * start using Input Bar. */ protected void fillCommandDict() { getLocalization().initCommand(); if (!getLocalization().isCommandChanged()) { return; } // translation table for all command names in command.properties getLocalization().initTranslateCommand(); // command dictionary for all public command names available in // GeoGebra's input field // removed check for null: commandDict.clear() removes keys, but they // are still available with commandDict.getIterator() // so change English -> French -> English doesn't work in the input bar // see AutoCompleteTextfield.lookup() // if (commandDict == null) commandDict = newLowerCaseDictionary(); // else commandDict.clear(); // ===================================== // init sub command dictionaries if (subCommandDict == null) { subCommandDict = new LowerCaseDictionary[CommandDispatcher.tableCount]; for (int i = 0; i < subCommandDict.length; i++) { subCommandDict[i] = newLowerCaseDictionary(); } } for (int i = 0; i < subCommandDict.length; i++) { subCommandDict[i].clear(); // ===================================== } HashMap<String, String> translateCommandTable = getLocalization() .getTranslateCommandTable(); for (Commands comm : Commands.values()) { String internal = comm.name(); if (!companion.tableVisible(comm.getTable()) || !kernel.getAlgebraProcessor().isCommandsEnabled()) { if (comm.getTable() == CommandsConstants.TABLE_ENGLISH) { putInTranslateCommandTable(comm, null); } continue; } // Log.debug(internal); String local = getLocalization().getCommand(internal); putInTranslateCommandTable(comm, local); if (local != null) { local = local.trim(); // case is ignored in translating local command names to // internal names! translateCommandTable.put(StringUtil.toLowerCase(local), internal); commandDict.addEntry(local); // add public commands to the sub-command dictionaries subCommandDict[comm.getTable()].addEntry(local); } } getParserFunctions().updateLocale(getLocalization()); // get CAS Commands if (kernel.isGeoGebraCASready()) { fillCasCommandDict(); } addMacroCommands(); getLocalization().setCommandChanged(false); } private void putInTranslateCommandTable(Commands comm, String local) { String internal = comm.name(); // Check that we don't overwrite local with English HashMap<String, String> translateCommandTable = getLocalization() .getTranslateCommandTable(); if (!translateCommandTable .containsKey(StringUtil.toLowerCase(internal))) { translateCommandTable.put(StringUtil.toLowerCase(internal), Commands.englishToInternal(comm).name()); } if (comm.getTable() == CommandsConstants.TABLE_ENGLISH) { return; } if (local != null) { translateCommandTable.put(StringUtil.toLowerCase(local), Commands.englishToInternal(comm).name()); } } /** * translate command name to internal name. Note: the case of localname is * NOT relevant * * @param command * local name * @return internal name */ public String getReverseCommand(String command) { // don't init command table on file loading if (kernel.isUsingInternalCommandNames()) { try { Commands.valueOf(command); return command; } catch (Exception e) { // not a valid command, fall through } } initTranslatedCommands(); return getLocalization().getReverseCommand(command); } /** * Updates command dictionary */ public void updateCommandDictionary() { // make sure all macro commands are in dictionary if (commandDict != null) { fillCommandDict(); } } /** * Adds macro commands to the dictionary */ protected void addMacroCommands() { if ((commandDict == null) || (kernel == null) || !kernel.hasMacros()) { return; } ArrayList<Macro> macros = kernel.getAllMacros(); for (int i = 0; i < macros.size(); i++) { String cmdName = macros.get(i).getCommandName(); if (!commandDict.containsValue(cmdName)) { commandDict.addEntry(cmdName); } } } /** * Remove macros from command dictionary */ public void removeMacroCommands() { if ((commandDict == null) || (kernel == null) || !kernel.hasMacros()) { return; } ArrayList<Macro> macros = kernel.getAllMacros(); for (int i = 0; i < macros.size(); i++) { String cmdName = macros.get(i).getCommandName(); commandDict.removeEntry(cmdName); } } public abstract boolean isApplet(); /** * Store current state of construction for undo/redo purposes */ public abstract void storeUndoInfo(); /** * Store current state of construction for undo/redo purposes, and state of * construction for mode starting (so undo cancels partial tool preview) */ public void storeUndoInfoAndStateForModeStarting() { storeUndoInfoAndStateForModeStarting(true); } final public void storeUndoInfoAndStateForModeStarting( boolean storeForMode) { if (isUndoActive()) { if (storeForMode) { kernel.storeUndoInfoAndStateForModeStarting(); } else { kernel.storeUndoInfo(); } setUnsaved(); } } /** * store undo info only if view coord system has changed */ public void storeUndoInfoIfSetCoordSystemOccured() { if (storeUndoInfoForSetCoordSystem == StoreUndoInfoForSetCoordSystem.SET_COORD_SYSTEM_OCCURED) { storeUndoInfo(); } storeUndoInfoForSetCoordSystem = StoreUndoInfoForSetCoordSystem.NONE; } /** * tells the application that a view coord system has changed */ public void setCoordSystemOccured() { if (storeUndoInfoForSetCoordSystem == StoreUndoInfoForSetCoordSystem.MAY_SET_COORD_SYSTEM) { storeUndoInfoForSetCoordSystem = StoreUndoInfoForSetCoordSystem.SET_COORD_SYSTEM_OCCURED; } } /** * tells the coord sys may be set */ public void maySetCoordSystem() { if (storeUndoInfoForSetCoordSystem == StoreUndoInfoForSetCoordSystem.NONE) { storeUndoInfoForSetCoordSystem = StoreUndoInfoForSetCoordSystem.MAY_SET_COORD_SYSTEM; } } public void setPropertiesOccured() { getKernel().getConstruction().getUndoManager().setPropertiesOccured(); } public void storeUndoInfoForProperties() { getKernel().getConstruction().getUndoManager().storeUndoInfoForProperties(isUndoActive()); } /** * @return true if we have access to complete gui (menubar, toolbar); false * for minimal applets (just one EV, no gui) */ public abstract boolean isUsingFullGui(); /** * * @param view * view ID * @return whether view with given ID is visible */ public abstract boolean showView(int view); public boolean letRename() { return true; } public boolean letDelete() { return true; } public boolean letRedefine() { return true; } /** * @return the blockUpdateScripts */ public boolean isBlockUpdateScripts() { return blockUpdateScripts; } /** * @param blockUpdateScripts * the blockUpdateScripts to set */ public void setBlockUpdateScripts(boolean blockUpdateScripts) { this.blockUpdateScripts = blockUpdateScripts; } /** * Translates localized command name into internal TODO check whether this * differs from translateCommand somehow and either document it or remove * this method * * @param cmd * localized command name * @return internal command name */ public String getInternalCommand(String cmd) { initTranslatedCommands(); String s; String cmdLower = StringUtil.toLowerCase(cmd); Commands[] values = Commands.values(); for (Commands c : values) { s = Commands.englishToInternal(c).name(); // make sure that when si[] is typed in script, it's changed to // Si[] etc if (StringUtil.toLowerCase(getLocalization().getCommand(s)) .equals(cmdLower)) { return s; } } return null; } /** * Show error dialog wiith given text * * @param s * error message */ public abstract void showError(String s); /** * Shows error dialog with a given text * * @param s */ protected abstract void showErrorDialog(String s); /** * @param useBrowserForJavaScript * desktop: determines whether Rhino will be used (false) or the * browser (true) web: determines whether JS input comes from the * html file (true) or from the ggb file (false) */ public void setUseBrowserForJavaScript(boolean useBrowserForJavaScript) { this.useBrowserForJavaScript = useBrowserForJavaScript; } /** * @return desktop: determines whether Rhino will be used (false) or the * browser (true) web: determines whether JS input comes from the * html file (true) or from the ggb file (false) */ public boolean useBrowserForJavaScript() { return useBrowserForJavaScript; } /** * @return script manager */ final public ScriptManager getScriptManager() { if (scriptManager == null) { scriptManager = newScriptManager(); } return scriptManager; } abstract protected ScriptManager newScriptManager(); /** * Get the event dispatcher, which dispatches events objects that manage * event driven scripts * * @return the app's event dispatcher */ public EventDispatcher getEventDispatcher() { if (eventDispatcher == null) { eventDispatcher = new EventDispatcher(this); } return eventDispatcher; } /** * @param ge * geo * @return trace-related XML elements */ final public String getTraceXML(GeoElement ge) { return getTraceManager().getTraceXML(ge); } /** * Start tracing geo to spreadsheet * * @param ge * geo */ public void traceToSpreadsheet(GeoElement ge) { getTraceManager().traceToSpreadsheet(ge); } /** * Reset tracing column for given geo * * @param ge * geo */ public void resetTraceColumn(GeoElement ge) { getTraceManager().setNeedsColumnReset(ge, true); } /** * Updates the counter of used layers * * @param layer * layer to which last element was added */ public void updateMaxLayerUsed(int layer) { int newLayer = layer; if (layer > EuclidianStyleConstants.MAX_LAYERS) { newLayer = EuclidianStyleConstants.MAX_LAYERS; } if (layer > maxLayerUsed) { maxLayerUsed = newLayer; } } /** * @return whether this is a 3D app or not */ public boolean is3D() { return false; } /** * @return last created GeoElement */ final public GeoElement getLastCreatedGeoElement() { return kernel.getConstruction().getLastGeoElement(); } /** * Deletes selected objects */ public void deleteSelectedObjects(boolean isCut) { if (letDelete()) { Object[] geos = selection.getSelectedGeos().toArray(); for (int i = 0; i < geos.length; i++) { GeoElement geo = (GeoElement) geos[i]; if (!geo.isProtected(EventType.REMOVE)) { if (isCut || geo.isShape()) { if (geo.getParentAlgorithm() != null) { for (GeoElement ge : geo .getParentAlgorithm().input) { ge.removeOrSetUndefinedIfHasFixedDescendent(); } } } geo.removeOrSetUndefinedIfHasFixedDescendent(); } } // also delete just created geos if possible ArrayList<GeoElement> geos2 = getActiveEuclidianView() .getEuclidianController().getJustCreatedGeos(); for (int j = 0; j < geos2.size(); j++) { GeoElement geo = geos2.get(j); if (!geo.isProtected(EventType.REMOVE)) { geo.removeOrSetUndefinedIfHasFixedDescendent(); } } getActiveEuclidianView().getEuclidianController() .clearJustCreatedGeos(); getActiveEuclidianView().getEuclidianController().clearSelections(); storeUndoInfoAndStateForModeStarting(); } } public ArrayList<GeoElement> getJustCreatedGeos() { return getActiveEuclidianView().getEuclidianController() .getJustCreatedGeos(); } /** * @return whether auxiliary objects are shown in AV */ public boolean showAuxiliaryObjects() { return showAuxiliaryObjects; } /** * Append XML describing the keyboard to given string builder * * @param sb * string builder */ public void getKeyboardXML(StringBuilder sb) { sb.append("<keyboard width=\""); sb.append(getSettings().getKeyboard().getKeyboardWidth()); sb.append("\" height=\""); sb.append(getSettings().getKeyboard().getKeyboardHeight()); sb.append("\" opacity=\""); sb.append(getSettings().getKeyboard().getKeyboardOpacity()); sb.append("\" language=\""); sb.append(getSettings().getKeyboard().getKeyboardLocale()); sb.append("\" show=\""); sb.append(getSettings().getKeyboard().isShowKeyboardOnStart()); sb.append("\"/>"); } /** * @return true if we have critically low free memory */ public abstract boolean freeMemoryIsCritical(); /** * @return Approximate amount of remaining memory in bytes */ public abstract long freeMemory(); /** * set right angle style * * @param style * style */ public void setRightAngleStyle(int style) { rightAngleStyle = style; } /** * @return the maximal currently used layer */ public int getMaxLayerUsed() { return maxLayerUsed; } /** * @param min * real world x min * @param max * real world x max * @return number of pixels in EV1 between given x coordinates */ public double countPixels(double min, double max) { EuclidianView ev = getEuclidianView1(); return ev.toScreenCoordXd(max) - ev.toScreenCoordXd(min); } /** * @return algebra view */ public abstract AlgebraView getAlgebraView(); /** * @return EV1 */ public EuclidianView getEuclidianView1() { Log.notice("AbstrEuclView"); return euclidianView; } /** * Resets the maximal used llayer to 0 */ public void resetMaxLayerUsed() { maxLayerUsed = 0; } /** * @return active euclidian view (may be EV, EV2 or 3D) */ public abstract EuclidianView getActiveEuclidianView(); /** * @return whether 3D view was initialized */ public boolean hasEuclidianView3D() { return false; } public boolean isEuclidianView3Dinited() { return false; } /** * @return 3D view */ public EuclidianView3DInterface getEuclidianView3D() { return null; } /** * @return whether EV2 was initialized */ public abstract boolean hasEuclidianView2EitherShowingOrNot(int idx); /** * @return whether EV2 is visible */ public abstract boolean isShowingEuclidianView2(int idx); /** * @return image manager */ public abstract ImageManager getImageManager(); /** * @return gui manager (it's null in minimal applets) */ public abstract GuiManagerInterface getGuiManager(); /** * @return dialog manager */ public abstract DialogManager getDialogManager(); /** * Initializes GUI manager */ protected abstract void initGuiManager(); /** * Whether we are running on Mac * * @return whether we are running on Mac */ public boolean isMacOS() { return false; } /** * Whether we are running on Windows * * @return whether we are running on Windows */ public boolean isWindows() { return false; } /** * Whether we are running on Windows Vista or later * * @return whether we are running on Windows Vista or later */ public boolean isWindowsVistaOrLater() { return false; } /** * @return the scriptingLanguage */ public String getScriptingLanguage() { // in some files we stored language="null" accidentally if ("null".equals(scriptingLanguage)) { scriptingLanguage = null; } return scriptingLanguage; } /** * @param scriptingLanguage * the scriptingLanguage to set */ public void setScriptingLanguage(String scriptingLanguage) { this.scriptingLanguage = scriptingLanguage; } /** * Runs JavaScript * * @param app * application * @param script * JS method name * @param arg * arguments * @throws Exception * when script contains errors */ public abstract void evalJavaScript(App app, String script, String arg) throws Exception; /** * @param v * version parts * @return whether given version is newer than this code */ public boolean fileVersionBefore(int[] v) { if (this.versionArray == null) { return true; } int length = versionArray.length; if (v.length < length) { length = v.length; } for (int i = 0; i < length; i++) { if (versionArray[i] < v[i]) { return true; } else if (versionArray[i] > v[i]) { return false; } } return versionArray.length < v.length; } /** * Sets version of currently loaded file * * @param version * version string */ public void setFileVersion(String version) { // AbstractApplication.debug("file version: " + version); if (version == null) { this.versionArray = null; return; } this.versionArray = getSubValues(version); } /** * @return euclidian view; if not present yet, new one is created */ public abstract EuclidianView createEuclidianView(); /** * Returns current mode (tool number) * * @return current mode */ final public int getMode() { EuclidianView view = getActiveEuclidianView(); if (view == null) { view = getEuclidianView1(); } return view.getMode(); } public void setMode(int mode) { setMode(mode, ModeSetter.TOOLBAR); } /** * Returns labeling style for newly created geos * * @return labeling style; AUTOMATIC is resolved either to * USE_DEFAULTS/POINTS_ONLY (for 3D) or OFF depending on visibility * of AV */ public int getCurrentLabelingStyle() { if (getLabelingStyle() == ConstructionDefaults.LABEL_VISIBLE_AUTOMATIC) { if ((getGuiManager() != null) && getGuiManager().hasAlgebraViewShowing()) { if (getAlgebraView().isVisible()) { if (isView3D(getGuiManager().getLayout().getDockManager() .getFocusedViewId())) { // only points (and sliders and angles) are labeled // for 3D return ConstructionDefaults.LABEL_VISIBLE_POINTS_ONLY; } // default behaviour for other views return ConstructionDefaults.LABEL_VISIBLE_USE_DEFAULTS; } // no AV: no label return ConstructionDefaults.LABEL_VISIBLE_ALWAYS_OFF; } return ConstructionDefaults.LABEL_VISIBLE_ALWAYS_OFF; } return getLabelingStyle(); } /** * This is needed for handling paths to images inside .ggb archive TODO * probably we should replace this methodby something else as images are * different in web * * @param fullPath * path to image * @return legth of MD5 hash output */ public int getMD5folderLength(String fullPath) { return 32; } /** * @param filename * filename * @return image wrapped in GBufferedImage */ public abstract MyImage getExternalImageAdapter(String filename, int width, int height); /** * @return whether label dragging is enableded */ final public boolean isLabelDragsEnabled() { return labelDragsEnabled; } /** * Enables or disables label dragging in this application. This is useful * for applets. * * @param flag * true to allow label dragging */ public void setLabelDragsEnabled(boolean flag) { labelDragsEnabled = flag; } /** * Enables or disables undo/redo in this application. This is useful for * applets. * * @param flag * true to allow Undo / Redo */ public void setUndoRedoEnabled(boolean flag) { undoRedoEnabled = flag; if (!undoRedoEnabled && kernel != null) { kernel.setUndoActive(false); } } /** * @return whether undo / redo are possible */ public boolean isUndoRedoEnabled() { return undoRedoEnabled; } /** * @param b */ public void setScrollToShow(boolean b) { // TODO Auto-generated method stub } /** * Sets state of application to "saved", so that no warning appears on * close. * * @author Zbynek Konecny * @version 2010-05-26 */ public void setSaved() { isSaved = true; for (SavedStateListener sl : savedListeners) { sl.stateChanged(true); } } public void registerSavedStateListener(SavedStateListener l) { savedListeners.add(l); } /** * Sets application state to "unsaved" so that user is reminded on close. */ public void setUnsaved() { isSaved = false; isAutoSaved = false; for (SavedStateListener sl : savedListeners) { sl.stateChanged(false); } } public final boolean isSaved() { return isSaved || kernel.getConstruction() == null || !kernel.getConstruction().isStarted(); } private boolean isAutoSaved = true; private AdjustViews adjustViews = null; private AdjustScreen adjustScreen = null; private AdjustScreen adjustScreen2 = null; public final boolean isAutoSaved() { return isAutoSaved; } public final void setAutoSaved() { isAutoSaved = true; } public final void setUnAutoSaved() { isAutoSaved = false; } /** * Makes given view active * * @param evID * view id */ public abstract void setActiveView(int evID); public void refreshViews() { getEuclidianView1().updateBackground(); if (hasEuclidianView2(1)) { getEuclidianView2(1).updateBackground(); } kernel.notifyRepaint(); } /** * Switches the application to macro editing mode * * @param editMacro * Tool to be edited * @author Zbynek Konecny * @version 2010-05-26 */ public void openMacro(Macro editMacro) { for (int i = 0; i < editMacro.getKernel().getMacroNumber(); i++) { if (editMacro.getKernel().getMacro(i) == editMacro) { break; } kernel.addMacro(editMacro.getKernel().getMacro(i)); } String allXml = getXML(); String header = allXml.substring(0, allXml.indexOf("<construction")); String footer = allXml.substring(allXml.indexOf("</construction>"), allXml.length()); StringBuilder sb = new StringBuilder(); editMacro.getXML(sb); String macroXml = sb.toString(); String newXml = header + macroXml.substring(macroXml.indexOf("<construction"), macroXml.indexOf("</construction>")) + footer; this.macro = editMacro; setXML(newXml, true); } public void openMacro(String macroName) { Macro editMacro = getKernel().getMacro(macroName); Log.debug("[STORAGE] nr: " + getKernel().getMacroNumber() + " macro for open is " + editMacro.getToolName()); openMacro(editMacro); // // for (int i = 0; i < editMacro.getKernel().getMacroNumber(); i++) { // // if (editMacro.getKernel().getMacro(i) == editMacro) { // // break; // // } // // kernel.addMacro(editMacro.getKernel().getMacro(i)); // // } // try { // getXMLio().processXMLString(macroXml, true, false, false); // } catch (Exception e) { // // TODO Auto-generated catch block // e.printStackTrace(); // this.macro = getKernel().getMacro(0); // // } // String allXml = getXML(); // String header = allXml.substring(0, allXml.indexOf("<construction")); // String footer = allXml.substring(allXml.indexOf("</construction>"), // allXml.length()); // // String newXml = header // + macroXml.substring(macroXml.indexOf("<construction"), // macroXml.indexOf("</construction>")) + footer; // setXML(newXml, true); } /** * Returns macro if in macro editing mode. * * @return macro being edited (in unchanged state) */ public Macro getMacro() { return macro; } /** * @return XML for all macros; if there are none, XML header+footer are * returned */ public String getMacroXML() { ArrayList<Macro> macros = kernel.getAllMacros(); return getXMLio().getFullMacroXML(macros); } /** * @return XML for or macros and/or Exercise or empty string if there are * none */ public String getMacroXMLorEmpty() { if (!kernel.hasMacros() && kernel.getExercise().isEmpty()) { return ""; } ArrayList<Macro> macros = kernel.getAllMacros(); return getXMLio().getFullMacroXML(macros); } /** * @param idx * secondary EV index, 1 for EV2 */ public boolean hasEuclidianView2(int idx) { return (getGuiManager() != null) && getGuiManager().hasEuclidianView2(idx); } public final void showError(MyError e) { String command = e.getcommandName(); String message = e.getLocalizedMessage(); if (command == null) { showErrorDialog(message); return; } getErrorHandler().showCommandError(command, message); } public final void showGenericError(Exception e) { // can't work out anything better, just show "Invalid Input" e.printStackTrace(); showError(getLocalization().getError("InvalidInput")); } /** * FKH * * @version 20040826 * @return full xml for GUI and construction */ public String getXML() { return getXMLio().getFullXML(); } public abstract void showError(String string, String str); /** * @param viewID * view id * @return view with given ID */ public View getView(int viewID) { // check for PlotPanel ID family first if ((getGuiManager() != null) && (getGuiManager().getPlotPanelView(viewID) != null)) { return getGuiManager().getPlotPanelView(viewID); } switch (viewID) { case VIEW_EUCLIDIAN: return getEuclidianView1(); case VIEW_EUCLIDIAN3D: return getEuclidianView3D(); case VIEW_ALGEBRA: return getAlgebraView(); case VIEW_SPREADSHEET: if (!isUsingFullGui()) { return null; } else if (getGuiManager() == null) { initGuiManager(); } if (getGuiManager() == null) { return null; } return getGuiManager().getSpreadsheetView(); case VIEW_CAS: if (!isUsingFullGui()) { return null; } else if (getGuiManager() == null) { initGuiManager(); } if (getGuiManager() == null) { return null; } return getGuiManager().getCasView(); case VIEW_EUCLIDIAN2: return hasEuclidianView2(1) ? getEuclidianView2(1) : null; case VIEW_CONSTRUCTION_PROTOCOL: if (!isUsingFullGui()) { return null; } else if (getGuiManager() == null) { initGuiManager(); } if (getGuiManager() == null) { return null; } return getGuiManager().getConstructionProtocolData(); case VIEW_PROBABILITY_CALCULATOR: if (!isUsingFullGui()) { return null; } else if (getGuiManager() == null) { initGuiManager(); } if (getGuiManager() == null) { return null; } return getGuiManager().getProbabilityCalculator(); case VIEW_DATA_ANALYSIS: if (!isUsingFullGui()) { return null; } else if (getGuiManager() == null) { initGuiManager(); } if (getGuiManager() == null) { return null; } return getGuiManager().getDataAnalysisView(); } return null; } /** * @param asPreference * true if we need this for prefs XML * @return XML for user interface (EVs, spreadsheet, kernel settings) */ public String getCompleteUserInterfaceXML(boolean asPreference) { StringBuilder sb = new StringBuilder(); // save gui tag settings sb.append(getGuiXML(asPreference)); // save euclidianView settings getEuclidianView1().getXML(sb, asPreference); // save euclidian view 2 settings // TODO: the EV preferences should be serialized using // app.getSettings(), not the view if (hasEuclidianView2EitherShowingOrNot(1)) { EuclidianView ev2 = getEuclidianView2(1); if (ev2 != null) { ev2.getXML(sb, asPreference); } } if (getGuiManager() != null) { // save spreadsheetView settings getGuiManager().getSpreadsheetViewXML(sb, asPreference); // save ProbabilityCalculator settings if (getGuiManager().hasProbabilityCalculator()) { getGuiManager().getProbabilityCalculatorXML(sb); } // save AlgebraView settings if (getGuiManager().hasAlgebraView()) { getGuiManager().getAlgebraViewXML(sb, asPreference); } // save Data Collection View settings if (getGuiManager().hasDataCollectionView()) { getGuiManager().getDataCollectionViewXML(sb, asPreference); } } if (asPreference) { getKeyboardXML(sb); } // coord style, decimal places settings etc kernel.getKernelXML(sb, asPreference); getScriptingXML(sb, asPreference); // save cas view seeting and cas session // if (casView != null) { // sb.append(((geogebra.cas.view.CASView) casView).getGUIXML()); // sb.append(((geogebra.cas.view.CASView) casView).getSessionXML()); // } return sb.toString(); } private void getScriptingXML(StringBuilder sb, boolean asPreference) { sb.append("<scripting"); if (getScriptingLanguage() != null) { sb.append(" language=\""); sb.append(getScriptingLanguage()); sb.append("\""); } sb.append(" blocked=\""); sb.append(isBlockUpdateScripts()); if (!asPreference) { sb.append("\" disabled=\""); sb.append(isScriptingDisabled()); } sb.append("\"/>\n"); } final public Settings getSettings() { return settings; } public final String getUniqueId() { return uniqueId; } public final void setUniqueId(String uniqueId) { this.uniqueId = uniqueId; } public abstract void resetUniqueId(); /** * @param auxiliaryObjects * true to show Auxiliary objects */ public final void setShowAuxiliaryObjects(boolean auxiliaryObjects) { if (showAuxiliaryObjects == auxiliaryObjects) { return; } showAuxiliaryObjects = auxiliaryObjects; if (getGuiManager() != null) { getGuiManager().setShowAuxiliaryObjects(auxiliaryObjects); // updateMenubar(); } } /** * Returns labeling style. See the constants in ConstructionDefaults (e.g. * LABEL_VISIBLE_AUTOMATIC) * * @return labeling style for new objects */ public int getLabelingStyle() { return labelingStyle; } /** * Sets labeling style. See the constants in ConstructionDefaults (e.g. * LABEL_VISIBLE_AUTOMATIC) * * @param labelingStyle * labeling style for new objects */ public void setLabelingStyle(int labelingStyle) { this.labelingStyle = labelingStyle; labelingStyleSelected = true; getKernel().getConstruction().getConstructionDefaults() .resetLabelModeDefaultGeos(); } /** * @return labeling style for new objects for menu */ public int getLabelingStyleForMenu() { if (labelingStyleSelected) { return getLabelingStyle(); } return -1; } /** * set the labeling style not selected, i.e. at least one default geo has * specific labeling style */ public void setLabelingStyleIsNotSelected() { labelingStyleSelected = false; if (getGuiManager() != null) { getGuiManager().updateMenubar(); } } /** * @return the scriptingDisabled */ public boolean isScriptingDisabled() { return scriptingDisabled; } /** * @param sd * the scriptingDisabled to set */ public void setScriptingDisabled(boolean sd) { this.scriptingDisabled = sd; } /** * @param size * preferred size */ public void setPreferredSize(GDimension size) { // TODO Auto-generated method stub } /** * @return timeout for tooltip disappearing (in seconds) */ public int getTooltipTimeout() { // TODO Auto-generated method stub return 0; } /** * Sets tooltip timeout (in seconds) * * @param ttt * tooltip timeout */ public void setTooltipTimeout(int ttt) { // TODO Auto-generated method stub } /** * @param ttl * tooltip language */ public void setTooltipLanguage(String ttl) { // TODO Auto-generated method stub } public abstract DrawEquation getDrawEquation(); public ArrayList<Perspective> getTmpPerspectives() { return tmpPerspectives; } /** * Save all perspectives included in a document into an array with temporary * perspectives. * * @param perspectives * array of perspetctives in the document */ public void setTmpPerspectives(ArrayList<Perspective> perspectives) { tmpPerspectives = perspectives; } /** * @param idx * view index; 1 for EV2 * @return EV2 */ public EuclidianView getEuclidianView2(int idx) { // TODO Auto-generated method stub return null; } /** * @return width of the whole application (central panel) This is needed for * Corner[6] */ public abstract double getWidth(); /** * @return height of the whole application (central panel) This is needed * for Corner[6] */ public abstract double getHeight(); /** * * @param serif * serif * @param style * font style * @param size * font size * @return font with given parameters */ public GFont getFontCommon(boolean serif, int style, int size) { return AwtFactory.getPrototype().newFont(serif ? "Serif" : "SansSerif", style, size); } /** * In Desktop gives current font, in Web creates a new one */ public abstract GFont getPlainFontCommon(); public boolean isExporting() { return exportType != ExportType.NONE; } public void setExporting(ExportType et, double scale) { exportType = et; exportScale = scale; } public ExportType getExportType() { return exportType; } public void setShowToolBarNoUpdate(boolean toolbar) { showToolBar = toolbar; } public void setShowToolBarHelpNoUpdate(boolean toolbarHelp) { showToolBarHelp = toolbarHelp; } public boolean showToolBar() { return showToolBar; } public boolean showMenuBar() { return showMenuBar; } public void setShowMenuBar(boolean flag) { showMenuBar = flag; } public void setShowToolBar(boolean toolbar) { showToolBar = toolbar; } public void setShowToolBar(boolean toolbar, boolean help) { showToolBar = toolbar; showToolBarHelp = help; } public int getToolbarPosition() { return toolbarPosition; } /** * Update the toolbar position flag and optionally rebuilds the UI * * @param position * new position * @param update * whether to rebuild the UI */ public void setToolbarPosition(int position, boolean update) { // needs to be overridden } /** * init the kernel (used for 3D) */ final public void initKernel() { kernel = companion.newKernel(); // ensure that the selection manager is created getSelectionManager(); } /** * init the EuclidianView */ final public void initEuclidianViews() { euclidianController = newEuclidianController(kernel); euclidianView = newEuclidianView(showAxes, showGrid); } abstract protected EuclidianView newEuclidianView(boolean[] showAxes1, boolean showGrid1); public abstract EuclidianController newEuclidianController(Kernel kernel1); /** * Returns undo manager * * @param cons * construction * @return undo manager */ public abstract UndoManager getUndoManager(Construction cons); /** * TODO refactor to remove this method Creates new animation manager * * @param kernel2 * kernel * @return animation manager */ public AnimationManager newAnimationManager(Kernel kernel2) { return new AnimationManager(kernel2); } /** * TODO maybe we should create another factory for internal classes like * this * * @return new graphics adapter for geo */ public abstract GeoElementGraphicsAdapter newGeoElementGraphicsAdapter(); /** * Repaints the spreadsheet view */ public void repaintSpreadsheet() { // TODO Auto-generated method stub } /** * @return whether on the fly point creation is active */ public final boolean isOnTheFlyPointCreationActive() { return isOnTheFlyPointCreationActive; } /** * @param isOnTheFlyPointCreationActive * Whether points can be created on the fly */ public final void setOnTheFlyPointCreationActive( boolean isOnTheFlyPointCreationActive) { this.isOnTheFlyPointCreationActive = isOnTheFlyPointCreationActive; } /** * @return spreadsheet trace manager */ final public SpreadsheetTraceManager getTraceManager() { if (traceManager == null) { traceManager = new SpreadsheetTraceManager(this); } return traceManager; } /** * * @return true if there is a trace manager */ final public boolean hasTraceManager() { return traceManager != null; } /** * * @return true if at least one geo is traced */ final public boolean hasGeoTraced() { if (traceManager == null) { return false; } return traceManager.hasGeoTraced(); } /** * Switch current cursor to default cursor */ public void setDefaultCursor() { // TODO Auto-generated method stub } /** * Switch current cursor to wait cursor */ public abstract void setWaitCursor(); /** * Update stylebars of all views */ public abstract void updateStyleBars(); /** * Update dynamic stylebars of all views */ public abstract void updateDynamicStyleBars(); /** * Changes current mode to move mode */ public void setMoveMode() { setMode(EuclidianConstants.MODE_MOVE); } /** * Changes current mode to mode of the toolbar's 1rst tool. */ public abstract void set1rstMode(); /** * @return spreadsheet table model */ public abstract SpreadsheetTableModel getSpreadsheetTableModel(); /** * Changes current mode (tool number) * * @param mode * new mode */ public void setMode(int mode, ModeSetter m) { if (mode != EuclidianConstants.MODE_SELECTION_LISTENER) { currentSelectionListener = null; } if (getGuiManager() != null) { setModeFromGuiManager(mode, m); } else if (euclidianView != null) { euclidianView.setMode(mode, m); } } protected void setModeFromGuiManager(int mode, ModeSetter m) { getGuiManager().setMode(mode, m); } /** * Adds geo to Euclidian view (EV1) * * @param geo * geo */ public void addToEuclidianView(GeoElement geo) { geo.addView(App.VIEW_EUCLIDIAN); getEuclidianView1().add(geo); } /** * Removes geo from Euclidian view (EV1) * * @param geo * geo */ public void removeFromEuclidianView(GeoElement geo) { geo.removeView(App.VIEW_EUCLIDIAN); getEuclidianView1().remove(geo); } /** * Adds geo to 3D views * * @param geo * geo */ public void addToViews3D(GeoElement geo) { geo.addViews3D(); getEuclidianView3D().add(geo); } /** * Removes geo from 3D views * * @param geo * geo */ public void removeFromViews3D(GeoElement geo) { geo.removeViews3D(); getEuclidianView3D().remove(geo); } public abstract void setXML(String string, boolean b); /** * Returns API that can be used from external applications * * @return GeoGebra API */ public abstract GgbAPI getGgbApi(); /** * @return sound manager */ public abstract SoundManager getSoundManager(); /** * @return kernel for this window */ public final Kernel getKernel() { return kernel; } /** * @param e * event * @return whether right mouse button was clicked or click + ctrl appeared * on Mac */ public boolean isRightClick(AbstractEvent e) { return e != null && e.isRightClick(); } /** * @param e * event * @return whether Ctrl on Win/Linux or Meta on Mac was pressed */ public boolean isControlDown(AbstractEvent e) { return e != null && e.isControlDown(); } /** * @param e * event * @return whether middle button was clicked once */ public boolean isMiddleClick(AbstractEvent e) { return e.isMiddleClick(); } /** * @return whether input bar is visible */ public abstract boolean showAlgebraInput(); /** * @return global key dispatcher */ public abstract GlobalKeyDispatcher getGlobalKeyDispatcher(); public abstract void callAppletJavaScript(String string, Object[] args); /** * Inform current selection listener about newly (un)selected geo * * @param geo * (un)selected geo * @param addToSelection * whether it should be added or removed from selection */ public void geoElementSelected(GeoElement geo, boolean addToSelection) { if (currentSelectionListener != null) { currentSelectionListener.geoElementSelected(geo, addToSelection); } } /** * Links properties view to this application * * @param propertiesView * properties view */ public void setPropertiesView(PropertiesView propertiesView) { this.propertiesView = propertiesView; } /** * Sets a mode where clicking on an object will notify the given selection * listener. * * @param sl * selection listener */ public void setSelectionListenerMode(GeoElementSelectionListener sl) { getSelectionManager().resetGeoToggled(); // prevent undo current tool // construction currentSelectionListener = sl; if (sl != null) { setMode(EuclidianConstants.MODE_SELECTION_LISTENER); } else { setMoveMode(); } } /** * Update stylebars and menubar (and possibly properties view) to match * selection * * @param updatePropertiesView * whether to update properties view */ @Override public void updateSelection(boolean updatePropertiesView) { if (!isUsingFullGui() || isIniting()) { return; } // put in to check possible bottleneck // Application.debug("Update Selection"); if (getGuiManager() != null && showMenuBar) { getGuiManager().updateMenubarSelection(); } // if showMenuBar is false, we can still update the style bars if (getActiveEuclidianView().getMode() == EuclidianConstants.MODE_MOVE || getActiveEuclidianView() .getMode() == EuclidianConstants.MODE_TRANSLATEVIEW) { updateStyleBars(); } if (has(Feature.DYNAMIC_STYLEBAR)) { // TODO update only dynamic stylebar updateStyleBars(); } if (updatePropertiesView && propertiesView != null && showMenuBar) { propertiesView.updateSelection(); } ScreenReader.updateSelection(this); } /** * @param type * what properties pannel should be showing (object, defults, * advanced, ...) */ public void setPropertiesViewPanel(OptionType type) { if (propertiesView != null) { propertiesView.setOptionPanel(type); } } /** * @return whether this app is initializing * @see #initing */ public boolean isIniting() { return initing; } /** * @return whether shift, drag and zoom features are enabled */ public final boolean isShiftDragZoomEnabled() { return shiftDragZoomEnabled; } /** * @param shiftDragZoomEnabled * whether shift, drag and zoom features are enabled */ public final void setShiftDragZoomEnabled(boolean shiftDragZoomEnabled) { this.shiftDragZoomEnabled = shiftDragZoomEnabled; } /** * Updates menubar */ public abstract void updateMenubar(); /** * @return general font size (used for EV and GUI) */ public int getFontSize() { return appFontSize; } /** * Changes font size and possibly resets fonts * * @param points * font size * @param update * whether fonts should be reset * @see #resetFonts() */ public void setFontSize(int points, boolean update) { if (points == appFontSize) { return; } appFontSize = Util.getValidFontSize(points); // isSaved = false; if (!update) { return; } EuclidianView ev1 = getEuclidianView1(); if (ev1 != null && ev1.hasStyleBar()) { ev1.getStyleBar().reinit(); } if (hasEuclidianView2(1)) { EuclidianView ev2 = getEuclidianView2(1); if (ev2 != null && ev2.hasStyleBar()) { ev2.getStyleBar().reinit(); } } if (hasEuclidianView3D() && isEuclidianView3Dinited() && getEuclidianView3D().hasStyleBar()) { getEuclidianView3D().getStyleBar().reinit(); } resetFonts(); updateUI(); } /** * Recursively update all components with current look and feel */ public abstract void updateUI(); /** * @return string representation of current locale, eg no_NO_NY */ /** * Update font sizes of all components to match current GUI font size */ final public void resetFonts() { companion.resetFonts(); } /** * @return font size for GUI; if not specified, general font size is * returned */ public int getGUIFontSize() { return guiFontSize == -1 ? getFontSize() : guiFontSize; } /** * @param size * GUI font size */ public void setGUIFontSize(int size) { guiFontSize = size; // updateFonts(); // isSaved = false; resetFonts(); } /** * Returns font manager * * @return font manager */ protected abstract FontManager getFontManager(); /** * Returns a font that can display testString in plain sans-serif font and * current font size. * * @param testString * test string * @return font */ public GFont getFontCanDisplay(String testString) { return getFontCanDisplay(testString, false, GFont.PLAIN, getFontSize()); } /** * Returns a font that can display testString in given font style, * sans-serif and current font size. * * @param testString * test string * @param fontStyle * font style * @return font */ public GFont getFontCanDisplay(String testString, int fontStyle) { return getFontCanDisplay(testString, false, fontStyle, getFontSize()); } /** * Returns a font that can display testString and given font size. * * @param testString * test string * @param serif * true=serif, false=sans-serif * @param fontStyle * font style * @param fontSize * font size * @return font */ public GFont getFontCanDisplay(String testString, boolean serif, int fontStyle, int fontSize) { return getFontManager().getFontCanDisplay(testString, serif, fontStyle, fontSize); } /** * Returns gui settings in XML format * * @param asPreference * whether this is for preferences file * @return gui settings in XML format */ public String getGuiXML(boolean asPreference) { StringBuilder sb = new StringBuilder(); sb.append("<gui>\n"); getWindowLayoutXML(sb, asPreference); sb.append("\t<font "); sb.append(" size=\""); sb.append(getFontSize()); sb.append("\"/>\n"); if (asPreference) { sb.append("\t<menuFont "); sb.append(" size=\""); sb.append(guiFontSize); sb.append("\"/>\n"); sb.append("\t<tooltipSettings "); if (getLocalization().getTooltipLanguageString() != null) { sb.append(" language=\""); sb.append(getLocalization().getTooltipLanguageString()); sb.append("\""); } sb.append(" timeout=\""); sb.append(getTooltipTimeout()); sb.append("\""); sb.append("/>\n"); } if (getGuiManager() != null) { getGuiManager().getExtraViewsXML(sb); } sb.append("</gui>\n"); return sb.toString(); } protected abstract int getWindowWidth(); protected abstract int getWindowHeight(); /** * Appends layout settings in XML format to given builder * * @param sb * string builder * @param asPreference * whether this is for preferences */ protected void getWindowLayoutXML(StringBuilder sb, boolean asPreference) { sb.append("\t<window width=\""); sb.append(getWindowWidth()); sb.append("\" height=\""); sb.append(getWindowHeight()); sb.append("\" />\n"); getLayoutXML(sb, asPreference); // labeling style // default changed so we need to always save this now // if (labelingStyle != ConstructionDefaults.LABEL_VISIBLE_AUTOMATIC) { sb.append("\t<labelingStyle "); sb.append(" val=\""); sb.append(getLabelingStyle()); sb.append("\"/>\n"); } protected abstract void getLayoutXML(StringBuilder sb, boolean asPreference); public abstract void reset(); /** * @return selection listener */ public GeoElementSelectionListener getCurrentSelectionListener() { return currentSelectionListener; } /** * @param sl * selection listener */ public void setCurrentSelectionListener(GeoElementSelectionListener sl) { currentSelectionListener = sl; } /** * @param flag * whether reset icon should be visible (in applets) */ public void setShowResetIcon(boolean flag) { if (flag != showResetIcon) { showResetIcon = flag; euclidianView.updateBackground(); } } /** * @return whether reset icon is visible */ final public boolean showResetIcon() { return showResetIcon && !runningInFrame; } /** * @return whether undo manger can save undo info */ public boolean isUndoActive() { return kernel.isUndoActive(); } /** * (De)activate undo and redo, update toolbar * * @param undoActive * whether undo should be active */ public void setUndoActive(boolean undoActive) { boolean flag = undoActive; // don't allow undo when data-param-EnableUndoRedo = false if (flag && !undoRedoEnabled) { flag = false; } if (kernel.isUndoActive() == flag) { return; } kernel.setUndoActive(flag); if (flag) { kernel.initUndoInfo(); } if (getGuiManager() != null) { getGuiManager().updateActions(); } setSaved(); } /** * @return whether we are running in HTML5 applet */ public abstract boolean isHTML5Applet(); /** * @param useTransparentCursorWhenDragging * whether transparent cursor should be used while dragging */ public void setUseTransparentCursorWhenDragging( boolean useTransparentCursorWhenDragging) { this.useTransparentCursorWhenDragging = useTransparentCursorWhenDragging; } public void doAfterRedefine(GeoElementND geo) { if (getGuiManager() != null) { getGuiManager().doAfterRedefine(geo); } } /** * Opens browser with given URL * * @param string * URL */ public abstract void showURLinBrowser(String string); /** * Opens the upload to GGT dialog */ public abstract void uploadToGeoGebraTube(); public boolean getUseFullGui() { return useFullGui; } public int getAppCanvasWidth() { return appCanvasWidth; } public int getAppCanvasHeight() { return appCanvasHeight; } /** * @return where to show the inputBar (respective inputBox) */ public InputPosition getInputPosition() { return showInputTop; } /** * Changes input position between bottom and top * * @param flag * whether input should be on top * @param update * whether layout update is needed afterwards */ public void setInputPosition(InputPosition flag, boolean update) { if (flag == showInputTop) { return; } showInputTop = flag; if (update && !isIniting()) { updateApplicationLayout(); } } /** * @return whether innput help toggle button should be visible */ public boolean showInputHelpToggle() { return showInputHelpToggle; } /** * Shows / hides input help toggle button * * @param flag * whether innput help toggle button should be visible */ public void setShowInputHelpToggle(boolean flag) { if (showInputHelpToggle == flag || getGuiManager() == null) { return; } showInputHelpToggle = flag; getGuiManager().updateAlgebraInput(); updateMenubar(); } /** * Updates application layout */ public abstract void updateApplicationLayout(); /** * Returns name or help for given tool * * @param mode * mode number * @param toolName * true for name, false for help * @return tool name or help */ public String getToolNameOrHelp(int mode, boolean toolName) { // macro String ret; if (mode >= EuclidianConstants.MACRO_MODE_ID_OFFSET) { // MACRO int macroID = mode - EuclidianConstants.MACRO_MODE_ID_OFFSET; try { Macro macro1 = kernel.getMacro(macroID); if (toolName) { // TOOL NAME ret = macro1.getToolOrCommandName(); } else { // TOOL HELP ret = macro1.getToolHelp(); } } catch (Exception e) { Log.debug( "Application.getModeText(): macro does not exist: ID = " + macroID); // e.printStackTrace(); return ""; } } else { // STANDARD TOOL if (toolName) { // tool name String modeText = EuclidianConstants.getModeText(mode); ret = getLocalization().getMenu(modeText); } else { String modeText = EuclidianConstants.getModeTextSimple(mode); // tool help ret = getLocalization().getMenu(modeText + ".Help"); } } return ret; } /** * Returns name of given tool. * * @param mode * number * @return name of given tool. */ public String getToolName(int mode) { return getToolNameOrHelp(mode, true); } /** * Returns the tool help text for the given tool. * * @param mode * number * @return the tool help text for the given tool. */ public String getToolHelp(int mode) { return getToolNameOrHelp(mode, false); } /** * @return parser extension for functions */ public ParserFunctions getParserFunctions() { if (pf == null) { pf = new ParserFunctions(); } pf.setInverseTrig( kernel.getLoadingMode() && kernel.getInverseTrigReturnsAngle()); return pf; } /** * Clears construction * * @return true if successful otherwise false (eg user clicks "Cancel") */ public abstract boolean clearConstruction(); /** * Clear construction and reset settings from preferences */ public abstract void fileNew(); /** * Remove references to dynamic bounds, reset selection rectangle */ protected void resetEVs() { if (kernel.getConstruction() != null) { kernel.getConstruction().setIgnoringNewTypes(true); } getEuclidianView1().resetXYMinMaxObjects(); getEuclidianView1().setSelectionRectangle(null); if (hasEuclidianView2EitherShowingOrNot(1)) { getEuclidianView2(1).resetXYMinMaxObjects(); getEuclidianView2(1).setSelectionRectangle(null); } if (kernel.getConstruction() != null) { kernel.getConstruction().setIgnoringNewTypes(false); } } /** * allows use of seeds to generate the same sequence for a ggb file * * @return random number in [0,1] */ public double getRandomNumber() { return random.nextDouble(); } /** * @param a * low value of distribution interval * @param b * high value of distribution interval * @return random number from Uniform Distribution[a,b] */ public double randomUniform(double a, double b) { return a + getRandomNumber() * (b - a); } /** * allows use of seeds to generate the same sequence for a ggb file * * @param low * least possible value of result * @param high * highest possible value of result * * @return random integer between a and b inclusive (or NaN for * getRandomIntegerBetween(5.5, 5.5)) * */ public int getRandomIntegerBetween(double low, double high) { // make sure 4.000000001 is not rounded up to 5 double a = Kernel.checkInteger(low); double b = Kernel.checkInteger(high); // Math.floor/ceil to make sure // RandomBetween[3.2, 4.7] is between 3.2 and 4.7 int min = (int) Math.ceil(Math.min(a, b)); int max = (int) Math.floor(Math.max(a, b)); // eg RandomBetween[5.499999, 5.500001] // eg RandomBetween[5.5, 5.5] if (min > max) { int tmp = max; max = min; min = tmp; } return random.nextInt(max - min + 1) + min; } /** * allows use of seeds to generate the same sequence for a ggb file * * @param seed * new seed */ public void setRandomSeed(int seed) { random = new Random(seed); } public abstract boolean loadXML(String xml) throws Exception; /** * copy bitmap of EV to clipboard */ public abstract void copyGraphicsViewToClipboard(); /** * copy base64 of current .ggb file to clipboard */ public void copyBase64ToClipboard() { copyTextToSystemClipboard(getGgbApi().getBase64()); } /** * copy full HTML5 export for current .ggb file to clipboard */ public void copyFullHTML5ExportToClipboard() { copyTextToSystemClipboard(getFullHTML5ExportString()); } public String getFullHTML5ExportString() { GuiManagerInterface gui = getGuiManager(); StringBuilder sb = new StringBuilder(); sb.append("<!DOCTYPE html>\n"); sb.append("<html>\n"); sb.append("<head>\n"); if (has(Feature.TUBE_BETA)) { sb.append( "<script src=\"https://beta.geogebra.org/scripts/deployggb.js\"></script>\n\n"); } else { sb.append( "<script src=\"https://www.geogebra.org/scripts/deployggb.js\"></script>\n\n"); } sb.append("</head>\n"); sb.append("<body>\n"); sb.append("<div id=\"ggbApplet\"></div>\n\n"); sb.append("<script>\n"); sb.append("var parameters = {\n"); sb.append("\"id\": \"ggbApplet\",\n"); sb.append("\"width\":" + (int) getWidth() + ",\n"); sb.append("\"height\":" + (int) getHeight() + ",\n"); sb.append("\"showMenuBar\":" + showMenuBar + ",\n"); sb.append("\"showAlgebraInput\":" + showAlgebraInput + ",\n"); sb.append("\"showToolBar\":" + showToolBar + ",\n"); if (showToolBar) { if (gui != null) { sb.append("\"customToolBar\":\""); sb.append(gui.getToolbarDefinition()); sb.append("\",\n"); } sb.append("\"showToolBarHelp\":" + showToolBarHelp + ",\n"); } sb.append("\"showResetIcon\":false,\n"); sb.append("\"enableLabelDrags\":false,\n"); sb.append("\"enableShiftDragZoom\":true,\n"); sb.append("\"enableRightClick\":false,\n"); sb.append("\"errorDialogsActive\":false,\n"); sb.append("\"useBrowserForJS\":false,\n"); sb.append("\"preventFocus\":false,\n"); sb.append("\"scale\":1,\n"); sb.append("\"disableAutoScale\":false,\n"); sb.append("\"clickToLoad\":false,\n"); sb.append( "\"language\":\"" + getLocalization().getLanguage() + "\",\n"); sb.append( "// use this instead of ggbBase64 to load a material from geogebra.org\n"); sb.append("// \"material_id\":12345,\n"); sb.append("// use this instead of ggbBase64 to load a .ggb file\n"); sb.append("// \"filename\":\"myfile.ggb\",\n"); sb.append("\"ggbBase64\":\""); // don't include preview bitmap sb.append(getGgbApi().getBase64(false)); sb.append("\"};\n"); // eg var views = // {"is3D":1,"AV":0,"SV":0,"CV":0,"EV2":0,"CP":0,"PC":0,"DA":0,"FI":0,"PV":0,"macro":0}; sb.append( "// is3D=is 3D applet using 3D view, AV=Algebra View, SV=Spreadsheet View, CV=CAS View, EV2=Graphics View 2, CP=Construction Protocol, PC=Probability Calculator, DA=Data Analysis, FI=Function Inspector, PV=Python, macro=Macro View\n"); sb.append("var views = {"); sb.append("'is3D': "); sb.append(kernel.getConstruction().has3DObjects() ? "1" : "0"); if (gui != null) { sb.append(",'AV': "); sb.append(gui.hasAlgebraView() && gui.getAlgebraView().isShowing() ? "1" : "0"); sb.append(",'SV': "); sb.append(gui.hasSpreadsheetView() && gui.getSpreadsheetView().isShowing() ? "1" : "0"); sb.append(",'CV': "); sb.append((gui.hasCasView() ? "1" : "0")); sb.append(",'EV2': "); sb.append((hasEuclidianView2(1) ? "1" : "0")); sb.append(",'CP': "); sb.append(gui.isUsingConstructionProtocol() ? "1" : "0"); sb.append(",'PC': "); sb.append(gui.hasProbabilityCalculator() ? "1" : "0"); sb.append(",'DA': "); sb.append(gui.hasDataAnalysisView() ? "1" : "0"); sb.append(",'FI': "); sb.append(getDialogManager().hasFunctionInspector() ? "1" : "0"); } // TODO sb.append(",'macro': 0"); sb.append("};\n"); sb.append("var applet = new GGBApplet(parameters, '5.0', views);\n"); // String codeBase = kernel.kernelHas3DObjects() ? "web3d" : "web"; // sb.append("applet.setHTML5Codebase('http://web.geogebra.org/5.0/" // + codeBase + "/');\n"); sb.append("window.onload = function() {applet.inject('ggbApplet')};\n"); sb.append("</script>\n"); sb.append("</body>\n"); sb.append("</html>\n"); return sb.toString(); } /** * Resets active EV to standard */ public final void setStandardView() { getActiveEuclidianView().setStandardView(true); } public abstract void exitAll(); // protected abstract Object getMainComponent(); public String getVersionString() { if (version != null) { return version.getVersionString(prerelease, canary); } // fallback in case version not set properly return GeoGebraConstants.VERSION_STRING + "?"; } public abstract NormalizerMinimal getNormalizer(); public final void zoom(double px, double py, double zoomFactor) { getActiveEuclidianView().zoom(px, py, zoomFactor, 15, true); } /** * Sets the ratio between the scales of y-axis and x-axis, i.e. ratio = * yscale / xscale; * * @param axesratio * axes scale ratio */ public final void zoomAxesRatio(double axesratio) { getActiveEuclidianView().zoomAxesRatio(axesratio, true); } /** * Zooms and pans active EV to show all objects * * @param keepRatio * true to keep ratio of axes */ public final void setViewShowAllObjects(boolean keepRatio) { getActiveEuclidianView().setViewShowAllObjects(true, keepRatio); } /** * @return whether right click features are enabled */ final public boolean isRightClickEnabled() { return rightClickEnabled; } /** * Enables or disables right clicking in this application. This is useful * for applets. * * @param flag * whether right click features should be enabled */ public void setRightClickEnabled(boolean flag) { rightClickEnabled = flag; } /** * @return whether right click features are enabled for Algebra View */ final public boolean isRightClickEnabledForAV() { return rightClickEnabledForAV; } /** * Enables or disables right clicking for Algebra View. Used e.g. in * Exam Simple Calc app * * @param flag whether right click features should be enabled */ public void setRightClickEnabledForAV(boolean flag) { rightClickEnabledForAV = flag; } /** * @return whether context menu is enabled */ public final boolean letShowPopupMenu() { return rightClickEnabled; } /** * @return whether properties dialog is enabled */ public boolean letShowPropertiesDialog() { return rightClickEnabled; } /** * @return preferences XML */ public String getPreferencesXML() { return getXMLio().getPreferencesXML(); } /** * @param geo1 * geo * @param string * parameter (for input box scripts) */ public abstract void runScripts(GeoElement geo1, String string); /** * @param type * JS or GGBScript * @param scriptText0 * possibly localized text * @param translate * whether to convert from localized * @return sript object */ public Script createScript(ScriptType type, String scriptText0, boolean translate) { String scriptText = scriptText0; if (type == ScriptType.GGBSCRIPT && translate) { scriptText = GgbScript.localizedScript2Script(this, scriptText); } return type.newScript(this, scriptText); } /** * Attach GGBScript runner to event dispatcher */ public void startGeoScriptRunner() { if (geoScriptRunner == null) { geoScriptRunner = new GeoScriptRunner(this); getEventDispatcher().addEventListener(geoScriptRunner); } } /** * Compares 2, 3 or 4 objects by using the Relation Tool. * * @param ra * first object * @param rb * second object * @param rc * third object (optional, can be null) * @param rd * forth object (optional, can be null) * * @author Zoltan Kovacs <zoltan@geogebra.org> */ public void showRelation(final GeoElement ra, final GeoElement rb, final GeoElement rc, final GeoElement rd) { Relation.showRelation(this, ra, rb, rc, rd); } public GeoElement getGeoForCopyStyle() { return geoForCopyStyle; } public void setGeoForCopyStyle(GeoElement geo) { geoForCopyStyle = geo; } public abstract CASFactory getCASFactory(); public abstract Factory getFactory(); public void dispatchEvent(Event evt) { getEventDispatcher().dispatchEvent(evt); } public OptionsMenu getOptionsMenu(MenuFactory mf) { if (optionsMenu == null) { optionsMenu = new OptionsMenu(this, mf); } return optionsMenu; } public boolean hasOptionsMenu() { return optionsMenu != null; } public MyXMLio getXMLio() { if (myXMLio == null) { myXMLio = createXMLio(kernel.getConstruction()); } return myXMLio; } public abstract MyXMLio createXMLio(Construction cons); public boolean hasEventDispatcher() { return eventDispatcher != null; } /** * This should not be used, just overriden in AppW */ public void scheduleUpdateConstruction() { kernel.getConstruction().updateConstructionLaTeX(); kernel.notifyRepaint(); } public void setShowAlgebraInput(boolean flag, boolean update) { showAlgebraInput = flag; if (update) { updateApplicationLayout(); updateMenubar(); } } public void setNeedsSpreadsheetTableModel() { needsSpreadsheetTableModel = true; } public boolean needsSpreadsheetTableModel() { return needsSpreadsheetTableModel; } public final int getAppletWidth() { return appletWidth; } public void setAppletWidth(int width) { this.appletWidth = width; } public int getAppletHeight() { return appletHeight; } public void setAppletHeight(int height) { this.appletHeight = height; } public void startCollectingRepaints() { getEuclidianView1().getEuclidianController() .startCollectingMinorRepaints(); } public void stopCollectingRepaints() { getEuclidianView1().getEuclidianController() .stopCollectingMinorRepaints(); } public abstract Localization getLocalization(); public SelectionManager getSelectionManager() { if (selection == null) { selection = new SelectionManager(getKernel(), this); } return selection; } /** * Returns the tool name and tool help text for the given tool as an HTML * text that is useful for tooltips. * * @param mode * : tool ID */ public String getToolTooltipHTML(int mode) { StringBuilder sbTooltip = new StringBuilder(); sbTooltip.append("<html><b>"); sbTooltip.append(StringUtil.toHTMLString(getToolName(mode))); sbTooltip.append("</b><br>"); sbTooltip.append(StringUtil.toHTMLString(getToolHelp(mode))); sbTooltip.append("</html>"); return sbTooltip.toString(); } public void resetPen() { getEuclidianView1().getEuclidianController().resetPen(); if (hasEuclidianView2(1)) { getEuclidianView2(1).getEuclidianController().resetPen(); } } public boolean getShowCPNavNeedsUpdate(int id) { if (showConstProtNavigationNeedsUpdate == null) { return false; } Boolean update = showConstProtNavigationNeedsUpdate.get(id); if (update == null) { return false; } return update; } private boolean getShowCPNavNeedsUpdate() { if (showConstProtNavigationNeedsUpdate == null) { return false; } for (boolean update : showConstProtNavigationNeedsUpdate.values()) { if (update) { return true; } } return false; } public boolean showConsProtNavigation() { if (showView(App.VIEW_CONSTRUCTION_PROTOCOL)) { return true; } if (showConsProtNavigation == null) { return false; } for (boolean show : showConsProtNavigation.values()) { if (show) { return true; } } return false; } public void getConsProtNavigationIds(StringBuilder sb) { if (showConsProtNavigation == null) { if (showView(App.VIEW_CONSTRUCTION_PROTOCOL)) { sb.append(App.VIEW_CONSTRUCTION_PROTOCOL); } return; } boolean alreadyOne = false; for (Entry<Integer, Boolean> entry : showConsProtNavigation .entrySet()) { int id = entry.getKey(); if (entry.getValue()) { if (alreadyOne) { sb.append(" "); } else { alreadyOne = true; } sb.append(id); } } } public boolean showConsProtNavigation(int id) { if (id == App.VIEW_CONSTRUCTION_PROTOCOL) { return true; } if (showConsProtNavigation == null) { return false; } Boolean show = showConsProtNavigation.get(id); if (show == null) { return false; } return show; } /** * @param show * whether navigation bar should be visible * @param playButton * whether play button should be visible * @param playDelay * delay between phases (in seconds) * @param showProtButton * whether button to show construction protocol should be visible */ public void setShowConstructionProtocolNavigation(boolean show, int id, boolean playButton, double playDelay, boolean showProtButton) { ConstructionProtocolSettings cpSettings = getSettings() .getConstructionProtocol(); cpSettings.setShowPlayButton(playButton); cpSettings.setPlayDelay(playDelay); cpSettings.setShowConsProtButton(showProtButton); if (getGuiManager() != null) { getGuiManager().applyCPsettings(cpSettings); } setShowConstructionProtocolNavigation(show, id); if (getGuiManager() != null) { if (show) { getGuiManager().setShowConstructionProtocolNavigation(show, id, playButton, playDelay, showProtButton); } } } public void setHideConstructionProtocolNavigation() { if (!showConsProtNavigation() && (!getShowCPNavNeedsUpdate())) { return; } if (showConsProtNavigation == null) { return; } if (getGuiManager() != null) { for (int id : showConsProtNavigation.keySet()) { showConsProtNavigation.put(id, false); getGuiManager().setShowConstructionProtocolNavigation(false, id); setShowConstProtNavigationNeedsUpdate(id, false); } } else { for (int id : showConsProtNavigation.keySet()) { setShowConstProtNavigationNeedsUpdate(id, true); } } } private void setShowConstProtNavigationNeedsUpdate(int id, boolean flag) { if (showConstProtNavigationNeedsUpdate == null) { showConstProtNavigationNeedsUpdate = new HashMap<Integer, Boolean>(); } Boolean update = showConstProtNavigationNeedsUpdate.get(id); if (update == null || update != flag) { showConstProtNavigationNeedsUpdate.put(id, flag); } } /** * Displays the construction protocol navigation * * @param flag * true to show navigation bar */ public void setShowConstructionProtocolNavigation(boolean flag) { dispatchEvent( new Event(EventType.SHOW_NAVIGATION_BAR, null, flag + "")); if (!flag) { setHideConstructionProtocolNavigation(); } else { if (!showConsProtNavigation()) { // show navigation bar in active view setShowConstructionProtocolNavigation(true, getActiveEuclidianView().getViewID()); return; } else if (!getShowCPNavNeedsUpdate()) { return; } if (getGuiManager() != null) { for (int id : showConsProtNavigation.keySet()) { showConsProtNavigation.put(id, true); getGuiManager().setShowConstructionProtocolNavigation(true, id); setShowConstProtNavigationNeedsUpdate(id, false); } } else { for (int id : showConsProtNavigation.keySet()) { setShowConstProtNavigationNeedsUpdate(id, true); } } } } /** * Displays the construction protocol navigation * * @param flag * true to show navigation bar */ public void setShowConstructionProtocolNavigation(boolean flag, int id) { if (showConsProtNavigation == null) { showConsProtNavigation = new HashMap<Integer, Boolean>(); } else { if ((flag == showConsProtNavigation(id)) && (!getShowCPNavNeedsUpdate(id))) { return; } } showConsProtNavigation.put(id, flag); dispatchEvent(new Event(EventType.SHOW_NAVIGATION_BAR, null, "[" + flag + "," + id + "]")); if (getGuiManager() != null) { getGuiManager().setShowConstructionProtocolNavigation(flag, id); setShowConstProtNavigationNeedsUpdate(id, false); } else { setShowConstProtNavigationNeedsUpdate(id, true); } } public void setNavBarButtonPause() { if (getGuiManager() != null) { getGuiManager().setNavBarButtonPause(); } } public void setNavBarButtonPlay() { if (getGuiManager() != null) { getGuiManager().setNavBarButtonPlay(); } } public void toggleShowConstructionProtocolNavigation(int id) { setShowConstructionProtocolNavigation(!showConsProtNavigation(id), id); setUnsaved(); // updateCenterPanel(true); if (getGuiManager() != null) { getGuiManager() .updateCheckBoxesForShowConstructinProtocolNavigation(id); } } /** * @param mode * app mode ID */ public GImageIcon wrapGetModeIcon(int mode) { // TODO: debug message commented out from Trunk version, probably loops // Log.debug("App.wrapGetModeIcon must be overriden"); return null; } /** * * useful for benchmarking ie only useful for elapsed time * * accuracy will depend on the platform / browser uses * System.nanoTime()/1000000 in Java performance.now() in JavaScript * * Won't return sub-millisecond accuracy * * Chrome: doesn't work for sub-millisecond yet * https://code.google.com/p/chromium/issues/detail?id=158234 * * @return millisecond time */ public abstract double getMillisecondTime(); public void updateActions() { if (isUsingFullGui() && getGuiManager() != null) { getGuiManager().updateActions(); } } public void doRepaintViews() { // TODO Auto-generated method stub } /** * @return SignInOperation eventFlow */ public LogInOperation getLoginOperation() { return loginOperation; } /** * This method is to be overridden in subclasses In Web, this can run in * asyncronous mode * * ** MUST STAY AS ABSTRACT OTHERWISE WEB PROJECT DOESN'T GET SPLIT UP ** * * @return AlgoKimberlingWeightsInterface */ public abstract AlgoKimberlingWeightsInterface getAlgoKimberlingWeights(); /** * Needed for running part of AlgoKimberling async * <p/> * ** MUST STAY AS ABSTRACT OTHERWISE WEB PROJECT DOESN'T GET SPLIT UP ** * * @param kw * @return */ public abstract double kimberlingWeight(AlgoKimberlingWeightsParams kw); /** * This method is to be overridden in subclasses In Web, this can run in * asyncronous mode * * ** MUST STAY AS ABSTRACT OTHERWISE WEB PROJECT DOESN'T GET SPLIT UP ** * * @return AlgoCubicSwitchInterface */ public abstract AlgoCubicSwitchInterface getAlgoCubicSwitch(); /** * Needed for running part of AlgoKimberling async * * ** MUST STAY AS ABSTRACT OTHERWISE WEB PROJECT DOESN'T GET SPLIT UP ** * * @param kw * @return */ public abstract String cubicSwitch(AlgoCubicSwitchParams kw); public abstract CommandDispatcher getCommandDispatcher(Kernel k); /** * Should lose focus on Web applets, implement only where appropriate */ public void loseFocus() { Log.debug( "Should lose focus on Web applets, ipmelment (override) only where appropriate"); } /** * Whether the app is running just to create a screenshot, some * recomputations can be avoided in such case * * @return false by defaul, overridden in AppW */ public boolean isScreenshotGenerator() { return false; } public final boolean isErrorDialogsActive() { return isErrorDialogsActive; } public final void setErrorDialogsActive(boolean isErrorDialogsActive) { this.isErrorDialogsActive = isErrorDialogsActive; } /** * Recompute coord systems in EV and spreadsheet Only needed in web, * */ public void updateViewSizes() { // overwritten in AppW } public void persistWidthAndHeight() { // overwritten in AppW } protected AppCompanion newAppCompanion() { return new AppCompanion(this); } public AppCompanion getCompanion() { return companion; } public SensorLogger getSensorLogger() { return null; } public void registerOpenFileListener(OpenFileListener o) { if (openFileListener == null) { this.openFileListener = new ArrayList<OpenFileListener>(); } this.openFileListener.add(o); } public void unregisterOpenFileListener(OpenFileListener o) { if (openFileListener == null) { return; } this.openFileListener.remove(o); } protected void onOpenFile() { if (this.openFileListener != null) { for (OpenFileListener listener : openFileListener) { listener.onOpenFile(); } } } public boolean isShowingMultipleEVs() { if (getGuiManager() == null || getGuiManager().getEuclidianViewCount() < 2) { return false; } for (int i = 1; i < getGuiManager().getEuclidianViewCount(); i++) { if (getGuiManager().hasEuclidianView2(i)) { return true; } } return false; } public boolean isAllowPopups() { return allowPopUps; } public void setAllowPopups(boolean b) { allowPopUps = b; } /** * @param query * search query */ public void openSearch(String query) { // TODO Auto-generated method stub } /** * Adds a macro from XML * * @param xml * macro code (including <macro> wrapper) * @return True if successful */ public boolean addMacroXML(String xml) { boolean ok = true; try { getXMLio().processXMLString( "<geogebra format=\"" + GeoGebraConstants.XML_FILE_FORMAT + "\">" + xml + "</geogebra>", false, true); } catch (MyError err) { err.printStackTrace(); showError(err); ok = false; } catch (Exception e) { e.printStackTrace(); ok = false; showError("LoadFileFailed"); } return ok; } /** * Tells if given View is enabled. 3D be disabled by using command line * option "--show3D=disable". CAS be disabled by using command line option * "--showCAS=disable". * * @return whether the 3D view is enabled */ public boolean supportsView(int viewID) { if (viewID == App.VIEW_EUCLIDIAN3D) { return _3DViewEnabled && this.is3D(); } if (viewID == App.VIEW_CAS) { return CASViewEnabled; } return true; } public void ensureTimerRunning() { // only for Web } public abstract void showCustomizeToolbarGUI(); public abstract boolean isSelectionRectangleAllowed(); public final boolean has(Feature f) { boolean whiteboard = isWhiteboardActive(); switch (f) { // leave as prerelease case TUBE_BETA: return prerelease; // leave as prerelease case ALL_LANGUAGES: return prerelease; case SOLVE_QUARTIC: return prerelease; case AUTOMATIC_DERIVATIVES: return canary; case EXERCISES: return prerelease; // when moved to stable, move ImplicitSurface[] from TABLE_ENGLISH // in Command.Java case IMPLICIT_SURFACES: return prerelease; case CONTOUR_PLOT_COMMAND: return prerelease; case KOREAN_KEYBOARD: return prerelease; case LOCALSTORAGE_FILES: return prerelease || Versions.WEB_FOR_DESKTOP.equals(getVersion()); case POLYGON_TRIANGULATION: return false; case TOOL_EDITOR: return prerelease; // GGB-776 case ABSOLUTE_TEXTS: return prerelease; // TRAC-4845 case LOG_AXES: return prerelease; case HIT_PARAMETRIC_SURFACE: return false; case PARAMETRIC_SURFACE_IS_REGION: return prerelease; case CONVEX_HULL_3D: return canary; case DIFFERENT_AXIS_RATIO_3D: return prerelease; // GGB-335 case TOOLBAR_ON_SMALL_SCREENS: return prerelease; // MOW-29 case MOW_TOOLBAR: return prerelease && whiteboard;// prerelease; // MOB-270 case ACRA: return prerelease; case ANALYTICS: return prerelease; case HANDWRITING: return false; // GGB-92 case AV_DEFINITION_AND_VALUE: if (isDesktop()) { return false; } if (isAndroid()) { return false; } return true; // GGB-1357 case AV_SINGLE_TAP_EDIT: return true; case DATA_COLLECTION: if (version != null && version != Versions.WEB_FOR_DESKTOP) { return true; } return false; // in web (not tablet apps yet) // File -> Enter Exam Mode case EXAM_TABLET: return prerelease; case SAVE_SETTINGS_TO_FILE: // not enabled for linux return isWindows() || isMacOS() || prerelease; // GGB-334, TRAC-3401 case ADJUST_WIDGETS: return prerelease ;// && Versions.ANDROID_NATIVE_GRAPHING.equals(getVersion()); // GGB-1288 case ADJUST_VIEWS: return true; // GGB-944 case EXPORT_ANIMATED_PDF: return prerelease; // MOB-601 case MOBILE_LOCAL_SAVE: return prerelease; //AND-217 case MOBILE_AV_EDITOR: return false; // GGB-790 case AV_INPUT_BUTTON_COVER: return true; // MOB-788 case MOBILE_USE_FBO_FOR_3D_IMAGE_EXPORT: return false; case DRAGGING_NON_MOVEABLE_OBJECT_SPIN_THE_VIEW: return true; case ONSCREEN_KEYBOARD_AT_EDIT_SV_CELLS: return prerelease; case ONSCREEN_KEYBOARD_AT_PROBCALC: return prerelease; // GGB-1349 case FIX_KEYBOARD_POSITION: return prerelease; case AUTOSCROLLING_SPREADSHEET: return prerelease; // GGB-1252 case KEYBOARD_BEHAVIOUR: return prerelease; case WHITEBOARD_APP: return prerelease; case MOBILE_CACHE_FEATURED: return prerelease; // MOB-961, MOB-962 case BIND_ANDROID_TO_EXAM_APP: return true; // MOB-1005 case MOBILE_DO_NOT_AUTOSYNC_APPS: return true; // 5.0.299 // related to MOB-1005 case MOBILE_ASK_WHICH_APP_SHOULD_OPEN: return false; // related to MOB-1005 case MOBILE_OPEN_IN_RELEVANT_APP: return false; //EXAM-10 case EXAM_ANDROID_CHECK_SCREEN_STATE: return true; case READ_OBJECT_NAME_AT_SELECTING: return prerelease; case SHOW_ONE_KEYBOARD_BUTTON_IN_FRAME: return prerelease; case ERASER: return prerelease; case ROUNDED_POLYGON: return prerelease; case CONTEXT_MENU: return prerelease && whiteboard; case DIALOGS_OVERLAP_KEYBOARD: // see comment at GPopupPanel.setOverlapFeature return prerelease; case AV_TEXT_BLACK: return true; case DYNAMIC_STYLEBAR: return prerelease && whiteboard; /** MOW-55 */ case BOUNDING_BOXES: return prerelease && whiteboard; case PEN_IS_LOCUS: return prerelease; case PEN_EVENTS: return false; case PEN_SMOOTHING: return prerelease; case AXES_STYLE_SUBMENU: return prerelease && whiteboard; case FILE_CONTROLS: return prerelease; case IMPROVE_CONTEXT_MENU: return prerelease && whiteboard; case CLEAR_VIEW_STYLEBAR: return prerelease && whiteboard; case COLORPOPUP_IMPROVEMENTS: return prerelease; case TABBED_KEYBOARD: return prerelease; case KEYBOARD_MESSED_WITH_OLD_INPUTBAR: return prerelease; case AND_TRACE_IN_PROPERTIES: return true; // 5.0.356 case AND_GEOMETRY_IN_MATH_APPS_MENU: return prerelease; /** GGB-1679 5.0.357.0 */ case ADVANCED_OPTIONS: return true; case DIRECT_FORMULA_CONVERSION: return false; case FIXED_OBJECTS_EDITABLE: return prerelease; case AV_CONTEXT_MENU: return prerelease; case AV_MORE_MENU: return prerelease; case AV_PLAY_ONLY: return prerelease; case AV_PLUS: return prerelease; /** GGB-1710 */ case NINVERT: return true; /** GGB-1499 */ case ONE_VAR_FREQUENCY_TABLE: return true; case EQUATION_LIST: return prerelease; case AND_KILL_TOOLBAR: return false; case SWITCH_BETWEEN_KEYBOARD_LANGUAGE: return prerelease; case LOCKED_GEO_HAVE_DYNAMIC_STYLEBAR: return prerelease; case TICK_NUMBERS_AT_EDGE: return prerelease; case STORE_IMAGES_ON_APPS_PICKER: return prerelease; case NEW_TOOLBAR: return false; default: Log.debug("missing case in Feature: " + f); return false; } } public boolean isWhiteboardActive() { return false; } public boolean canResize() { return !isApplet() && has(Feature.ADJUST_VIEWS); } /** * * @return true if we want to use shaders */ public boolean useShaders() { return false; } public final int getTubeId() { return tubeID; } public final void setTubeId(int uniqueId) { this.tubeID = uniqueId; } public boolean hasFocus() { return true; } final public boolean hasEuclidianViewForPlane() { return companion.hasEuclidianViewForPlane(); } final public boolean hasEuclidianViewForPlaneVisible() { return companion.hasEuclidianViewForPlaneVisible(); } final public EuclidianView getViewForPlaneVisible() { return companion.getViewForPlaneVisible(); } /** * add to views for plane (if any) * * @param geo * geo */ final public void addToViewsForPlane(GeoElement geo) { companion.addToViewsForPlane(geo); } public boolean isModeValid(int mode) { return !"".equals(getToolName(mode)); } public void updateKeyboard() { // TODO Auto-generated method stub } /** * handle space key hitted * * @return true if key is consumed */ public boolean handleSpaceKey() { ArrayList<GeoElement> selGeos = selection.getSelectedGeos(); if (selGeos.size() == 1) { GeoElement geo = selGeos.get(0); if (geo.isGeoBoolean()) { GeoBoolean geoBool = (GeoBoolean) selGeos.get(0); geoBool.setValue(!geoBool.getBoolean()); geoBool.updateRepaint(); } else if (geo.isGeoInputBox()) { getActiveEuclidianView() .focusAndShowTextField((GeoInputBox) geo); } else if (geo.isGeoList() && ((GeoList) geo).drawAsComboBox()) { Drawable d = (Drawable) getActiveEuclidianView() .getDrawableFor(geo); ((DrawDropDownList) d).toggleOptions(); } else { geo.runClickScripts(null); } return true; } return false; } public void setAltText() { // ignored in desktop } /** * remove from views for plane (if any) * * @param geo * geo */ final public void removeFromViewsForPlane(GeoElement geo) { companion.removeFromViewsForPlane(geo); } public int getFontSizeWeb() { return Math.max(getFontSize(), 12); } /** * @return if sliders are displayed in the AV */ public boolean showAutoCreatedSlidersInEV() { return true; } public ExamEnvironment getExam() { return exam; } public boolean isExam() { return exam != null; } public void setExam(ExamEnvironment exam) { this.exam = exam; } public void setNewExam() { setExam(new ExamEnvironment()); } /** * @param lang * locale description */ public void setLanguage(String lang) { // overridden in subtypes } public void isShowingLogInDialog() { // TODO Auto-generated method stub } public void forEachView(ViewCallback c) { if (getGuiManager().showView(App.VIEW_ALGEBRA)) { c.run(App.VIEW_ALGEBRA, "AlgebraWindow"); } if (getGuiManager().showView(App.VIEW_CAS)) { c.run(App.VIEW_CAS, "CAS"); } if (getGuiManager().showView(App.VIEW_SPREADSHEET)) { c.run(App.VIEW_SPREADSHEET, "Spreadsheet"); } if (getGuiManager().showView(App.VIEW_EUCLIDIAN)) { c.run(App.VIEW_EUCLIDIAN, "DrawingPad"); } if (getGuiManager().showView(App.VIEW_EUCLIDIAN2)) { c.run(App.VIEW_EUCLIDIAN2, "DrawingPad2"); } if (getGuiManager().showView(App.VIEW_CONSTRUCTION_PROTOCOL)) { c.run(App.VIEW_CONSTRUCTION_PROTOCOL, "ConstructionProtocol"); } if (getGuiManager().showView(App.VIEW_DATA_ANALYSIS)) { c.run(App.VIEW_DATA_ANALYSIS, "DataAnalysis"); } } public String getInput3DType() { return Input3DConstants.PREFS_NONE; } public abstract void closePopups(); public void closePopups(int x, int y) { closePopups(); getActiveEuclidianView().closeDropDowns(x, y); } public String getExportTitle() { String title = getKernel().getConstruction().getTitle(); return "".equals(title) ? "geogebra-export" : title; } public double getExportScale() { return this.exportScale; } /** * Creates a new Timer. * * @param delay * Milliseconds to run timer after start()1. * @return GTimer descendant instance. */ public abstract GTimer newTimer(GTimerListener listener, int delay); /** * possible positions for the inputBar (respective inputBox) */ public enum InputPosition { /** * inputBox in the AV */ algebraView, /** * inputBar at the top */ top, /** * inputBar at the bottom */ bottom } public enum ExportType { NONE, PDF_TEXTASSHAPES, PDF_EMBEDFONTS, EPS, EMF, PNG, PNG_BRAILLE, SVG, PRINTING; public char getAxisMinusSign() { switch (this) { case PDF_EMBEDFONTS: case PNG_BRAILLE: return '-'; default: return Unicode.nDash; } } } /** * state to know if we'll need to store undo info */ private enum StoreUndoInfoForSetCoordSystem { /** tells that the mouse has been pressed */ MAY_SET_COORD_SYSTEM, /** tells that the coord system has changed */ SET_COORD_SYSTEM_OCCURED, /** no particular state */ NONE } public interface ViewCallback { public void run(int viewID, String viewName); } final public boolean loadXML(byte[] zipFile) { try { // make sure objects are displayed in the correct View setActiveView(App.VIEW_EUCLIDIAN); getXMLio().readZipFromString(zipFile); kernel.initUndoInfo(); setSaved(); setCurrentFile(null); // command list may have changed due to macros updateCommandDictionary(); hideDockBarPopup(); return true; } catch (Exception err) { setCurrentFile(null); err.printStackTrace(); return false; } } abstract public void setCurrentFile(Object file); protected void hideDockBarPopup() { // only used in desktop } public void schedulePreview(Runnable scheduledPreview) { // this is basic implementation with no scheduled delay scheduledPreview.run(); } public void cancelPreview() { // not needed in basic implementation } static final protected long SCHEDULE_PREVIEW_DELAY_IN_MILLISECONDS = 500; public String getURLforID(String id) { String url; if (has(Feature.TUBE_BETA)) { url = GeoGebraConstants.GEOGEBRA_WEBSITE_BETA; } else { url = GeoGebraConstants.GEOGEBRA_WEBSITE; } // something like // http://www.geogebra.org/files/material-1264825.mp3 url = url + "material/download/format/file/id/" + id; return url; } public ErrorHandler getErrorHandler() { return getDefaultErrorHandler(); } public ErrorHandler getDefaultErrorHandler() { return ErrorHelper.silent(); } /** * * @return true if running in native "desktop" Java */ public boolean isDesktop() { return false; } /** * * @return true if running on native Android (not WebView) */ protected boolean isAndroid() { return false; } public void setRounding(String rounding) { if (rounding.length() > 0) { StringBuilder roundingNum = new StringBuilder("0"); for (int i = 0; i < rounding.length(); i++) { if (rounding.charAt(i) <= '9' && rounding.charAt(i) >= '0') { roundingNum.append(rounding.charAt(i)); } } int roundInt = Integer.parseInt(roundingNum.toString()); if (rounding.contains("s")) { getKernel().setPrintFigures(roundInt); } else { getKernel().setPrintDecimals(roundInt); } if (rounding.contains("r")) { GeoElement defNumber = getKernel().getConstruction() .getConstructionDefaults() .getDefaultGeo(ConstructionDefaults.DEFAULT_NUMBER); if (defNumber != null) { ((GeoNumeric) defNumber).setSymbolicMode(true, false); } } } } public void examWelcome() { // TODO Auto-generated method stub } public GBufferedImage getActiveEuclidianViewExportImage(double maxX, double maxY) { return getEuclidianViewExportImage(getActiveEuclidianView(), maxX, maxY); } final static protected GBufferedImage getEuclidianViewExportImage( EuclidianView ev, double maxX, double maxY) { double scale = Math.min(maxX / ev.getSelectedWidthInPixels(), maxY / ev.getSelectedHeightInPixels()); return ev.getExportImage(scale); } public void batchUpdateStart() { // used in android } public void batchUpdateEnd() { // used in android } public void adjustScreen(boolean reset) { if (!kernel.getApplication().has(Feature.ADJUST_WIDGETS)) { return; } if (adjustScreen == null) { adjustScreen = new AdjustScreen(getEuclidianView1()); } if (!reset) { adjustScreen.restartButtons(); } adjustScreen.apply(reset); if (this.hasEuclidianView2(1)) { if (adjustScreen2 == null) { adjustScreen2 = new AdjustScreen(getEuclidianView2(1)); } if (!reset) { adjustScreen2.restartButtons(); } adjustScreen2.apply(reset); } } /** * Adjusts Algebra and Euclidian View next to or bellow each other * (Portrait) according to app size. * * @return if screen became portrait or not. */ public boolean adjustViews(boolean reset) { if (!has(Feature.ADJUST_VIEWS)) { return false; } if (adjustViews == null) { adjustViews = new AdjustViews(this); } adjustViews.apply(); adjustScreen(reset); return adjustViews.isPortait(); } public Versions getVersion() { return version; } final public static String getLabelStyleName(App app, int id) { switch (id) { case (-1): return app.getLocalization().getPlain("Hidden"); case (GeoElement.LABEL_NAME): return app.getLocalization().getPlain("Name"); case (GeoElement.LABEL_NAME_VALUE): return app.getLocalization().getPlain("NameAndValue"); case (GeoElement.LABEL_VALUE): return app.getLocalization().getPlain("Value"); case (GeoElement.LABEL_CAPTION): return app.getLocalization().getPlain("Caption"); default: return ""; } } /** * static so that you can copy & paste between instances */ public static volatile CopyPaste copyPaste = null; public CopyPaste getCopyPaste() { // return 2D version in AppD, AppW, AppWSimple if (copyPaste == null) { copyPaste = new CopyPaste3D(); } return copyPaste; } /** * Update view settings with size from XML * * @param evSet * view settings */ public void ensureEvSizeSet(EuclidianSettings evSet) { // only for applets } /** * * @return 9999 (or 200 in web) */ public int getMaxSpreadsheetRowsVisible() { return Kernel.MAX_SPREADSHEET_ROWS_DESKTOP; } /** * * @return 9999 (or 200 in web) */ public int getMaxSpreadsheetColumnsVisible() { return Kernel.MAX_SPREADSHEET_COLUMNS_DESKTOP; } public boolean singularWSisAvailable() { return singularWS != null && singularWS.isAvailable(); } public String singularWSgetTranslatedCASCommand(String s) { if (singularWS == null) { return null; } return singularWS.getTranslatedCASCommand(s); } public String singularWSdirectCommand(String s) throws Throwable { if (singularWS == null) { return null; } return singularWS.directCommand(s); } abstract public void invokeLater(Runnable runnable); /** * * @return GeoGebraToPstricks object */ public GeoGebraToPstricks newGeoGebraToPstricks() { // overridden in AppD, AppW return null; } /** * * @return GeoGebraToAsymptote object */ public GeoGebraToAsymptote newGeoGebraToAsymptote() { // overridden in AppD, AppW return null; } /** * * @return GeoGebraToPgf object */ public GeoGebraToPgf newGeoGebraToPgf() { // overridden in AppD, AppW return null; } /** * @param text * text to be copied */ public void copyTextToSystemClipboard(String text) { // overridden in AppD, AppW } //////////////////////////////////////////////////// // last commands selected from help (used in Android & iOS native) //////////////////////////////////////////////////// private ArrayList<String> mLastCommandsSelectedFromHelp; public void addToLastCommandsSelectedFromHelp(String commandName) { if (mLastCommandsSelectedFromHelp == null) { mLastCommandsSelectedFromHelp = new ArrayList<String>(); } // remove if already in it mLastCommandsSelectedFromHelp.remove(commandName); mLastCommandsSelectedFromHelp.add(commandName); } public ArrayList<String> getLastCommandsSelectedFromHelp() { return mLastCommandsSelectedFromHelp; } protected EuclidianController getEuclidianController() { return euclidianController; } final public boolean useTransparentCursorWhenDragging() { return useTransparentCursorWhenDragging; } public AlgoKimberlingWeightsInterface getKimberlingw() { return kimberlingw; } public AlgoKimberlingWeightsInterface setKimberlingw(AlgoKimberlingWeightsInterface kimberlingw) { this.kimberlingw = kimberlingw; return kimberlingw; } public AlgoCubicSwitchInterface getCubicw() { return cubicw; } public AlgoCubicSwitchInterface setCubicw(AlgoCubicSwitchInterface cubicw) { this.cubicw = cubicw; return cubicw; } /** * SMART and Android WebView apps use special native Giac Other web apps use * giac.js GGB6 WebView uses giac.js for now, see GGB-895 Everything else * uses native Giac * * @return true if using native Giac, false if using giac.js */ public boolean nativeCAS() { return true; } }