/*
GeoGebra - Dynamic Mathematics for Everyone
http://www.geogebra.org
This file is part of GeoGebra.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation.
*/
/**
* GeoGebra Application
*
* @author Markus Hohenwarter
*/
package org.geogebra.desktop.main;
import java.awt.AWTKeyStroke;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.SystemColor;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ComponentEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import javax.imageio.ImageIO;
import javax.naming.OperationNotSupportedException;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import org.geogebra.common.GeoGebraConstants;
import org.geogebra.common.GeoGebraConstants.Versions;
import org.geogebra.common.awt.GDimension;
import org.geogebra.common.awt.GFont;
import org.geogebra.common.awt.MyImage;
import org.geogebra.common.euclidian.EuclidianConstants;
import org.geogebra.common.euclidian.EuclidianController;
import org.geogebra.common.euclidian.EuclidianCursor;
import org.geogebra.common.euclidian.EuclidianView;
import org.geogebra.common.euclidian.EuclidianViewInterfaceCommon;
import org.geogebra.common.euclidian.event.AbstractEvent;
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.factories.FormatFactory;
import org.geogebra.common.factories.LaTeXFactory;
import org.geogebra.common.factories.UtilFactory;
import org.geogebra.common.gui.toolbar.ToolBar;
import org.geogebra.common.gui.view.algebra.AlgebraView;
import org.geogebra.common.io.OFFHandler;
import org.geogebra.common.io.layout.DockPanelData;
import org.geogebra.common.io.layout.Perspective;
import org.geogebra.common.io.layout.PerspectiveDecoder;
import org.geogebra.common.javax.swing.GImageIcon;
import org.geogebra.common.jre.factory.FormatFactoryJre;
import org.geogebra.common.jre.util.Base64;
import org.geogebra.common.kernel.Construction;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.Macro;
import org.geogebra.common.kernel.barycentric.AlgoCubicSwitch;
import org.geogebra.common.kernel.barycentric.AlgoKimberlingWeights;
import org.geogebra.common.kernel.commands.CommandDispatcher;
import org.geogebra.common.kernel.geos.AnimationExportSlider;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoElementGraphicsAdapter;
import org.geogebra.common.main.AlgoCubicSwitchInterface;
import org.geogebra.common.main.AlgoCubicSwitchParams;
import org.geogebra.common.main.AlgoKimberlingWeightsInterface;
import org.geogebra.common.main.AlgoKimberlingWeightsParams;
import org.geogebra.common.main.App;
import org.geogebra.common.main.DialogManager;
import org.geogebra.common.main.MyError;
import org.geogebra.common.main.ProverSettings;
import org.geogebra.common.main.SingularWSSettings;
import org.geogebra.common.main.SpreadsheetTableModel;
import org.geogebra.common.main.error.ErrorHandler;
import org.geogebra.common.move.ggtapi.models.json.JSONObject;
import org.geogebra.common.move.ggtapi.models.json.JSONTokener;
import org.geogebra.common.move.ggtapi.operations.OpenFromGGTOperation;
import org.geogebra.common.plugin.ScriptManager;
import org.geogebra.common.plugin.SensorLogger;
import org.geogebra.common.util.AsyncOperation;
import org.geogebra.common.util.Charsets;
import org.geogebra.common.util.CopyPaste;
import org.geogebra.common.util.FileExtensions;
import org.geogebra.common.util.GTimer;
import org.geogebra.common.util.GTimerListener;
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.debug.Log.LogDestination;
import org.geogebra.common.util.lang.Language;
import org.geogebra.desktop.CommandLineArguments;
import org.geogebra.desktop.GeoGebra;
import org.geogebra.desktop.awt.GBufferedImageD;
import org.geogebra.desktop.awt.GDimensionD;
import org.geogebra.desktop.awt.GFontD;
import org.geogebra.desktop.euclidian.DrawEquationD;
import org.geogebra.desktop.euclidian.EuclidianControllerD;
import org.geogebra.desktop.euclidian.EuclidianViewD;
import org.geogebra.desktop.euclidian.event.MouseEventD;
import org.geogebra.desktop.euclidian.event.MouseEventND;
import org.geogebra.desktop.euclidianND.EuclidianViewInterfaceD;
import org.geogebra.desktop.export.GeoGebraTubeExportD;
import org.geogebra.desktop.export.PrintPreviewD;
import org.geogebra.desktop.export.pstricks.GeoGebraToAsymptoteD;
import org.geogebra.desktop.export.pstricks.GeoGebraToPgfD;
import org.geogebra.desktop.export.pstricks.GeoGebraToPstricksD;
import org.geogebra.desktop.factories.AwtFactoryD;
import org.geogebra.desktop.factories.CASFactoryD;
import org.geogebra.desktop.factories.FactoryD;
import org.geogebra.desktop.factories.LaTeXFactoryD;
import org.geogebra.desktop.factories.UtilFactoryD;
import org.geogebra.desktop.gui.GuiManagerD;
import org.geogebra.desktop.gui.MyImageD;
import org.geogebra.desktop.gui.app.GeoGebraFrame;
import org.geogebra.desktop.gui.dialog.AxesStyleListRenderer;
import org.geogebra.desktop.gui.dialog.DashListRenderer;
import org.geogebra.desktop.gui.dialog.DecorationListRenderer;
import org.geogebra.desktop.gui.dialog.PointStyleListRenderer;
import org.geogebra.desktop.gui.dialog.options.OptionsAdvancedD;
import org.geogebra.desktop.gui.inputbar.AlgebraInputD;
import org.geogebra.desktop.gui.layout.DockBar;
import org.geogebra.desktop.gui.layout.DockPanelD;
import org.geogebra.desktop.gui.layout.LayoutD;
import org.geogebra.desktop.gui.toolbar.ToolbarContainer;
import org.geogebra.desktop.gui.toolbar.ToolbarD;
import org.geogebra.desktop.gui.util.ImageSelection;
import org.geogebra.desktop.io.MyXMLioD;
import org.geogebra.desktop.io.OFFReader;
import org.geogebra.desktop.javax.swing.GImageIconD;
import org.geogebra.desktop.kernel.UndoManagerD;
import org.geogebra.desktop.kernel.geos.GeoElementGraphicsAdapterD;
import org.geogebra.desktop.move.ggtapi.models.LoginOperationD;
import org.geogebra.desktop.plugin.GgbAPID;
import org.geogebra.desktop.plugin.ScriptManagerD;
import org.geogebra.desktop.plugin.UDPLoggerD;
import org.geogebra.desktop.sound.SoundManagerD;
import org.geogebra.desktop.util.FrameCollector;
import org.geogebra.desktop.util.GTimerD;
import org.geogebra.desktop.util.GuiResourcesD;
import org.geogebra.desktop.util.ImageManagerD;
import org.geogebra.desktop.util.ImageResourceD;
import org.geogebra.desktop.util.LoggerD;
import org.geogebra.desktop.util.Normalizer;
import org.geogebra.desktop.util.StringUtilD;
import org.geogebra.desktop.util.UtilD;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@SuppressWarnings("javadoc")
public class AppD extends App implements KeyEventDispatcher {
/**
* License file
*/
public static final String LICENSE_FILE = "/org/geogebra/desktop/_license.txt";
/**
* Command line arguments
*/
protected CommandLineArguments cmdArgs;
// ==============================================================
// JAR fields
// ==============================================================
/**
* Possible alternative names for geogebra.jar. Used for 3D webstart at the
* moment.
*/
public final static String[] GEOGEBRA_JAR_ALT = { "geogebra.jar",
"geogebra-jogl2.jar" };
// ==============================================================
// LOCALE fields
// ==============================================================
// ==============================================================
// FILE fields
// ==============================================================
private static LinkedList<File> fileList = new LinkedList<File>();
protected File currentPath, currentImagePath, currentFile = null;
/** maximum number of files to (save &) show in File -> Recent submenu */
public static final int MAX_RECENT_FILES = 8;
// ==============================================================
// RESOURCE fields
// ==============================================================
private ResourceBundle rbmenuEnglish;
private final LocalizationD loc;
// ==============================================================
// APPLET fields
// ==============================================================
private static volatile AppletImplementation appletImpl;
private static Object lock = new Object();
private boolean isApplet = false;
// ==============================================================
// GUI fields
// ==============================================================
private JFrame frame;
/** Main component */
protected Component mainComp;
/** Panels that form the main content panel */
protected JPanel centerPanel, northPanel, southPanel, eastPanel, westPanel;
/**
* Split pane panel that holds main content panel and a slide-out sidebar
* help panel for the input bar.
*/
private JSplitPane applicationSplitPane;
private DockBarInterface dockBar;
private boolean showDockBar = true;
private boolean isDockBarEast = true;
protected boolean showAlgebraView = true;
/**
* Preferred application frame size. Used in case frame size needs updating.
*/
private Dimension preferredSize = new Dimension();
/** Horizontal page margin in cm */
public static final double PAGE_MARGIN_X = (1.8 * 72) / 2.54;
/** Vertical page margin in cm */
public static final double PAGE_MARGIN_Y = (1.8 * 72) / 2.54;
/** Default icon size */
public static final int DEFAULT_ICON_SIZE = 32;
/**
* made a little darker in ggb40 (problem showing on some projectors)
*/
public static final Color COLOR_SELECTION = new Color(210, 210, 225);
// ==============================================================
// MODEL & MANAGER fields
// ==============================================================
private final FontManagerD fontManager;
/** GUI manager */
protected GuiManagerInterfaceD guiManager;
private GlobalKeyDispatcherD globalKeyDispatcher;
protected ImageManagerD imageManager;
private GgbAPID ggbapi = null;
private SpreadsheetTableModelD tableModel;
// ==============================================================
// MISC FLAGS
// ==============================================================
private boolean allowToolTips = true;
protected boolean isErrorDialogShowing = false;
public boolean macsandbox = false;
/*************************************************************
* Construct application within JFrame
*
* @param args
* @param frame
* @param undoActive
*/
public AppD(CommandLineArguments args, JFrame frame, boolean undoActive) {
this(args, frame, null, null, undoActive, new LocalizationD(2));
}
/*************************************************************
* Construct application within Applet
*
* @param args
* @param appletImpl
* @param undoActive
*/
public AppD(CommandLineArguments args, AppletImplementation appletImpl,
boolean undoActive) {
this(args, null, appletImpl, null, undoActive, new LocalizationD(2));
}
/*************************************************************
* Construct application within Container (e.g. GeoGebraPanel)
*
* @param args
* @param comp
* @param undoActive
*/
public AppD(CommandLineArguments args, Container comp, boolean undoActive) {
this(args, null, null, comp, undoActive, new LocalizationD(2));
}
/*************************************************************
* GeoGebra application general constructor
*
* @param args
* @param frame
* @param appletImpl
* @param comp
* @param undoActive
*/
public AppD(CommandLineArguments args, JFrame frame,
AppletImplementation appletImpl, Container comp, boolean undoActive,
LocalizationD loc) {
super(Versions.DESKTOP);
this.loc = loc;
loc.setApp(this);
this.cmdArgs = args;
if (args != null && !args.containsArg("silent")) {
Log.setLogger(new LoggerD());
Log.setLogDestination(LogDestination.CONSOLE);
if (args.containsArg("logLevel")) {
Log.setLogLevel(args.getStringValue("logLevel"));
}
if (args.containsArg("logFile")) {
Log.setLogDestination(LogDestination.FILE);
Log.setLogFile(args.getStringValue("logFile"));
}
if (args.containsArg("logShowCaller")) {
Log.setCallerShown(args.getBooleanValue("logShowCaller", true));
}
if (args.containsArg("logShowTime")) {
Log.setTimeShown(args.getBooleanValue("logShowTime", true));
}
if (args.containsArg("logShowLevel")) {
Log.setLevelShown(args.getBooleanValue("logShowLevel", true));
}
}
this.prerelease = args != null && (args.containsArg("prerelease")
|| args.containsArg("canary"));
this.canary = args != null && args.containsArg("canary");
if (canary) {
Log.error("*****************************");
Log.error("*** Running with --canary ***");
Log.error("*****************************");
} else if (prerelease) {
Log.error("*********************************");
Log.error("*** Running with --prerelease ***");
Log.error("*********************************");
}
setFileVersion(GeoGebraConstants.VERSION_STRING);
if (args != null) {
handleHelpVersionArgs(args);
}
isApplet = appletImpl != null;
JApplet applet = null;
if (frame != null) {
mainComp = frame;
} else if (isApplet) {
applet = appletImpl.getJApplet();
mainComp = applet;
setApplet(appletImpl);
} else {
mainComp = comp;
}
useFullGui = !isApplet || appletImpl.needsGui();
// don't want to redirect System.out and System.err when running as
// Applet
// or eg from Eclipse
getCodeBase(); // initialize runningFromJar
Log.debug("isApplet=" + isApplet + " runningFromJar=" + runningFromJar
+ " appletImpl=" + appletImpl);
if (!isApplet && runningFromJar) {
setUpLogging();
} else {
Log.debug("Not setting up logging via LogManager");
}
// needed for JavaScript getCommandName(), getValueString() to work
// (security problem running non-locally)
if (isApplet) {
preferredSize = appletImpl.getJApplet().getSize();
// needs command.properties in main.jar
// causes problems when not in English
// initCommandBundle();
} else {
preferredSize = new Dimension(800, 600);
}
fontManager = new FontManagerD();
initImageManager(mainComp);
// set locale
setLocale(mainComp.getLocale());
// init kernel
initFactories();
initKernel();
kernel.setPrintDecimals(Kernel.STANDARD_PRINT_DECIMALS);
// init settings
settings = companion.newSettings();
// init euclidian view
initEuclidianViews();
// load file on startup and set fonts
// set flag to avoid multiple calls of setLabels() and
// updateContentPane()
initing = true;
// setFontSize(12);
// This is needed because otherwise Exception might come and
// GeoGebra may exit. (dockPanel not entirely defined)
// This is needed before handleFileArg because
// we don't want to redefine the toolbar string from the file.
boolean ggtloading = isLoadingTool(args);
// init default preferences if necessary
if (!isApplet) {
GeoGebraPreferencesD.getPref().initDefaultXML(this);
}
if (ggtloading) {
if (!isApplet) {
GeoGebraPreferencesD.getPref().loadXMLPreferences(this);
}
}
// open file given by startup parameter
handleOptionArgsEarly(args); // for --regressionFile=...
// here we initialize SingularWS
// for a better approach see [22746] --- but it would break file loading
// at the moment
initializeSingularWSD();
boolean fileLoaded = handleFileArg(args);
// initialize GUI
if (isUsingFullGui()) {
initGuiManager();
// set frame
if (!isApplet && (frame != null)) {
setFrame(frame);
}
}
if (!isApplet) {
// load XML preferences
currentPath = GeoGebraPreferencesD.getPref().getDefaultFilePath();
currentImagePath = GeoGebraPreferencesD.getPref()
.getDefaultImagePath();
if (!fileLoaded && !ggtloading) {
GeoGebraPreferencesD.getPref().loadXMLPreferences(this);
imageManager.setMaxIconSizeAsPt(getFontSize());
}
if (MAC_OS) {
String path = System.getProperty("user.home") + "/Documents";
if (currentPath == null) {
currentPath = new File(path);
}
if (currentImagePath == null) {
currentImagePath = new File(path);
}
}
}
if (isUsingFullGui() && (tmpPerspectives != null)) {
getGuiManager().getLayout()
.setPerspectives(tmpPerspectives, PerspectiveDecoder.decode(
this.perspectiveParam, getKernel().getParser(),
ToolBar.getAllToolsNoMacros(false, false, this)));
}
if (needsSpreadsheetTableModel) {
// if tableModel==null, will create one
getSpreadsheetTableModel();
}
if (isUsingFullGui() && ggtloading) {
getGuiManager().setToolBarDefinition(ToolbarD.getAllTools(this));
}
setUndoActive(undoActive);
// applet/command line options
handleOptionArgs(args);
initing = false;
// for key listening
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(this);
if (!isApplet()) {
getScriptManager().ggbOnInit();
getFactory();
}
setSaved();
if (getCASVersionString().equals("")) {
setCASVersionString(loc.getMenu("CASInitializing"));
}
if (!isApplet()) {
// user authentication handling
initSignInEventFlow();
}
if (kernel.wantAnimationStarted()) {
kernel.getAnimatonManager().startAnimation();
kernel.setWantAnimationStarted(false);
}
}
// **************************************************************************
// INIT
// **************************************************************************
public void setApplet(AppletImplementation appletImpl0) {
isApplet = true;
synchronized (lock) {
AppD.appletImpl = appletImpl0;
}
mainComp = appletImpl.getJApplet();
}
public AppletImplementation getApplet() {
return appletImpl;
}
@Override
public void reset() {
if (appletImpl != null) {
appletImpl.reset();
} else if (currentFile != null) {
loadFile(this, currentFile);
} else {
clearConstruction();
}
}
public void setFrame(JFrame frame) {
isApplet = false;
mainComp = frame;
this.frame = frame;
updateTitle();
// Windows 7 uses this for the Toolbar icon too
// (needs to be larger)
frame.setIconImage(getInternalImage(GuiResourcesD.GEOGEBRA64));
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
WindowListener[] wl = frame.getWindowListeners();
if ((wl == null) || (wl.length == 0)) {
// window closing listener
WindowAdapter windowListener = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent event) {
exit();
}
};
frame.addWindowListener(windowListener);
}
}
/**
* Sets the look and feel.
*
* @param isSystemLAF
* true => set system LAF, false => set cross-platform LAF
*/
public static void setLAF(boolean isSystemLAF) {
try {
if (isSystemLAF) {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} else {
UIManager.setLookAndFeel(
UIManager.getCrossPlatformLookAndFeelClassName());
}
} catch (Exception e) {
Log.debug(e + "");
}
}
/**
* Toggles between the system LAF and the cross-platform LAF
*/
public static void toggleCrossPlatformLAF() {
setLAF(!UIManager.getLookAndFeel().isNativeLookAndFeel());
}
/**
* init factories
*/
protected void initFactories() {
if (AwtFactory.getPrototype() == null) {
AwtFactory.setPrototypeIfNull(new AwtFactoryD());
}
if (FormatFactory.getPrototype() == null) {
FormatFactory.setPrototypeIfNull(new FormatFactoryJre());
}
if (LaTeXFactory.getPrototype() == null) {
LaTeXFactory.setPrototypeIfNull(new LaTeXFactoryD());
}
if (UtilFactory.getPrototype() == null) {
UtilFactory.setPrototypeIfNull(new UtilFactoryD());
}
if (StringUtil.getPrototype() == null) {
StringUtil.setPrototypeIfNull(new StringUtilD());
}
}
private static void handleHelpVersionArgs(CommandLineArguments args) {
System.out.println("GeoGebra " + GeoGebraConstants.VERSION_STRING + " "
+ GeoGebraConstants.BUILD_DATE + " Java " + getJavaVersion()
+ "\n");
if (args.containsArg("help")) {
// help message
System.out.println("Usage: java -jar geogebra.jar [OPTION] [FILE]\n"
+ "Start GeoGebra with the specified OPTIONs and open the given FILE.\n"
+ " --help\t\tprint this message\n"
+ " --v\t\tprint version\n"
+ " --language=LANGUAGE_CODE\t\tset language using locale strings, e.g. en, de, de_AT, ...\n" // here
// "auto"
// is
// also
// accepted
+ " --showAlgebraInput=BOOLEAN\tshow/hide algebra input field\n"
+ " --showAlgebraInputTop=BOOLEAN\tshow algebra input at top/bottom\n"
+ " --showAlgebraWindow=BOOLEAN\tshow/hide algebra window\n"
+ " --showSpreadsheet=BOOLEAN\tshow/hide spreadsheet\n"
+ " --showCAS=BOOLEAN\tshow/hide CAS window\n" // here
// "disable"
// is also
// accepted
+ " --show3D=BOOLEAN\tshow/hide 3D window\n" // here
// "disable"
// is
// also
// accepted
+ " --showSplash=BOOLEAN\tenable/disable the splash screen\n"
+ " --enableUndo=BOOLEAN\tenable/disable Undo\n"
+ " --fontSize=NUMBER\tset default font size\n"
+ " --showAxes=BOOLEAN\tshow/hide coordinate axes\n"
+ " --showGrid=BOOLEAN\tshow/hide grid\n"
+ " --settingsFile=PATH|FILENAME\tload/save settings from/in a local file\n"
+ " --resetSettings\treset current settings\n"
+ " --regressionFile=FILENAME\texport textual representations of dependent objects, then exit\n"
+ " --versionCheckAllow=SETTING\tallow version check (on/off or true/false for single launch)\n"
+ " --logLevel=LEVEL\tset logging level (EMERGENCY|ALERT|CRITICAL|ERROR|WARN|NOTICE|INFO|DEBUG|TRACE)\n"
+ " --logFile=FILENAME\tset log file\n"
+ " --silent\tCompletely mute logging\n"
+ " --prover=OPTIONS\tSet options for the prover subsystem (use --proverhelp for more information)\n"
/*
* +
* " --singularWS=OPTIONS\tSet options for SingularWS (use --singularWShelp for more information)\n"
*/
);
AppD.exit(0);
}
if (args.containsArg("proverhelp")) {
ProverSettings proverSettings = ProverSettings.get();
// help message for the prover
System.out.println(
" --prover=OPTIONS\tset options for the prover subsystem\n"
+ " where OPTIONS is a comma separated list, formed with the following available settings (defaults in brackets):\n"
+ " engine:ENGINE\tset engine (Auto|OpenGeoProver|Recio|Botana|PureSymbolic) ["
+ proverSettings.proverEngine + "]\n"
+ " timeout:SECS\tset the maximum time attributed to the prover (in seconds) ["
+ proverSettings.proverTimeout + "]\n"
+ " maxterms:NUMBER\tset the maximal number of terms ["
+ proverSettings.getMaxTerms()
+ "] (OpenGeoProver only)\n"
+ " method:METHOD\tset the method (Wu|Groebner|Area) ["
+ proverSettings.proverMethod
+ "] (OpenGeoProver/Recio only)\n"
/*
* +
* " fpnevercoll:BOOLEAN\tassume three free points are never collinear for Prove ["
* + ProverSettings.freePointsNeverCollinear +
* "] (Botana only, forced to 'yes' when SingularWS is unavailable)\n"
*/
+ " usefixcoords:NUMBER1NUMBER2\tuse fix coordinates for the first NUMBER1 for Prove and NUMBER2 for ProveDetails, maximum of 4 both ["
+ proverSettings.useFixCoordinatesProve
+ proverSettings.useFixCoordinatesProveDetails
+ "] (Botana only)\n"
/*
* +
* " transcext:BOOLEAN\tuse polynomial ring with coeffs from a transcendental extension for Prove ["
* + ProverSettings.transcext +
* "] (Botana only, needs SingularWS)\n"
*/
+ " captionalgebra:BOOLEAN\tshow algebraic debug information in object captions ["
+ proverSettings.captionAlgebra
+ "] (Botana only)\n"
+ " Example: --prover=engine:Botana,timeout:10,fpnevercoll:true,usefixcoords:43\n");
AppD.exit(0);
}
if (args.containsArg("singularWShelp")) {
// help message for singularWS
System.out.println(
" --singularWS=OPTIONS\tset options for SingularWS\n"
+ " where OPTIONS is a comma separated list, formed with the following available settings (defaults in brackets):\n"
+ " enable:BOOLEAN\tuse Singular WebService when possible ["
+ SingularWSSettings.useSingularWebService() + "]\n"
+ " remoteURL:URL\tset the remote server URL ["
+ SingularWSSettings
.getSingularWebServiceRemoteURL()
+ "]\n" + " timeout:SECS\tset the timeout ["
+ SingularWSSettings.getTimeout() + "]\n"
+ " caching:BOOLEAN\tset server side caching ["
+ SingularWSSettings.getCachingText() + "]\n"
+ " Example: singularWS=timeout:3\n");
AppD.exit(0);
}
if (args.containsArg("v")) {
AppD.exit(0);
}
}
@Override
public EuclidianController newEuclidianController(Kernel kernel1) {
return new EuclidianControllerD(kernel1);
}
@Override
protected EuclidianView newEuclidianView(boolean[] showAxesFlags,
boolean showGridFlags) {
return new EuclidianViewD(getEuclidianController(), showAxesFlags,
showGridFlags, getSettings().getEuclidian(1));
}
/**
* init the ImageManager (and ImageManager3D for 3D)
*
* @param component
*/
protected void initImageManager(Component component) {
imageManager = new ImageManagerD(component);
}
/**
* @return True if the whole GUI is available, false if just the euclidian
* view is displayed.
*/
@Override
final public synchronized boolean isUsingFullGui() {
return useFullGui;
}
/**
* Initialize the gui manager.
*/
@Override
final protected void initGuiManager() {
setWaitCursor();
guiManager = newGuiManager();
newLayout(this);
// guiManager.setLayout(new geogebra.gui.layout.LayoutD());
guiManager.initialize();
setDefaultCursor();
// make sure mouse events are NOT consumed when a popup menu is closed,
// see #2574
UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE);
}
// **************************************************************************
// COMMAND LINE ARGUMENTS
// **************************************************************************
/**
* Handles command line options
*/
private void handleOptionArgs(CommandLineArguments args) {
// args.containsArg("help");
if (args == null) {
return;
}
if (args.containsArg("showAlgebraInput")) {
boolean showInputBar = args.getBooleanValue("showAlgebraInput",
true);
if (!showInputBar) {
setShowAlgebraInput(false, false);
}
}
if (args.containsArg("showAlgebraInputTop")) {
boolean showAlgebraInputTop = args
.getBooleanValue("showAlgebraInputTop", true);
if (showAlgebraInputTop) {
setInputPosition(InputPosition.top, false);
}
}
String fontSize = args.getStringValue("fontSize");
if (fontSize.length() > 0) {
setFontSize(Util.getValidFontSize(Integer.parseInt(fontSize)),
true);
}
boolean enableUndo = args.getBooleanValue("enableUndo", true);
if (!enableUndo) {
setUndoActive(false);
}
if (args.containsArg("showAxes")) {
boolean showAxesParam = args.getBooleanValue("showAxes", true);
this.showAxes[0] = showAxesParam;
this.showAxes[1] = showAxesParam;
this.getSettings().getEuclidian(1).setShowAxes(showAxesParam,
showAxesParam);
this.getSettings().getEuclidian(2).setShowAxes(showAxesParam,
showAxesParam);
}
if (args.containsArg("showGrid")) {
boolean showGridParam = args.getBooleanValue("showGrid", false);
this.showGrid = showGridParam;
this.getSettings().getEuclidian(1).showGrid(showGridParam);
this.getSettings().getEuclidian(2).showGrid(showGridParam);
}
if (args.containsArg("giacJSONtests")) {
// set CAS timeout to 13 seconds
kernel.getApplication().getSettings().getCasSettings()
.setTimeoutMilliseconds(13000);
String filename = args.getStringValue("giacJSONtests");
if (filename == null || "".equals(filename)) {
filename = "../web/war/__giac.js";
}
int count = 0;
ArrayList<String> errors = new ArrayList<String>();
// Open the file
FileInputStream fstream;
try {
fstream = new FileInputStream(filename);
BufferedReader br = new BufferedReader(
new InputStreamReader(fstream, Charsets.UTF_8));
String strLine;
// Read File Line By Line
while ((strLine = br.readLine()) != null
&& (strLine.indexOf("JSONSTART") == -1)) {
// Print the content on the console
// System.out.println("IGNORE " + strLine);
}
while ((strLine = br.readLine()) != null
&& (strLine.indexOf("JSONEND") == -1)) {
// Print the content on the console
strLine = strLine.trim();
if (strLine.endsWith(",")) {
strLine = strLine.substring(0, strLine.length() - 1);
}
// System.out.println(strLine);
if (strLine.startsWith("{")) {
count++;
JSONTokener tokener = new JSONTokener(strLine);
JSONObject response = new JSONObject(tokener);
String command = (String) response.get("cmd");
String result = (String) response.get("result");
response.get("cat");
// System.out.println("response = " + response);
// System.out.println("result = " + result);
// command = "Solve[13^(x+1)-2*13^x=(1/5)*5^x,x]";
// result =
// "{-ln(55)/ln(13/5)}|OR|{x=(-ln(11)-ln(5))/(ln(13)-ln(5))}";
String casResult = getGgbApi().evalGeoGebraCAS(command);
String casResultOriginal = casResult;
// remove spaces
casResult = casResult.replace(" ", "");
result = result.replace(" ", "");
// sort out arbitrary constants
result = result.replaceAll("n_[0-9]*", "n_0");
result = result.replaceAll("c_[0-9]*", "c_0");
casResult = casResult
.replaceAll("arbconst\\([+0-9]*\\)", "c_0");
casResult = casResult
.replaceAll("arbint\\(([+0-9]*)\\)", "n_0");
String[] results = { result };
if (result.indexOf("|OR|") > -1) {
results = result.split("\\|OR\\|");
}
boolean OK = false;
// check if one of the answers matches
for (int i = 0; i < results.length; i++) {
if (casResult.equals(results[i])) {
OK = true;
break;
}
}
if (OK || "GEOGEBRAERROR".equals(result)
|| "RANDOM".equals(result)) {
Log.debug("OK " + count);
} else {
String error = "\n\nnot OK " + count + "\ncmd = "
+ command + "\ndesired result= "
+ StringUtil.toJavaString(result)
+ "\nactual result = " + StringUtil
.toJavaString(casResultOriginal);
// to auto-fill answers for new test-cases
// error = "{ cat:\"Integral\", cmd:\"";
// error += StringUtil.toJavaString(command);
// error += "\", result:\"";
// error +=
// StringUtil.toJavaString(casResultOriginal);
// error += "\", notes:\"from Giac's tests\" },\n";
Log.error(error);
errors.add(error);
}
}
}
br.close();
} catch (RuntimeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.error("CAS TESTS ENDED. Total tests run = " + count
+ ". Failed = " + errors.size());
Iterator<String> it = errors.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
AppD.exit(0);
}
boolean macSandbox = args.getBooleanValue("macSandbox", false);
if (macSandbox) {
this.macsandbox = true;
}
setVersionCheckAllowed(args.getStringValue("versionCheckAllow"));
}
@SuppressFBWarnings({ "DM_EXIT", "" })
public static void exit(int i) {
System.exit(i);
}
private static boolean versionCheckAllowed = true;
private void setVersionCheckAllowed(String versionCheckAllow) {
if (isApplet()) {
versionCheckAllowed = false;
return;
}
if (versionCheckAllow != null) {
if ("off".equals(versionCheckAllow)) {
GeoGebraPreferencesD.getPref().saveVersionCheckAllow("false");
versionCheckAllowed = false;
return;
}
if ("on".equals(versionCheckAllow)) {
GeoGebraPreferencesD.getPref().saveVersionCheckAllow("true");
versionCheckAllowed = true;
return;
}
if ("false".equals(versionCheckAllow)) {
versionCheckAllowed = false;
return;
}
if ("true".equals(versionCheckAllow)) {
versionCheckAllowed = true;
return;
}
Log.warn("Option versionCheckAllow not recognized : "
.concat(versionCheckAllow));
}
versionCheckAllowed = GeoGebraPreferencesD.getPref()
.loadVersionCheckAllow("true");
}
private static void setProverOption(String option) {
String[] str = option.split(":", 2);
ProverSettings proverSettings = ProverSettings.get();
if ("engine".equalsIgnoreCase(str[0])) {
if ("OpenGeoProver".equalsIgnoreCase(str[1])
|| "Recio".equalsIgnoreCase(str[1])
|| "Botana".equalsIgnoreCase(str[1])
|| "alternativeBotana".equalsIgnoreCase(str[1])
|| "PureSymbolic".equalsIgnoreCase(str[1])
|| "Auto".equalsIgnoreCase(str[1])) {
proverSettings.proverEngine = str[1].toLowerCase();
return;
}
Log.warn("Option not recognized: ".concat(option));
return;
}
if ("timeout".equalsIgnoreCase(str[0])) {
proverSettings.proverTimeout = Integer.parseInt(str[1]);
return;
}
if ("maxTerms".equalsIgnoreCase(str[0])) {
proverSettings.setMaxTerms(Integer.parseInt(str[1]));
return;
}
if ("method".equalsIgnoreCase(str[0])) {
if ("Groebner".equalsIgnoreCase(str[1])
|| "Wu".equalsIgnoreCase(str[1])
|| "Area".equalsIgnoreCase(str[1])) {
proverSettings.proverMethod = str[1].toLowerCase();
return;
}
Log.warn("Method parameter not recognized: ".concat(option));
return;
}
if ("fpnevercoll".equalsIgnoreCase(str[0])) {
proverSettings.freePointsNeverCollinear = Boolean
.parseBoolean(str[1]);
return;
}
if ("usefixcoords".equalsIgnoreCase(str[0])) {
int fixcoordsP = Integer.parseInt(str[1].substring(0, 1));
int fixcoordsPD = Integer.parseInt(str[1].substring(1, 2));
if (fixcoordsP < 0 || fixcoordsP > 4) {
Log.error(
"Improper value for usefixcoords for Prove, using default instead");
} else {
proverSettings.useFixCoordinatesProve = fixcoordsP;
}
if (fixcoordsPD < 0 || fixcoordsPD > 4) {
Log.error(
"Improper value for usefixcoords for ProveDetails, using default instead");
} else {
proverSettings.useFixCoordinatesProveDetails = fixcoordsPD;
}
return;
}
if ("transcext".equalsIgnoreCase(str[0])) {
proverSettings.transcext = Boolean.parseBoolean(str[1]);
return;
}
if ("captionalgebra".equalsIgnoreCase(str[0])) {
proverSettings.captionAlgebra = Boolean.parseBoolean(str[1]);
return;
}
Log.warn("Prover option not recognized: ".concat(option));
}
private static void setSingularWSOption(String option) {
String[] str = option.split(":", 2);
if ("enable".equalsIgnoreCase(str[0])) {
SingularWSSettings.setUseSingularWebService(
Boolean.valueOf(str[1]).booleanValue());
return;
}
if ("remoteURL".equalsIgnoreCase(str[0])) {
SingularWSSettings
.setSingularWebServiceRemoteURL(str[1].toLowerCase());
return;
}
if ("timeout".equalsIgnoreCase(str[0])) {
SingularWSSettings.setTimeout(Integer.parseInt(str[1]));
return;
}
if ("caching".equalsIgnoreCase(str[0])) {
SingularWSSettings.setCachingFromText(str[1]);
return;
}
Log.warn("Prover option not recognized: ".concat(option));
}
/**
* Reports if GeoGebra version check is allowed. The version_check_allowed
* preference is read to decide this, which can be set by the command line
* option --versionCheckAllow (off/on). For changing the behavior for a
* single run, the same command line option must be used with false/true
* parameters.
*
* @return if the check is allowed
* @author Zoltan Kovacs <zoltan@geogebra.org>
*/
public boolean getVersionCheckAllowed() {
if (isApplet()) {
return false;
}
return versionCheckAllowed;
}
protected void handleOptionArgsEarly(CommandLineArguments args) {
if (args == null) {
return;
}
if (args.containsArg("showCAS")) {
String showCASs = args.getStringValue("showCAS");
if (showCASs.equalsIgnoreCase("disable")) {
disableCASView();
getSettings().getCasSettings().setEnabled(false);
}
}
if (args.containsArg("show3D")) {
String show3Ds = args.getStringValue("show3D");
if (show3Ds.equalsIgnoreCase("disable")) {
disable3DView();
}
}
String language = args.getStringValue("language");
if (language.length() > 0) {
if ("Auto".equalsIgnoreCase(language)) {
Locale systemLocale = Locale.getDefault();
setLocale(systemLocale);
} else {
setLocale(getLocale(language));
}
}
boolean eg = args.getBooleanValue("enableGraphing", true);
kernel.getAlgebraProcessor().setCommandsEnabled(eg);
if (args.containsArg("regressionFile")) {
this.regressionFileName = args.getStringValue("regressionFile");
}
if (args.containsArg("prover")) {
String[] proverOptions = args.getStringValue("prover").split(",");
for (int i = 0; i < proverOptions.length; i++) {
setProverOption(proverOptions[i]);
}
}
if (args.containsArg("singularWS")) {
String[] singularWSOptions = args.getStringValue("singularWS")
.split(",");
for (int i = 0; i < singularWSOptions.length; i++) {
setSingularWSOption(singularWSOptions[i]);
}
}
}
// **************************************************************************
// STATUS
// **************************************************************************
@Override
final public boolean isApplet() {
return isApplet;
}
public boolean isStandaloneApplication() {
return !isApplet && (mainComp instanceof JFrame);
}
public boolean onlyGraphicsViewShowing() {
if (!isUsingFullGui()) {
return true;
}
return getGuiManager().getLayout().isOnlyVisible(App.VIEW_EUCLIDIAN);
}
final static int MEMORY_CRITICAL = 100 * 1024;
static Runtime runtime = Runtime.getRuntime();
@Override
public boolean freeMemoryIsCritical() {
return runtime.freeMemory() < MEMORY_CRITICAL;
}
@Override
public long freeMemory() {
return runtime.freeMemory();
}
public long getHeapSize() {
return runtime.maxMemory();
}
public void traceMethodsOn(boolean on) {
runtime.traceMethodCalls(on);
}
private static boolean virtualKeyboardActive = false;
public static boolean isVirtualKeyboardActive() {
return virtualKeyboardActive;
}
public static void setVirtualKeyboardActive(boolean active) {
virtualKeyboardActive = active;
// Application.debug("VK active:"+virtualKeyboardActive);
}
// **************************************************************************
// File Handling
// **************************************************************************
public File getCurrentFile() {
return currentFile;
}
public File getCurrentPath() {
return currentPath;
}
public void setCurrentPath(File file) {
currentPath = file;
}
@Override
public void setCurrentFile(Object file) {
if (currentFile == file) {
return;
}
currentFile = (File) file;
if (currentFile != null) {
currentPath = currentFile.getParentFile();
addToFileList(currentFile);
}
if (!isIniting() && isUsingFullGui()) {
updateTitle();
getGuiManager().updateMenuWindow();
}
}
public static void addToFileList(File file) {
if ((file == null) || !file.exists()) {
return;
}
// add or move fileName to front of list
fileList.remove(file);
fileList.addFirst(file);
}
public static File getFromFileList(int i) {
if (fileList.size() > i) {
return fileList.get(i);
}
return null;
}
public static int getFileListSize() {
return fileList.size();
}
public void createNewWindow() {
GeoGebraFrame.createNewWindow(cmdArgs.getGlobalArguments());
}
@Override
public void fileNew() {
// clear all
// triggers the "do you want to save" dialog
// so must be called first
if (!clearConstruction()) {
return;
}
// clear input bar
if (isUsingFullGui() && showAlgebraInput()) {
getGuiManager().clearInputbar();
}
// reset spreadsheet columns, reset trace columns
if (isUsingFullGui()) {
getGuiManager().resetSpreadsheet();
getGuiManager().resetCasView();
}
resetEVs();
resetAllToolbars();
// reload the saved/(default) preferences
GeoGebraPreferencesD.getPref().loadXMLPreferences(this);
resetUniqueId();
}
private void resetAllToolbars() {
GuiManagerD gm = (GuiManagerD) getGuiManager();
DockPanelD[] panels = gm.getLayout().getDockManager().getPanels();
for (DockPanelD panel : panels) {
if (panel.canCustomizeToolbar()) {
panel.setToolbarString(panel.getDefaultToolbarString());
}
}
gm.setToolBarDefinition(gm.getDefaultToolbarString());
}
private String regressionFileName = null;
/**
* Creates the regression file for the current GGB file with the textual
* content of the algebra window, then exits.
*
* @throws IOException
* if the file is not writable
*/
public void createRegressionFile() throws IOException {
if (regressionFileName == null) {
return;
}
File regressionFile = new File(regressionFileName);
BufferedWriter regressionFileWriter = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(regressionFile),
"UTF-8"));
kernel.updateConstruction();
regressionFileWriter.append(getXMLio().getConstructionRegressionOut());
regressionFileWriter.close();
AppD.exit(0);
}
/**
* This function helps determine if a ggt file was loaded because if a ggt
* file was loaded we will need to load something instead of the ggb
*
* @return true if file is loading and is a ggt file
*/
private static boolean isLoadingTool(CommandLineArguments args) {
if ((args == null) || (args.getNoOfFiles() == 0)) {
return false;
}
String fileArgument = args.getStringValue("file0");
String lowerCase = StringUtil.toLowerCase(fileArgument);
return lowerCase.endsWith(FileExtensions.GEOGEBRA_TOOL.toString());
}
/**
* Opens a file specified as last command line argument
*
* @return true if a file was loaded successfully
*/
private boolean handleFileArg(final CommandLineArguments args) {
if ((args == null) || (args.getNoOfFiles() == 0)) {
return false;
}
boolean successRet = true;
for (int i = 0; i < args.getNoOfFiles(); i++) {
final String fileArgument = args.getStringValue("file" + i);
final String key = "file0";
if (i > 0) { // load in new Window
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
GeoGebraFrame.createNewWindow(args.getGlobalArguments()
.add(key, fileArgument));
}
});
} else {
try {
boolean success;
String lowerCase = StringUtil.toLowerCase(fileArgument);
FileExtensions ext = StringUtil.getFileExtension(lowerCase);
boolean isMacroFile = ext
.equals(FileExtensions.GEOGEBRA_TOOL);
if (lowerCase.startsWith("http:")
|| lowerCase.startsWith("https:")
|| lowerCase.startsWith("file:")) {
// replace all whitespace characters by %20 in URL
// string
String fileArgument2 = fileArgument.replaceAll("\\s",
"%20");
URL url = new URL(fileArgument2);
success = loadXML(url, isMacroFile);
// check if full GUI is necessary
if (success && !isMacroFile) {
if (!isUsingFullGui()) {
if (showConsProtNavigation()
|| !isJustEuclidianVisible()) {
useFullGui = true;
}
}
}
} else if (lowerCase.startsWith("base64://")) {
// substring to strip off base64://
byte[] zipFile = Base64
.decode(fileArgument.substring(9));
success = loadXML(zipFile);
if (success && !isMacroFile) {
if (!isUsingFullGui()) {
if (showConsProtNavigation()
|| !isJustEuclidianVisible()) {
useFullGui = true;
}
}
}
} else if (ext.equals(FileExtensions.HTM)
|| ext.equals(FileExtensions.HTML)) {
loadBase64File(new File(fileArgument));
success = true;
} else {
File f = new File(fileArgument);
f = f.getCanonicalFile();
success = loadFile(f, isMacroFile);
}
successRet = successRet && success;
} catch (Exception e) {
e.printStackTrace();
successRet = false;
}
}
}
return successRet;
}
/**
* loads an html file with <param name="ggbBase64" value="UEsDBBQACAAI...
*
* @param file
* html file
* @return success
*/
public boolean loadBase64File(final File file) {
if (!file.exists()) {
// show file not found message
JOptionPane.showConfirmDialog(getMainComponent(),
getLocalization().getError("FileNotFound") + ":\n"
+ file.getAbsolutePath(),
getLocalization().getError("Error"),
JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE);
return false;
}
boolean success = false;
setWaitCursor();
// hide navigation bar for construction steps if visible
setHideConstructionProtocolNavigation();
try {
success = loadFromHtml(file.toURI().toURL()); // file.toURL() does
// not escape
// illegal
// characters
} catch (Exception e) {
setDefaultCursor();
showError(getLocalization().getError("LoadFileFailed") + ":\n"
+ file);
e.printStackTrace();
return false;
}
// updateGUIafterLoadFile(success, false);
setDefaultCursor();
return success;
}
/**
* Tries to load a construction from the following sources in order:
* <ol>
* <li>From embedded base64 string
* <ol type="a">
* <li><code><article ... data-param-ggbbase64="..." /></code></li>
* <li><code><param name="ggbBase64" value="..." /></code></li>
* </ol>
* </li>
* <li>From relative referenced *.ggb file
* <ol type="a">
* <li><code><article ... data-param-filename="..." /></code></li>
* <li><code><param name="filename" value="..." /></code></li>
* </ol>
* </li>
* </ol>
*
*/
public boolean loadFromHtml(URL htmlurl) throws IOException {
URL url = htmlurl;
String page = fetchPage(url);
page = page.replaceAll("\\s+", " "); // Normalize white spaces
page = page.replace('"', '\''); // Replace double quotes (") with single
// quotes (')
String lowerCasedPage = StringUtil.toLowerCase(page); // We must
// preserve
// casing for
// base64
// strings and
// case sensitve
// file systems
String val = getAttributeValue(page, lowerCasedPage,
"data-param-ggbbase64='");
val = val == null ? getAttributeValue(page, lowerCasedPage,
"name='ggbbase64' value='") : val;
if (val != null) { // 'val' is the base64 string
byte[] zipFile = Base64.decode(val);
return loadXML(zipFile);
}
val = getAttributeValue(page, lowerCasedPage, "data-param-filename='");
val = val == null ? getAttributeValue(page, lowerCasedPage,
"name='filename' value='") : val;
if (val != null) { // 'val' is the relative path to *.ggb file
String path = url.getPath(); // http://www.geogebra.org/mobile/test.html?test=true
// -> path would be
// '/mobile/test.html'
int index = path.lastIndexOf('/');
path = index == -1 ? path : path.substring(0, index + 1); // Remove
// the
// 'test.html'
// part
path += val; // Add filename
URL fileUrl = new URL(url.getProtocol(), url.getHost(), path);
return loadXML(fileUrl, false);
}
final String iframeURL1 = "<iframe src='http://www.geogebratube.org/material/iframe/id/";
final String iframeURL2 = "<iframe src='http://ggbtu.be/e";
// try loading from an embedded iframe
int index = lowerCasedPage.indexOf(iframeURL1);
if (index > -1) {
index += iframeURL1.length();
} else {
index = lowerCasedPage.indexOf(iframeURL2);
if (index > -1) {
index += iframeURL2.length();
}
}
if (index > -1) {
StringBuilder sb = new StringBuilder(
"http://www.geogebratube.org/material/download/format/file/id/");
while (index < lowerCasedPage.length()
&& Character.isDigit(lowerCasedPage.charAt(index))) {
sb.append(lowerCasedPage.charAt(index));
index++;
}
url = new URL(sb.toString());
return loadXML(url, false);
}
return false;
}
private static String getAttributeValue(String page, String lowerCasedPage,
String attrName0) {
String attrName = attrName0;
int index;
if (-1 != (index = lowerCasedPage.indexOf(attrName))) { // value='test.ggb'
index += attrName.length();
return getAttributeValue(page, index, '\''); // Search for next
// single quote (')
}
attrName = attrName.replaceAll("'", "");
if (-1 != (index = lowerCasedPage.indexOf(attrName))) { // value=filename_
// or
// value=filename>
// ( ) or (>)
index += attrName.length();
return getAttributeValue(page, index, ' ', '>'); // Search for next
// white space (
// ) or angle
// bracket (>)
}
return null;
}
private static String getAttributeValue(String page, int begin,
char... attributeEndMarkers) {
int end = begin;
while (end < page.length()
&& !isMarker(attributeEndMarkers, page.charAt(end))) {
end++;
}
return end == page.length() || end == begin ? // attribute value not
// terminated or empty
null : page.substring(begin, end);
}
private static boolean isMarker(char[] markers, char character) {
for (char m : markers) {
if (m == character) {
return true;
}
}
return false;
}
private static String fetchPage(URL url) throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(
new InputStreamReader(url.openStream(), Charsets.UTF_8));
StringBuilder page = new StringBuilder();
String line;
while (null != (line = reader.readLine())) {
page.append(line); // page does not contain any line breaks
// '\n', '\r' or "\r\n"
}
return page.toString();
} finally {
if (reader != null) {
reader.close();
}
}
}
// **************************************************************************
// VIEWS
// **************************************************************************
@Override
public void setActiveView(int view) {
if (getGuiManager() != null) {
setActiveView(this, view);
}
}
/**
* Check if just the euclidian view is visible in the document just loaded.
*
* @return
* @throws OperationNotSupportedException
*/
private boolean isJustEuclidianVisible()
throws OperationNotSupportedException {
if (tmpPerspectives == null) {
throw new OperationNotSupportedException();
}
Perspective docPerspective = null;
for (Perspective perspective : tmpPerspectives) {
if (perspective.getId().equals("tmp")) {
docPerspective = perspective;
}
}
if (docPerspective == null) {
throw new OperationNotSupportedException();
}
boolean justEuclidianVisible = false;
for (DockPanelData panel : docPerspective.getDockPanelData()) {
if ((panel.getViewId() == App.VIEW_EUCLIDIAN)
&& panel.isVisible()) {
justEuclidianVisible = true;
} else if (panel.isVisible()) {
justEuclidianVisible = false;
break;
}
}
return justEuclidianVisible;
}
@Override
public EuclidianView createEuclidianView() {
return this.euclidianView;
}
@Override
public EuclidianViewD getEuclidianView1() {
return (EuclidianViewD) euclidianView;
}
@Override
public AlgebraView getAlgebraView() {
if (guiManager == null) {
return null;
}
return (AlgebraView) guiManager.getAlgebraView();
}
@Override
public EuclidianViewD getEuclidianView2(int idx) {
return (EuclidianViewD) getGuiManager().getEuclidianView2(idx);
}
@Override
public boolean hasEuclidianView2EitherShowingOrNot(int idx) {
return (guiManager != null)
&& getGuiManager().hasEuclidianView2EitherShowingOrNot(1);
}
@Override
public boolean isShowingEuclidianView2(int idx) {
return (guiManager != null) && getGuiManager().hasEuclidianView2(idx)
&& getGuiManager().getEuclidianView2(idx).isShowing();
}
@Override
public EuclidianView getActiveEuclidianView() {
if (getGuiManager() == null) {
return getEuclidianView1();
}
return getGuiManager().getActiveEuclidianView();
}
public void setShowAxesSelected(JCheckBoxMenuItem cb) {
cb.setSelected(getGuiManager().getActiveEuclidianView().getShowXaxis()
&& (getGuiManager().getActiveEuclidianView().getShowYaxis()));
}
public void setShowGridSelected(JCheckBoxMenuItem cb) {
cb.setSelected(getGuiManager().getActiveEuclidianView().getShowGrid());
}
// **************************************************************************
// ICONS & IMAGES
// **************************************************************************
@Override
public ImageManagerD getImageManager() {
return imageManager;
}
@Override
public void setGUIFontSize(int size) {
// TRAC-4770
if (size != -1) {
// set tool icon size between 32 and 64
imageManager.setMaxIconSize(Math.max(32, size * 2));
}
super.setGUIFontSize(size);
}
@Override
public void setFontSize(int points, boolean update) {
if (guiFontSize == -1) {
// set tool icon size between 32 and 64
imageManager.setMaxIconSizeAsPt(points);
}
super.setFontSize(points, update);
}
public ImageIcon getImageIcon(ImageResourceD res) {
return imageManager.getImageIcon(res, null);
}
public ImageIcon getScaledIcon(ImageResourceD res) {
return getScaledIcon(res, null);
}
/*
* needed for padding in Windows XP or earlier without check, checkbox isn't
* shown in Vista, Win 7
*/
public void setEmptyIcon(JCheckBoxMenuItem cb) {
if (!WINDOWS_VISTA_OR_LATER) {
cb.setIcon(getEmptyIcon());
}
}
protected String getMenuIconPath() {
// int fontSize = getGUIFontSize();
String path = "/gui/images/64px/";
// if (fontSize < 30) {
// path += "20px/";
// } else if (fontSize >= 30 && fontSize < 79.5) {
// path += "40px/";
// } else if (fontSize >= 79.5) {
// path += "106px/";
// }
//
return path;
}
public static int ptToPx(int points) {
int px = 0;
switch (points) {
case 12:
case 14:
case 16:
px = 16;
break;
default:
case 18:
case 20:
case 24:
case 28:
px = 24;
break;
case 32:
case 48:
px = 48;
break;
}
return px;
}
public int getScaledIconSize() {
return ptToPx(getFontSize());
}
public ImageIcon getScaledIcon(ImageResourceD res, Color borderColor) {
ImageIcon icon = imageManager.getImageIcon(res, borderColor);
return scaleIcon(icon, getScaledIconSize());
}
public ImageIcon getScaledIconCommon(ImageResourceD res) {
ImageIcon icon = imageManager.getImageIcon(res, null);
return scaleIcon(icon, getScaledIconSize());
}
public ImageIcon getScaledIcon(ImageResourceD res, int iconSize) {
ImageIcon icon = imageManager.getImageIcon(res, null);
return scaleIcon(icon, iconSize);
}
private static ImageIcon scaleIcon(ImageIcon icon, int iconSize) {
if (icon == null || iconSize == 0) {
return null;
}
Image img = icon.getImage().getScaledInstance(iconSize, iconSize,
Image.SCALE_SMOOTH);
return new ImageIcon(img);
}
public Image getScaledInternalImage(ImageResourceD fileName) {
MyImageD img = imageManager.getInternalImage(fileName);
int iconSize = getScaledIconSize();
return img.getImage().getScaledInstance(iconSize, iconSize, 0);
}
/**
* Attempt to return a flag to represent the current language
*
* Not always possible to return a sensible value as there is not a 1-1
* correspondence between countries & languages
*
* @return
*
*/
public String getFlagName() {
String country = Language.getCountry(getLocale().getLanguage(),
getLocale().getCountry());
// http://stackoverflow.com/questions/10175658/is-there-a-simple-way-to-get-the-language-code-from-a-country-code-in-php
// http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
country = StringUtil.toLowerCase(country);
String flag = country + ".png";
return flag;
}
public ImageIcon getScaledFlagIcon(String filename) {
ImageIcon icon = imageManager.getFlagIcon(filename);
if (isMacOS()) {
return icon;
}
return scaleIcon(icon, getScaledIconSize());
}
public ImageIcon getToolBarImage(String modeText, Color borderColor) {
ImageIcon icon = imageManager.getImageIcon(
imageManager.getToolImageResource(modeText),
borderColor, Color.WHITE);
/*
* mathieu 2010-04-10 see ImageManager3D.getImageResourceGeoGebra() if
* (icon == null) { // load3DJar(); // try to find this image in 3D
* extension path = "org/geogebra/desktop/geogebra3D/images/" +
* filename; icon = imageManager.getImageIcon(path, borderColor); }
*/
if (icon == null) {
icon = getToolIcon(borderColor);
Log.debug("icon missing for mode " + modeText);
}
// scale icon if necessary
icon = ImageManagerD.getScaledIcon(icon,
Math.min(icon.getIconWidth(), imageManager.getMaxIconSize()),
Math.min(icon.getIconHeight(), imageManager.getMaxIconSize()));
return icon;
}
public ImageIcon getToolIcon(Color border) {
ImageResourceD res;
if (imageManager.getMaxIconSize() <= 32) {
res = GuiResourcesD.TOOL_MODE32;
} else {
res = GuiResourcesD.TOOL_MODE64;
}
return imageManager.getImageIcon(res, border);
}
public ImageIcon getEmptyIcon() {
return imageManager.getImageIcon(GuiResourcesD.EMPTY);
}
public Image getInternalImage(ImageResourceD filename) {
return imageManager.getInternalImage(filename).getImage();
}
public Image getRefreshViewImage() {
// don't need to load gui jar as reset image is in main jar
return getMenuInternalImage(GuiResourcesD.VIEW_REFRESH);
}
public Image getPlayImage() {
// don't need to load gui jar as reset image is in main jar
return imageManager.getInternalImage(GuiResourcesD.NAV_PLAY).getImage();
}
public Image getPlayImageCircle() {
// don't need to load gui jar as reset image is in main jar
return imageManager.getInternalImage(GuiResourcesD.NAV_PLAY_CIRCLE)
.getImage();
}
public Image getPlayImageCircleHover() {
// don't need to load gui jar as reset image is in main jar
return imageManager.getInternalImage(GuiResourcesD.NAV_PLAY_HOVER)
.getImage();
}
public Image getPauseImageCircle() {
// don't need to load gui jar as reset image is in main jar
return imageManager.getInternalImage(GuiResourcesD.NAV_PAUSE_CIRCLE)
.getImage();
}
public Image getPauseImageCircleHover() {
// don't need to load gui jar as reset image is in main jar
return imageManager
.getInternalImage(GuiResourcesD.NAV_PAUSE_CIRCLE_HOVER)
.getImage();
}
public Image getPauseImage() {
// don't need to load gui jar as reset image is in main jar
return imageManager.getInternalImage(GuiResourcesD.NAV_PAUSE)
.getImage();
}
public MyImageD getExternalImage(String filename) {
return ImageManagerD.getExternalImage(filename);
}
@Override
public final MyImage getExternalImageAdapter(String filename, int width,
int height) {
MyImageD im = ImageManagerD.getExternalImage(filename);
return im;
}
public void addExternalImage(String filename, MyImageD image) {
imageManager.addExternalImage(filename, image);
}
@Override
public GImageIcon wrapGetModeIcon(int mode) {
return new GImageIconD(getModeIcon(mode));
}
public ImageIcon getModeIcon(int mode) {
ImageIcon icon;
Color border = Color.lightGray;
// macro
if (mode >= EuclidianConstants.MACRO_MODE_ID_OFFSET) {
int macroID = mode - EuclidianConstants.MACRO_MODE_ID_OFFSET;
try {
Macro macro = kernel.getMacro(macroID);
String iconName = macro.getIconFileName();
MyImageD img = getExternalImage(iconName);
if (img == null || img.isSVG()) {
// default icon
icon = getToolIcon(border);
} else {
// use image as icon
int size = imageManager.getMaxIconSize();
icon = new ImageIcon(ImageManagerD.addBorder(img.getImage()
.getScaledInstance(size, -1, Image.SCALE_SMOOTH),
border, null));
}
} catch (Exception e) {
Log.debug("macro does not exist: ID = " + macroID);
return null;
}
} else {
// standard case
String modeText = EuclidianConstants.getModeTextSimple(mode);
// bugfix for Turkish locale added Locale.US
icon = getToolBarImage(modeText, border);
}
return icon;
}
/**
* stores an image in the application's imageManager.
*
* @return fileName of image stored in imageManager
*/
public String createImage(MyImageD image, String imageFileName) {
String fileName = imageFileName;
MyImageD img = image;
try {
String zip_directory = img.getMD5();
String fn = fileName;
int index = fileName.lastIndexOf(File.separator);
if (index != -1) {
fn = fn.substring(index + 1, fn.length()); // filename without
}
// path
fn = Util.processFilename(fn);
// filename will be of form
// "a04c62e6a065b47476607ac815d022cc/filename.ext"
fileName = zip_directory + "/" + fn;
/*
*
* // write and reload image to make sure we can save it // without
* problems ByteArrayOutputStream os = new ByteArrayOutputStream();
* getXMLio().writeImageToStream(os, fileName, img); os.flush();
* ByteArrayInputStream is = new
* ByteArrayInputStream(os.toByteArray());
*
* // reload the image img = ImageIO.read(is); is.close();
* os.close();
*
*
*
* setDefaultCursor(); if (img == null) {
* showError("LoadFileFailed"); return null; }
*/
// make sure this filename is not taken yet
MyImageD oldImg = ImageManagerD.getExternalImage(fileName);
if (oldImg != null) {
// image with this name exists already
if ((oldImg.getWidth() == img.getWidth())
&& (oldImg.getHeight() == img.getHeight())) {
// same size and filename => we consider the images as equal
return fileName;
}
// same name but different size: change filename
// this bit of code should now be
// redundant as it
// is near impossible for the filename to be the same unless
// the files are the same
int n = 0;
do {
n++;
int pos = fileName.lastIndexOf('.');
String firstPart = pos > 0 ? fileName.substring(0, pos)
: "";
String extension = pos < fileName.length()
? fileName.substring(pos) : "";
fileName = firstPart + n + extension;
} while (ImageManagerD.getExternalImage(fileName) != null);
}
imageManager.addExternalImage(fileName, img);
return fileName;
} catch (Exception e) {
setDefaultCursor();
e.printStackTrace();
showError("LoadFileFailed");
return null;
} catch (java.lang.OutOfMemoryError t) {
Log.debug("Out of memory");
System.gc();
setDefaultCursor();
// t.printStackTrace();
// TODO change to OutOfMemoryError
showError("LoadFileFailed");
return null;
}
}
// **************************************************************************
// PRINTING & EXPORT
// **************************************************************************
public File getCurrentImagePath() {
return currentImagePath;
}
public void setCurrentImagePath(File currentImagePath) {
this.currentImagePath = currentImagePath;
}
/**
* Loads text file and returns content as String.
*/
public String loadTextFile(String s) {
StringBuilder sb = new StringBuilder();
BufferedReader br = null;
try {
InputStream is = AppD.class.getResourceAsStream(s);
br = new BufferedReader(
new InputStreamReader(is, Charsets.UTF_8));
String thisLine;
while ((thisLine = br.readLine()) != null) {
sb.append(thisLine);
sb.append('\n');
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
@Override
public void copyGraphicsViewToClipboard() {
copyGraphicsViewToClipboard(getGuiManager().getActiveEuclidianView());
}
@Override
public void copyTextToSystemClipboard(String text) {
Toolkit.getDefaultToolkit().getSystemClipboard()
.setContents(new StringSelection(text), null);
}
@Override
public void copyBase64ToClipboard() {
// don't include preview bitmap
copyTextToSystemClipboard(getGgbApi().getBase64(false));
}
@Override
public void copyFullHTML5ExportToClipboard() {
copyTextToSystemClipboard(getFullHTML5ExportString());
}
public void copyGraphicsViewToClipboard(final EuclidianView copyView) {
getSelectionManager().clearSelectedGeos(true, false);
updateSelection(false);
Thread runner = new Thread() {
@Override
public void run() {
setWaitCursor();
simpleExportToClipboard(copyView);
/*
* doesn't work in Win7, XP pasting into eg Paint pasting into
* eg Office 2010 is OK
*
*
* if (!WINDOWS_VISTA_OR_LATER) {
*
* // use other method for WinXP or earlier //
* GraphicExportDialog.exportPNG() doesn't work well on XP // eg
* paste into Paint
*
* simpleExportToClipboard(ev);
*
* } else {
*
* GraphicExportDialog export = new GraphicExportDialog(app);
* export.setDPI("300");
*
* if (!export.exportPNG(true, false)) { // if there's an error
* (eg memory) just do a simple // export
* simpleExportToClipboard(ev);
*
* } }
*/
setDefaultCursor();
}
};
runner.start();
}
static void simpleExportToClipboard(EuclidianView ev) {
double scale = getMaxScaleForClipBoard(ev);
// copy drawing pad to the system clipboard
Image img = GBufferedImageD.getAwtBufferedImage(
((EuclidianViewD) ev).getExportImage(scale));
ImageSelection imgSel = new ImageSelection(img);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(imgSel,
null);
}
private static Rectangle screenSize = null;
/*
* gets the screensize (taking into account toolbars etc)
*/
public static Rectangle getScreenSize() {
if (screenSize == null) {
GraphicsEnvironment env = GraphicsEnvironment
.getLocalGraphicsEnvironment();
screenSize = env.getMaximumWindowBounds();
}
return screenSize;
}
/**
* @param maxX
* maximum width
* @param maxY
* maximum height
* @return preview image
* @throws OutOfMemoryError
* error
*/
public BufferedImage getExportImage(double maxX, double maxY)
throws OutOfMemoryError {
return GBufferedImageD.getAwtBufferedImage(
getActiveEuclidianViewExportImage(maxX, maxY));
}
// **************************************************************************
// LOCALES
// **************************************************************************
/**
* Creates a Locale object according to the given language code. The
* languageCode string should consist of two letters for the language, two
* letters for the country and two letters for the variant. E.g. "en" ...
* language: English , no country specified, "deAT" or "de_AT" ... language:
* German , country: Austria, "noNONY" or "no_NO_NY" ... language: Norwegian
* , country: Norway, variant: Nynorsk
*
* @param languageISOCode
* locale iso code (may contain _ or not)
* @return locale
*/
public static Locale getLocale(String languageISOCode) {
// remove "_" from string
String languageCode = languageISOCode.replaceAll("_", "");
Locale loc;
if (languageCode.length() == 6) {
// language, country, variant
loc = new Locale(languageCode.substring(0, 2),
languageCode.substring(2, 4), languageCode.substring(4, 6));
} else if (languageCode.length() == 4) {
// language, country
loc = new Locale(languageCode.substring(0, 2),
languageCode.substring(2, 4));
} else {
// language only
loc = new Locale(languageCode.substring(0, 2));
}
return loc;
}
@Override
public void setTooltipLanguage(String s) {
boolean updateNeeded = loc.setTooltipLanguage(s);
updateNeeded = updateNeeded || (loc.getTooltipLocale() != null);
if (updateNeeded) {
setLabels(); // update eg Tooltips for Toolbar
}
}
@Override
public int getTooltipTimeout() {
int dmd = ToolTipManager.sharedInstance().getDismissDelay();
if ((dmd <= 0) || (dmd == Integer.MAX_VALUE)) {
return -1;
}
dmd /= 1000;
for (int i = 0; i < (OptionsAdvancedD.tooltipTimeoutsLength()
- 1); i++) {
if (Integer.parseInt(OptionsAdvancedD.tooltipTimeouts(i)) >= dmd) {
return Integer.parseInt(OptionsAdvancedD.tooltipTimeouts(i));
}
}
return Integer.parseInt(OptionsAdvancedD
.tooltipTimeouts(OptionsAdvancedD.tooltipTimeoutsLength() - 2));
}
@Override
public void setLanguage(String s) {
String[] parts = s.split("_");
String language = parts[0];
String country = parts.length > 1 ? parts[1] : null;
Locale locale = null;
if (language != null) {
if (country != null) {
locale = new Locale(language, country);
} else {
locale = new Locale(language);
}
}
setLocale(locale);
}
/**
* set language via iso language string
*/
public void setLanguage(Locale locale) {
if ((locale == null)
|| loc.getLocale().toString().equals(locale.toString())) {
return;
}
if (!initing) {
setMoveMode();
}
// load resource files
setLocale(locale);
// update right angle style in euclidian view (different for German)
// if (euclidianView != null)
// euclidianView.updateRightAngleStyle(locale);
// make sure digits are updated in all numbers
getKernel().updateConstructionLanguage();
setUnsaved();
setLabels(); // update display
setOrientation();
}
StringBuilder testCharacters = new StringBuilder();
public void setLocale(Locale locale) {
if (locale == loc.getLocale()) {
return;
}
Locale oldLocale = loc.getLocale();
// only allow special locales due to some weird server
// problems with the naming of the property files
loc.setLocale(locale);
// update font for new language (needed for e.g. chinese)
try {
fontManager.setLanguage(loc.getLocale());
} catch (Exception e) {
e.printStackTrace();
showError(e.getMessage());
// go back to previous locale
loc.setLocale(oldLocale);
}
getLocalization().updateLanguageFlags(locale.getLanguage());
}
/**
* @return current locale
*/
public Locale getLocale() {
return loc.getLocale();
}
final public String getEnglishMenu(String key) {
if (rbmenuEnglish == null) {
rbmenuEnglish = MyResourceBundle.createBundle(LocalizationD.RB_MENU,
Locale.ENGLISH);
}
try {
return rbmenuEnglish.getString(key);
} catch (Exception e) {
return key;
}
}
/**
* Shows localized help message
*
* @param key
* key (for plain) to be localized
*/
public void showHelp(String key) {
final String text = loc.getMenu(key);
JOptionPane.showConfirmDialog(mainComp, text,
GeoGebraConstants.APPLICATION_NAME + " - "
+ loc.getMenu("Help"),
JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE);
}
// **************************************************************************
// GUI Updates
// **************************************************************************
/**
* Updates the GUI of the main component.
*/
public void updateContentPane() {
updateContentPane(true);
}
/**
* Updates the GUI of the frame and its size.
*/
public void updateContentPaneAndSize() {
if (initing) {
return;
}
updateContentPane(false);
if ((frame != null) && frame.isShowing()) {
getGuiManager().updateFrameSize();
}
updateComponentTreeUI();
}
private void updateContentPane(boolean updateComponentTreeUI) {
if (initing) {
return;
}
Container cp;
if (isApplet) {
cp = appletImpl.getJApplet().getContentPane();
} else if ((frame != null) && (frame == mainComp)) {
cp = frame.getContentPane();
} else {
cp = (Container) mainComp;
}
addMacroCommands();
cp.removeAll();
cp.add(buildApplicationPanel());
fontManager.setFontSize(getGUIFontSize());
// update sizes
euclidianView.updateSize();
if (hasEuclidianView2(1)) {
getEuclidianView2(1).updateSize();
}
// update layout
if (updateComponentTreeUI) {
updateComponentTreeUI();
}
// reset mode and focus
setMoveMode();
if (mainComp.isShowing()) {
euclidianView.requestFocusInWindow();
}
}
@Override
public void updateUI() {
if (!initing) {
if (appletImpl != null) {
SwingUtilities.updateComponentTreeUI(appletImpl.getJApplet());
}
if (frame != null) {
SwingUtilities.updateComponentTreeUI(frame);
}
}
}
private void setLabels() {
if (initing) {
return;
}
if (guiManager != null) {
getGuiManager().setLabels();
kernel.setViewsLabels();
}
if (loc.propertiesFilesPresent()) {
kernel.updateLocalAxesNames();
}
updateCommandDictionary();
}
private void setOrientation() {
if (initing) {
return;
}
if (guiManager != null) {
kernel.setViewsOrientation();
}
}
protected void updateComponentTreeUI() {
if (isApplet()) {
SwingUtilities.updateComponentTreeUI(appletImpl.getJApplet());
} else if ((frame != null) && (frame == mainComp)) {
SwingUtilities.updateComponentTreeUI(frame);
} else if (mainComp != null) {
SwingUtilities.updateComponentTreeUI(mainComp);
}
}
/**
* Builds a panel with all components that should be shown on screen (like
* toolbar, input field, algebra view).
*
* @return application panel
*/
public JPanel buildApplicationPanel() {
JPanel applicationPanel = new JPanel(new BorderLayout());
// remove existing elements
if (centerPanel != null) {
centerPanel.removeAll();
} else {
centerPanel = new JPanel(new BorderLayout());
}
centerPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0,
SystemColor.controlShadow));
updateCenterPanel(true);
// full GUI => use layout manager, add other GUI elements as requested
if (isUsingFullGui()) {
// create panels if empty
if (northPanel == null) {
northPanel = new JPanel(new BorderLayout(0, 0));
}
if (southPanel == null) {
southPanel = new JPanel(new BorderLayout(0, 0));
}
if (eastPanel == null) {
eastPanel = new JPanel(new BorderLayout(0, 0));
}
if (westPanel == null) {
westPanel = new JPanel(new BorderLayout(0, 0));
}
if (dockBar == null) {
dockBar = newDockBar(this);
dockBar.setEastOrientation(isDockBarEast);
}
// clear the panels
northPanel.removeAll();
southPanel.removeAll();
eastPanel.removeAll();
westPanel.removeAll();
northPanel.removeAll();
// create a JSplitPane with the center panel as the left component.
// The right component is null initially, but can be used for
// sliding a
// help panel in/out of the center application panel.
if (applicationSplitPane == null) {
applicationSplitPane = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT, centerPanel, null);
applicationSplitPane
.setBorder(BorderFactory.createEmptyBorder());
// set all resize weight to the left pane
applicationSplitPane.setResizeWeight(1.0);
applicationSplitPane.setDividerSize(0);
}
// add north/south panels to center panel
JPanel northSouthCenter = new JPanel(new BorderLayout());
northSouthCenter.add(applicationSplitPane, BorderLayout.CENTER);
northSouthCenter.add(northPanel, BorderLayout.NORTH);
northSouthCenter.add(southPanel, BorderLayout.SOUTH);
// add east/west panels to the northSouthCenter panel
// (this puts them outside, not sandwiched between north/south)
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(northSouthCenter, BorderLayout.CENTER);
mainPanel.add(eastPanel, getLocalization().borderEast());
mainPanel.add(westPanel, getLocalization().borderWest());
applicationPanel.add(mainPanel, BorderLayout.CENTER);
if (showDockBar && !isApplet()) {
if (dockBar.isEastOrientation()) {
applicationPanel.add((Component) dockBar,
getLocalization().borderEast());
} else {
applicationPanel.add((Component) dockBar,
getLocalization().borderWest());
}
}
// configure the panel components (adds toolbar, input bar, dockbar)
updateApplicationLayout();
// init labels
setLabels();
// Special case: return application panel with menubar
// If the main component is a JPanel, we need to add the
// menubar manually to the north
if (showMenuBar() && (mainComp instanceof JPanel)) {
return getMenuBarPanel(this, applicationPanel);
}
resetFonts();
// Standard case: return application panel
return applicationPanel;
}
// Minimal applet case: return only the center panel with the EV
applicationPanel.add(
((EuclidianViewInterfaceD) euclidianView).getJPanel(),
BorderLayout.CENTER);
centerPanel.add(applicationPanel, BorderLayout.CENTER);
return applicationPanel;
}
/**
* Open/close the sidebar help panel for the input bar
*/
public void setShowInputHelpPanel(boolean isVisible) {
if (isVisible) {
applicationSplitPane
.setRightComponent((getGuiManager()).getInputHelpPanel());
if (applicationSplitPane.getLastDividerLocation() <= 0) {
applicationSplitPane.setLastDividerLocation(
applicationSplitPane.getWidth()
- (((GuiManagerD) getGuiManager()))
.getInputHelpPanelMinimumWidth());
}
applicationSplitPane.setDividerLocation(
applicationSplitPane.getLastDividerLocation());
applicationSplitPane.setDividerSize(8);
} else {
applicationSplitPane.setLastDividerLocation(
applicationSplitPane.getDividerLocation());
applicationSplitPane.setRightComponent(null);
applicationSplitPane.setDividerSize(0);
}
}
/**
* Updates the configuration of the panels surrounding the main panel
* (toolbar, input bar etc.). This method should be called when the
* visibility or arrangement of these components is changed.
*/
@Override
public void updateApplicationLayout() {
if ((northPanel == null) || (southPanel == null) || (eastPanel == null)
|| (westPanel == null)) {
return;
}
northPanel.removeAll();
southPanel.removeAll();
eastPanel.removeAll();
westPanel.removeAll();
// handle input bar
if (showAlgebraInput) {
initInputBar(this, getInputPosition() == InputPosition.top,
northPanel, southPanel);
}
if (showToolBar) {
initToolbar(this, getToolbarPosition(), showToolBarHelp, northPanel,
eastPanel, southPanel, westPanel);
}
if (frame != null && frame.getContentPane() != null) {
frame.getContentPane().validate();
}
}
public void updateCenterPanel(boolean updateUI) {
if (centerPanel == null) {
return;
}
centerPanel.removeAll();
if (isUsingFullGui()) {
centerPanel.add(getRootComponent(this), BorderLayout.CENTER);
} else {
centerPanel.add(getEuclidianView1().getJPanel(),
BorderLayout.CENTER);
}
if (updateUI) {
SwingUtilities.updateComponentTreeUI(centerPanel);
}
}
public void validateComponent() {
if (isApplet) {
appletImpl.getJApplet().validate();
} else {
frame.validate();
}
}
public void updateToolBar() {
if (!showToolBar || isIniting()) {
return;
}
getGuiManager().updateToolbar();
if (!initing) {
if (appletImpl != null) {
SwingUtilities.updateComponentTreeUI(appletImpl.getJApplet());
}
if (frame != null) {
SwingUtilities.updateComponentTreeUI(frame);
}
}
setMoveMode();
}
@Override
public void updateMenubar() {
if (!showMenuBar || !isUsingFullGui() || isIniting()) {
return;
}
getGuiManager().updateMenubar();
getGuiManager().updateActions();
}
@Override
public void updateStyleBars() {
if (!isUsingFullGui() || isIniting()) {
return;
}
if (getEuclidianView1().hasStyleBar()) {
getEuclidianView1().getStyleBar().updateStyleBar();
}
if (hasEuclidianView2(1) && getEuclidianView2(1).hasStyleBar()) {
getEuclidianView2(1).getStyleBar().updateStyleBar();
}
}
@Override
public void updateDynamicStyleBars() {
// not implemented here
}
public void updateMenuWindow() {
if (!showMenuBar || !isUsingFullGui() || isIniting()) {
return;
}
getGuiManager().updateMenuWindow();
getGuiManager().updateMenuFile();
}
public void updateTitle() {
if (frame == null) {
return;
}
getGuiManager().updateFrameTitle();
}
@Override
public void setShowToolBar(boolean toolbar, boolean help) {
super.setShowToolBar(toolbar, help);
if (toolbar && getGuiManager() != null) {
getGuiManager().setShowToolBarHelp(help);
}
}
// **************************************************************************
// GUI Getters/Setters
// **************************************************************************
protected GuiManagerInterfaceD newGuiManager() {
return newGuiManager(this);
}
/**
* @return this application's GUI manager.
*/
@Override
final public synchronized GuiManagerInterfaceD getGuiManager() {
return guiManager;
}
final public static JApplet getJApplet() {
if (appletImpl == null) {
return null;
}
return appletImpl.getJApplet();
}
public synchronized JFrame getFrame() {
if ((frame == null) && (getGuiManager() != null)) {
frame = (JFrame) getGuiManager().createFrame();
}
return frame;
}
public Component getMainComponent() {
return mainComp;
}
public Dimension getPreferredSize() {
return preferredSize;
}
@Override
public void setPreferredSize(GDimension size) {
preferredSize = GDimensionD.getAWTDimension(size);
}
public Container getContentPane() {
if (mainComp == frame) {
return frame.getContentPane();
} else if ((appletImpl != null)
&& (mainComp == appletImpl.getJApplet())) {
return appletImpl.getJApplet().getContentPane();
} else {
return null;
}
}
public JPanel getCenterPanel() {
return centerPanel;
}
@Override
public boolean showAlgebraInput() {
return showAlgebraInput;
}
@Override
public void setToolbarPosition(int position, boolean update) {
toolbarPosition = position;
if (update) {
updateApplicationLayout();
updateMenubar();
}
}
public boolean showToolBarHelp() {
return showToolBarHelp;
}
public void updateToolBarLayout() {
if (!isIniting()) {
updateApplicationLayout();
updateMenubar();
}
}
@Override
public boolean showMenuBar() {
return showMenuBar;
}
@Override
protected void hideDockBarPopup() {
if (getDockBar() != null) {
getDockBar().hidePopup();
}
}
public DockBarInterface getDockBar() {
return dockBar;
}
public boolean isShowDockBar() {
return showDockBar;
}
public boolean isDockBarEast() {
return isDockBarEast;
}
public void setDockBarEast(boolean isDockBarEast) {
this.isDockBarEast = isDockBarEast;
if (getDockBar() != null) {
dockBar.setEastOrientation(isDockBarEast);
}
}
/**
* Set show dockBar with GUI update
*
* @param showDockBar
*/
public void setShowDockBar(boolean showDockBar) {
setShowDockBar(showDockBar, true);
}
public void setShowDockBar(boolean showDockBar, boolean update) {
this.showDockBar = showDockBar;
if (update) {
updateContentPane();
}
}
// ***************************************************************************
// TOOL TIPS
// **************************************************************************
public boolean getAllowToolTips() {
return allowToolTips;
}
/**
* Sets allowToolTips flag and toggles tooltips for the application.
*/
public void setAllowToolTips(boolean allowToolTips) {
this.allowToolTips = allowToolTips;
ToolTipManager.sharedInstance().setEnabled(allowToolTips);
}
/**
* 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
*/
@Override
public String getToolTooltipHTML(int mode) {
if (loc.getTooltipLocale() != null) {
loc.setTooltipFlag();
}
String toolTipHtml = super.getToolTooltipHTML(mode);
loc.clearTooltipFlag();
return toolTipHtml;
}
// ***************************************************************************
// FONTS
// **************************************************************************
final public Font getBoldFont() {
return fontManager.getBoldFont();
}
final public Font getItalicFont() {
return fontManager.getItalicFont();
}
final public Font getPlainFont() {
return fontManager.getPlainFont();
}
@Override
final public GFont getPlainFontCommon() {
return new GFontD(fontManager.getPlainFont());
}
final public Font getSerifFont() {
return fontManager.getSerifFont();
}
final public Font getSmallFont() {
return fontManager.getSmallFont();
}
final public Font getFont(boolean serif, int style, int size) {
return fontManager.getFont(serif, style, size);
}
/**
* @return the font manager to access fonts for different tasks
*/
@Override
final public FontManagerD getFontManager() {
return fontManager;
}
// ***************************************************************************
// CURSORS
// **************************************************************************
@Override
public void setWaitCursor() {
Cursor waitCursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
mainComp.setCursor(waitCursor);
if (euclidianView != null) {
((EuclidianViewInterfaceD) getActiveEuclidianView())
.setCursor(waitCursor);
}
if (guiManager != null) {
guiManager.allowGUIToRefresh();
}
}
@Override
public void setDefaultCursor() {
mainComp.setCursor(Cursor.getDefaultCursor());
if (guiManager != null) {
for (int i = 0; i < guiManager.getEuclidianViewCount(); i++) {
if (guiManager.hasEuclidianView2EitherShowingOrNot(i)) {
((EuclidianViewInterfaceCommon) guiManager
.getEuclidianView2(i))
.setCursor(EuclidianCursor.DEFAULT);
}
}
} else if (euclidianView != null) {
getEuclidianView1().setCursor(Cursor.getDefaultCursor());
}
}
Cursor transparentCursor = null;
public Cursor getTransparentCursor() {
if (transparentCursor == null) {
int[] pixels = new int[16 * 16];
Image image = Toolkit.getDefaultToolkit()
.createImage(new MemoryImageSource(16, 16, pixels, 0, 16));
transparentCursor = Toolkit.getDefaultToolkit().createCustomCursor(
image, new Point(0, 0), "invisibleCursor");
}
return transparentCursor;
}
Cursor eraserCursor = null;
public Cursor getEraserCursor() {
if (eraserCursor == null) {
int size = 32;
/*
* we need two buffered images as the cursor only supports on/off
* for alpha
*
* so we need to draw to an image without alpha support then draw
* that to one with alpha support then make "white" transparent
*/
BufferedImage image = new BufferedImage(size, size,
BufferedImage.TYPE_INT_RGB);
BufferedImage image2 = new BufferedImage(size, size,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
Graphics2D g2 = image2.createGraphics();
g.setColor(Color.white);
g.fillRect(0, 0, size, size);
// turn on anti-aliasing.
g.setStroke(new BasicStroke(4.0f)); // 4-pixel lines
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(new Color(0.5f, 0f, 0f));
g.drawOval(3, 3, size - 7, size - 7);
g2.drawImage(image, 0, 0, Color.white, null);
for (int y = 0; y < size; y++) {
for (int x = 0; x < size; x++) {
int rgb = image.getRGB(x, y);
int blue = rgb & 0xff;
int green = (rgb & 0xff00) >> 8;
int red = (rgb & 0xff0000) >> 16;
// int alpha = (rgb & 0xff000000) >> 24;
if (red == 255 && green == 255 && blue == 255) {
// make white transparent
image2.setRGB(x, y, 0);
}
}
}
eraserCursor = Toolkit.getDefaultToolkit().createCustomCursor(
image2, new Point(size / 2, size / 2), "eraserCursor");
}
return eraserCursor;
}
// **************************************************************************
// EXIT
// **************************************************************************
/**
* // think about this Downloads the latest jar files from the GeoGebra
* server.
*
* private void updateGeoGebra() { try { File dest = new File(codebase +
* Application.JAR_FILE); URL jarURL = new URL(Application.UPDATE_URL +
* Application.JAR_FILE);
*
* if (dest.exists()) { // check if jarURL is newer then dest try {
* URLConnection connection = jarURL.openConnection(); if
* (connection.getLastModified() <= dest.lastModified()) { showMessage("No
* update available"); return; } } catch (Exception e) { // we don't know if
* the file behind jarURL is newer than dest // so don't do anything
* showMessage("No update available: " + (e.getMessage())); return; } } //
* copy JAR_FILE if (!CopyURLToFile.copyURLToFile(this, jarURL, dest))
* return; // copy properties file dest = new File(codebase +
* Application.PROPERTIES_FILE); jarURL = new URL(Application.UPDATE_URL +
* Application.PROPERTIES_FILE); if (!CopyURLToFile.copyURLToFile(this,
* jarURL, dest)) return; // copy jscl file dest = new File(codebase +
* Application.JSCL_FILE); jarURL = new URL(Application.UPDATE_URL +
* Application.JSCL_FILE); if (!CopyURLToFile.copyURLToFile(this, jarURL,
* dest)) return;
*
*
* showMessage("Update finished. Please restart GeoGebra."); } catch
* (Exception e) { showError("Update failed: "+ e.getMessage()); } }
*/
/**
* Clears the current construction. Used for File-New.
*/
@Override
public boolean clearConstruction() {
if (isSaved() || saveCurrentFile()) {
kernel.clearConstruction(true);
kernel.initUndoInfo();
resetMaxLayerUsed();
setCurrentFile(null);
setMoveMode();
return true;
}
return false;
}
public void exit() {
// glassPane is active: don't exit now!
if (glassPaneListener != null) {
return;
}
// stop sound thread if currently playing
if (getSoundManager() != null) {
getSoundManager().stopCurrentSound();
}
if (isSaved() || (appletImpl != null) || saveCurrentFile()) {
if (appletImpl != null) {
setApplet(appletImpl);
appletImpl.showApplet();
} else {
exitFrame();
}
}
}
protected void exitFrame() {
frame.setVisible(false);
if (getGuiManager() != null) {
getGuiManager().exitAllCurrent();
}
}
@Override
public synchronized void exitAll() {
// glassPane is active: don't exit now!
if (glassPaneListener != null) {
return;
}
GuiManagerD.exitAll();
}
// returns true for YES or NO and false for CANCEL
public boolean saveCurrentFile() {
return getGuiManager().saveCurrentFile();
}
// **************************************************************************
// SAVE / LOAD
// **************************************************************************
/**
* Load file
*/
public boolean loadFile(File file, boolean isMacroFile) {
if (!checkFileExistsAndShowFileNotFound(file)) {
return false;
}
return loadExistingFile(file, isMacroFile);
}
private OFFHandler offHandler;
public boolean loadOffFile(File file) {
if (!checkFileExistsAndShowFileNotFound(file)) {
return false;
}
boolean status = true;
try {
OFFReader reader = new OFFReader();
if (!initing) {
initing = true;
reader.parse(file, getOFFHandler());
initing = false;
} else {
reader.parse(file, getOFFHandler());
}
} catch (Exception ex) {
status = false;
ex.printStackTrace();
}
return status;
}
protected final boolean checkFileExistsAndShowFileNotFound(File file) {
// show file not found message
if (!file.exists()) {
/*
* First parameter can not be the main component of the application,
* otherwise that component would be validated too early if a
* missing file was loaded through the command line, which causes
* some nasty rendering problems.
*/
JOptionPane.showConfirmDialog(null,
getLocalization().getError("FileNotFound") + ":\n"
+ file.getAbsolutePath(),
getLocalization().getError("Error"),
JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE);
return false;
}
return true;
}
public boolean loadExistingFile(File file, boolean isMacroFile) {
setWaitCursor();
if (!isMacroFile) {
// hide navigation bar for construction steps if visible
setHideConstructionProtocolNavigation();
}
boolean success = loadXML(file, isMacroFile);
try {
createRegressionFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return success;
}
/**
* Loads construction file
*
* @return true if successful
*/
final public boolean loadXML(File file, boolean isMacroFile) {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
boolean success = false;
// pretend we're initializing the application to prevent unnecessary
// update
if (!initing) {
initing = true;
success = loadXML(fis, isMacroFile);
initing = false;
} else {
success = loadXML(fis, isMacroFile);
}
if (success && !isMacroFile) {
setCurrentFile(file);
}
return success;
} catch (Exception e) {
setCurrentFile(null);
e.printStackTrace();
showError(getLocalization().getError("LoadFileFailed") + ":\n"
+ file);
return false;
} finally {
initing = false;
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* Loads construction file from URL
*
* @return true if successful
*/
final public boolean loadXML(URL url, boolean isMacroFile) {
try {
boolean success = loadXML(url.openStream(), isMacroFile);
// don't clear JavaScript here -- we may have just read one from the
// file.
// MyXMLio.readZip() handles script resetting
// set current file
if (!isMacroFile && url.toExternalForm().startsWith("file")) {
String path = url.getPath();
path = path.replaceAll("%20", " ");
File f = new File(path);
if (f.exists()) {
setCurrentFile(f);
}
}
return success;
} catch (Exception e) {
showError("LoadFileFailed", e.getMessage());
setCurrentFile(null);
return false;
}
}
/*
* loads an XML file as a String
*/
@Override
public boolean loadXML(String xml) {
try {
// make sure objects are displayed in the correct View
setActiveView(App.VIEW_EUCLIDIAN);
getXMLio().processXMLString(xml, true, false);
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;
}
}
private boolean loadXML(InputStream is, boolean isMacroFile)
throws Exception {
try {
if (!isMacroFile) {
setMoveMode();
}
// store current location of the window
storeFrameCenter();
// make sure objects are displayed in the correct View
setActiveView(App.VIEW_EUCLIDIAN);
// reset unique id (for old files, in case they don't have one)
resetUniqueId();
BufferedInputStream bis = new BufferedInputStream(is);
if (bis.markSupported()) {
bis.mark(Integer.MAX_VALUE);
BufferedReader reader = new BufferedReader(
new InputStreamReader(bis, Charsets.UTF_8));
String str = reader.readLine();
// check if .ggb file is actually a base64 file from 4.2 Chrome
// App
if (str != null && str.startsWith("UEs")) {
StringBuilder sb = new StringBuilder(str);
sb.append("\n");
while ((str = reader.readLine()) != null) {
sb.append(str + "\n");
}
reader.close();
is.close();
bis.close();
byte[] zipFile = Base64.decode(sb.toString());
return loadXML(zipFile);
}
bis.reset();
}
getXMLio().readZipFromInputStream(bis, isMacroFile);
is.close();
bis.close();
if (!isMacroFile) {
kernel.initUndoInfo();
setSaved();
setCurrentFile(null);
}
// command list may have changed due to macros
updateCommandDictionary();
hideDockBarPopup();
return true;
} catch (MyError err) {
setCurrentFile(null);
showError(err);
return false;
}
}
private int centerX, centerY;
private void storeFrameCenter() {
centerX = getWindowCenterX();
centerY = getWindowCenterY();
}
public void centerFrame() {
// re-center window
if (frame != null) {
int x0 = centerX - frame.getWidth() / 2;
if (x0 < 0) {
x0 = 0;
}
int y0 = centerY - frame.getHeight() / 2;
if (y0 < 0) {
y0 = 0;
}
frame.setLocation(x0, y0);
}
}
/**
* Saves all objects.
*
* @return true if successful
*/
public boolean saveGeoGebraFile(File file) {
try {
setWaitCursor();
getXMLio().writeGeoGebraFile(file);
setSaved();
setDefaultCursor();
return true;
} catch (Exception e) {
setDefaultCursor();
showError("SaveFileFailed");
e.printStackTrace();
return false;
}
}
/**
* Saves given macros to file.
*
* @return true if successful
*/
final public boolean saveMacroFile(File file, ArrayList<Macro> macros) {
try {
setWaitCursor();
getXMLio().writeMacroFile(file, macros);
setDefaultCursor();
return true;
} catch (Exception e) {
setDefaultCursor();
showError("SaveFileFailed");
e.printStackTrace();
return false;
}
}
@Override
public void setXML(String xml, boolean clearAll) {
if (xml == null) {
return;
}
if (clearAll) {
setCurrentFile(null);
}
try {
// make sure objects are displayed in the correct View
setActiveView(App.VIEW_EUCLIDIAN);
getXMLio().processXMLString(xml, clearAll, false);
} catch (MyError err) {
err.printStackTrace();
showError(err);
} catch (Exception e) {
e.printStackTrace();
showError("LoadFileFailed");
}
}
public byte[] getMacroFileAsByteArray() {
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
getXMLio().writeMacroStream(os, kernel.getAllMacros());
os.flush();
return os.toByteArray();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public void loadMacroFileFromByteArray(byte[] byteArray,
boolean removeOldMacros) {
try {
if (removeOldMacros) {
kernel.removeAllMacros();
}
if (byteArray != null) {
ByteArrayInputStream is = new ByteArrayInputStream(byteArray);
getXMLio().readZipFromInputStream(is, true);
is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
final public MyXMLioD getXMLio() {
return (MyXMLioD) super.getXMLio();
}
public OFFHandler getOFFHandler() {
if (offHandler == null) {
offHandler = new OFFHandler(kernel.getConstruction());
}
return offHandler;
}
@Override
public MyXMLioD createXMLio(Construction cons) {
return new MyXMLioD(cons.getKernel(), cons);
}
@Override
public void storeUndoInfo() {
if (isUndoActive()) {
kernel.storeUndoInfo();
setUnsaved();
}
}
public void restoreCurrentUndoInfo() {
if (isUndoActive()) {
kernel.restoreCurrentUndoInfo();
setUnsaved();
}
}
@Override
protected int getWindowWidth() {
if ((frame != null) && (frame.getWidth() > 0)) {
return frame.getWidth();
}
return 800;
}
@Override
protected int getWindowHeight() {
if ((frame != null) && (frame.getHeight() > 0)) {
return frame.getHeight();
}
return 600;
}
private int getWindowCenterX() {
if (frame != null) {
return frame.getX() + frame.getWidth() / 2;
}
return 400;
}
private int getWindowCenterY() {
if (frame != null) {
return frame.getY() + frame.getHeight() / 2;
}
return 300;
}
/*
* final public void clearAll() { // load preferences
* GeoGebraPreferences.loadXMLPreferences(this); updateContentPane(); //
* clear construction kernel.clearConstruction(); kernel.initUndoInfo();
*
* isSaved = true; System.gc(); }
*/
@Override
protected void getLayoutXML(StringBuilder sb, boolean asPreference) {
if (guiManager == null) {
initGuiManager();
}
getGuiManager().getLayout().getXml(sb, asPreference);
}
/**
* Returns the CodeBase URL.
*/
public static URL getCodeBase() {
if (codebase == null) {
initCodeBase();
}
return codebase;
}
private static URL codebase;
private static boolean runningFromJar = false;
final private static String packgz = ".pack.gz";
private static void initCodeBase() {
try {
// application codebase
String path = GeoGebra.class.getProtectionDomain().getCodeSource()
.getLocation().toExternalForm();
// remove .pack.gz from end
// not sure why we've started getting this (maybe when using the
// mirror servers?)
// eg Codebase:
// http://jars.geogebra.org/webstart/4.2/jnlp/geogebra.jar.pack.gz
if (path.endsWith(packgz)) {
path = path.substring(0, path.length() - packgz.length());
}
// remove "geogebra.jar" from end of codebase string
for (int i = 0; i < GEOGEBRA_JAR_ALT.length; ++i) {
if (path.endsWith(GEOGEBRA_JAR_ALT[i])) {
runningFromJar = true;
path = path.substring(0,
path.length() - GEOGEBRA_JAR_ALT[i].length());
}
}
// set codebase
codebase = new URL(path);
} catch (Exception e) {
Log.info("GeoGebra is running with restricted permissions.");
// make sure temporary files not used
// eg ggbApi.getPNGBase64()
ImageIO.setUseCache(false);
if (appletImpl != null) {
// applet codebase
codebase = appletImpl.getJApplet().getCodeBase();
}
}
}
// **************************************************************************
// EVENT DISPATCHING
// **************************************************************************
private GlassPaneListener glassPaneListener;
private ErrorHandler defaultErrorHandler;
public void startDispatchingEventsTo(JComponent comp) {
if (guiManager != null) {
getDialogManager().closeAll();
}
if (glassPaneListener == null) {
Component glassPane = getGlassPane();
glassPaneListener = new GlassPaneListener(glassPane,
getContentPane(), comp);
// mouse
glassPane.addMouseListener(glassPaneListener);
glassPane.addMouseMotionListener(glassPaneListener);
// keys
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addKeyEventDispatcher(glassPaneListener);
glassPane.setVisible(true);
}
}
public void stopDispatchingEvents() {
if (glassPaneListener != null) {
Component glassPane = getGlassPane();
glassPane.removeMouseListener(glassPaneListener);
glassPane.removeMouseMotionListener(glassPaneListener);
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.removeKeyEventDispatcher(glassPaneListener);
glassPane.setVisible(false);
glassPaneListener = null;
}
}
public Component getGlassPane() {
if (mainComp == frame) {
return frame.getGlassPane();
} else if ((appletImpl != null)
&& (mainComp == appletImpl.getJApplet())) {
return appletImpl.getJApplet().getGlassPane();
} else {
return null;
}
}
public void setGlassPane(Component component) {
if ((appletImpl != null) && (mainComp == appletImpl.getJApplet())) {
appletImpl.getJApplet().setGlassPane(component);
} else if (mainComp == frame) {
frame.setGlassPane(component);
}
}
// **************************************************************************
// KEY EVENTS
// **************************************************************************
/*
* KeyEventDispatcher implementation to handle key events globally for the
* application
*/
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
// make sure the event is not consumed
if (e.isConsumed()) {
return true;
}
controlDown = isControlDown(e);
shiftDown = e.isShiftDown();
// check if key event came from this main component
// (needed to take care of multiple application windows or applets)
Component eventPane = SwingUtilities.getRootPane(e.getComponent());
Component mainPane = SwingUtilities.getRootPane(mainComp);
if (eventPane != mainPane) {
// ESC from dialog: close it
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
Component rootComp = SwingUtilities.getRoot(e.getComponent());
if (rootComp instanceof JDialog) {
((JDialog) rootComp).setVisible(false);
return true;
}
}
// key event came from another window or applet: ignore it
if (isApplet() || !inExternalWindow(this, eventPane)) {
return false;
}
} else if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
handleShiftEvent(shiftDown);
}
// if the glass pane is visible, don't do anything
// (there might be an animation running)
Component glassPane = getGlassPane();
if ((glassPane != null) && glassPane.isVisible()) {
return false;
}
// handle global keys like ESC and function keys
return getGlobalKeyDispatcher().dispatchKeyEvent(e);
}
/**
* handle shift key pressed or released
*
* @param isShiftDown
* whether shift is pressed
*/
protected void handleShiftEvent(boolean isShiftDown) {
// we may overwrite in subclasses
}
@Override
final public GlobalKeyDispatcherD getGlobalKeyDispatcher() {
if (globalKeyDispatcher == null) {
globalKeyDispatcher = newGlobalKeyDispatcher();
}
return globalKeyDispatcher;
}
protected GlobalKeyDispatcherD newGlobalKeyDispatcher() {
return new GlobalKeyDispatcherD(this);
}
/*
* check for alt pressed (but not ctrl) (or ctrl but not alt on MacOS)
*/
public static boolean isAltDown(InputEvent e) {
// we don't want to act when AltGr is down
// as it is used eg for entering {[}] is some locales
// NB e.isAltGraphDown() doesn't work
if (e.isAltDown() && e.isControlDown()) {
return false;
}
return MAC_OS ? e.isControlDown() : e.isAltDown();
}
// global controlDown, shiftDown flags
// Application.dispatchKeyEvent sets these on every keyEvent.
private boolean controlDown = false;
private boolean shiftDown = false;
public boolean getControlDown() {
return controlDown;
}
public boolean getShiftDown() {
return shiftDown;
}
public static boolean isControlDown(InputEvent e) {
return isControlDown(e.isMetaDown(), e.isControlDown());
}
public static final boolean isControlDown(boolean isMetaDown,
boolean isControlDown) {
/*
* debug("isMetaDown = "+e.isMetaDown()); debug("isControlDown =
* "+e.isControlDown()); debug("isShiftDown = "+e.isShiftDown()); debug(
* "isAltDown = "+e.isAltDown()); debug("isAltGrDown =
* "+e.isAltGraphDown()); debug("fakeRightClick = "+fakeRightClick);
*/
if (fakeRightClick) {
return false;
}
boolean ret = (MAC_OS && isMetaDown) // Mac: meta down for
// multiple
// selection
|| (!MAC_OS && isControlDown); // non-Mac: Ctrl down for
// multiple selection
// debug("isPopupTrigger = "+e.isPopupTrigger());
// debug("ret = " + ret);
return ret;
// return e.isControlDown();
}
private static boolean fakeRightClick = false;
public static boolean isMiddleClick(MouseEventND e) {
return e.isMiddleClick();
}
public static boolean isRightClick(MouseEvent e) {
// right-click returns isMetaDown on MAC_OS
// so we want to return true for isMetaDown
// if it occurred first at the same time as
// a popup trigger
if (MAC_OS && !e.isMetaDown()) {
fakeRightClick = false;
}
if (MAC_OS && e.isPopupTrigger() && e.isMetaDown()) {
fakeRightClick = true;
}
/*
* debug("MAC_OS = "+MAC_OS); debug("isMetaDown = "+e.isMetaDown());
* debug("isControlDown ="+e.isControlDown()); debug("isShiftDown = "
* +e.isShiftDown()); debug("isAltDown = "+e.isAltDown()); debug(
* "isAltGrDown ="+e.isAltGraphDown()); debug("isPopupTrigger = "
* +e.isPopupTrigger()); debug("fakeRightClick = "+fakeRightClick);
*/
if (fakeRightClick) {
return true;
}
boolean ret =
// e.isPopupTrigger() ||
(MAC_OS && e.isControlDown()) // Mac: ctrl click = right click
|| (!MAC_OS && e.isMetaDown()); // non-Mac: right click
// = meta
// click
// debug("ret = " + ret);
return ret;
// return e.isMetaDown();
}
public static boolean isRightClickForceMetaDown(MouseEvent e) {
boolean ret =
// e.isPopupTrigger() ||
(MAC_OS && e.isControlDown()) // Mac: ctrl click = right click
|| (e.isMetaDown()); // non-Mac: right click = meta
// click
// debug("ret = " + ret);
return ret;
// return e.isMetaDown();
}
public void removeTraversableKeys(JPanel p) {
Set<AWTKeyStroke> set = p.getFocusTraversalKeys(
KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
set.clear();
p.setFocusTraversalKeys(KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
set);
p.setFocusTraversalKeys(KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS,
set);
p.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
set);
p.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
set);
}
// **************************************************************************
// ERROR HANDLING
// **************************************************************************
@Override
public void showError(String key) {
showErrorDialog(key);
}
@Override
public void showError(String key, String error) {
showErrorDialog(getLocalization().getError(key) + ":\n" + error);
}
/**
* Show error dialog with given message
*
* @param msg
* (localized) message
*/
@Override
public void showErrorDialog(final String msg) {
if (!isErrorDialogsActive()) {
return;
}
if (this.getErrorHandler() != null) {
this.getErrorHandler().showError(msg);
return;
}
}
@Override
public ErrorHandler getDefaultErrorHandler() {
if (defaultErrorHandler == null) {
defaultErrorHandler = new ErrorHandler() {
@Override
public void showError(final String msg) {
// don't remove, useful
if (msg == null) {
return;
}
Log.printStacktrace("" + msg);
// make sure splash screen not showing (will be in front)
GeoGebra.hideSplash();
isErrorDialogShowing = true;
final String msgDisplay = msg.substring(0,
Math.min(msg.length(), 1000));
// use SwingUtilities to make sure this gets executed in the
// correct
// (=GUI) thread.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// TODO investigate why this freezes Firefox
// sometimes
JOptionPane.showConfirmDialog(
mainComp,
msgDisplay,
GeoGebraConstants.APPLICATION_NAME + " - "
+ getLocalization()
.getError("Error"),
JOptionPane.DEFAULT_OPTION,
JOptionPane.WARNING_MESSAGE);
isErrorDialogShowing = false;
}
});
}
@Override
public void resetError() {
showError(null);
}
@Override
public boolean onUndefinedVariables(String string,
AsyncOperation<String[]> callback) {
return getGuiManager().checkAutoCreateSliders(string,
callback);
}
@Override
public void showCommandError(String command, String message) {
// make sure splash screen not showing (will be in front)
GeoGebra.hideSplash();
Object[] options = { getLocalization().getPlain("OK"),
getLocalization().getPlain("ShowOnlineHelp") };
int n = JOptionPane.showOptionDialog(mainComp, message,
GeoGebraConstants.APPLICATION_NAME + " - "
+ getLocalization().getError("Error"),
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE, null, // do
// not
// use
// a
// custom
// Icon
options, // the titles of buttons
options[0]); // default button title
if (n == 1) {
getGuiManager().openCommandHelp(command);
}
}
@Override
public String getCurrentCommand() {
return null;
}
};
}
return defaultErrorHandler;
}
/**
* @return whether there is an open error dialog
*/
public boolean isErrorDialogShowing() {
return isErrorDialogShowing;
}
public void showMessage(final String message) {
// use SwingUtilities to make sure this gets executed in the correct
// (=GUI) thread.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JOptionPane.showConfirmDialog(mainComp, message,
GeoGebraConstants.APPLICATION_NAME + " - "
+ getLocalization().getMenu("Info"),
JOptionPane.DEFAULT_OPTION,
JOptionPane.INFORMATION_MESSAGE);
}
});
}
public static void printStacktrace(String message) {
try {
throw new Exception(message);
} catch (Exception e) {
e.printStackTrace();
}
}
// **************************************************************************
// SCRIPTING: GgbAPI/PYTHON
// **************************************************************************
/**
* PluginManager gets API with this H-P Ulven 2008-04-16
*/
@Override
public GgbAPID getGgbApi() {
if (ggbapi == null) {
ggbapi = new GgbAPID(this);
}
return ggbapi;
}
@Override
protected ScriptManager newScriptManager() {
return new ScriptManagerD(this);
}
// **************************************************************************
// LOGGING
// **************************************************************************
LogManager logManager;
// String logFile = DownloadManager.getTempDir()+"GeoGebraLog.txt";
// public String logFile = "c:\\GeoGebraLog.txt";
public StringBuilder logFile = null;
/*
* code from
* http://blogs.sun.com/nickstephen/entry/java_redirecting_system_out_and
*/
private void setUpLogging() {
Log.debug("Setting up logging");
if (Log.getLogDestination() == LogDestination.FILE) {
// File logging already set up, don't override:
Log.debug(
"Logging into explicitly defined file into GeoGebraLogger, not using LogManager");
return;
}
// initialize logging to go to rolling log file
logManager = LogManager.getLogManager();
logManager.reset();
logFile = new StringBuilder(30);
logFile.append(UtilD.getTempDir());
logFile.append("GeoGebraLog_");
// randomize filename
for (int i = 0; i < 10; i++) {
logFile.append((char) ('a' + Math.round(Math.random() * 25)));
}
logFile.append(".txt");
Log.debug("Logging is redirected to " + logFile.toString());
Log.setTimeShown(false); // do not print the time twice
// log file max size 10K, 1 file, append-on-open
Handler fileHandler;
try {
fileHandler = new FileHandler(logFile.toString(),
Log.LOGFILE_MAXLENGTH, 1, false);
} catch (Exception e) {
logFile = null;
return;
}
fileHandler.setFormatter(new SimpleFormatter());
Logger.getLogger("").addHandler(fileHandler);
// preserve old stdout/stderr streams in case they might be useful
// PrintStream stdout = System.out;
// PrintStream stderr = System.err;
// now rebind stdout/stderr to logger
Logger logger;
LoggingOutputStream los;
logger = Logger.getLogger("stdout");
los = new LoggingOutputStream(logger, StdOutErrLevel.STDOUT);
try {
System.setOut(new PrintStream(los, true, Charsets.UTF_8));
logger = Logger.getLogger("stderr");
los = new LoggingOutputStream(logger, StdOutErrLevel.STDERR);
System.setErr(new PrintStream(los, true, Charsets.UTF_8));
} catch (UnsupportedEncodingException e) {
// do nothing
}
// show stdout going to logger
// System.out.println("Hello world!");
// now log a message using a normal logger
// logger = Logger.getLogger("test");
// logger.info("This is a test log message");
// now show stderr stack trace going to logger
// try {
// throw new RuntimeException("Test");
// } catch (Exception e) {
// e.printStackTrace();
// }
// and output on the original stdout
// stdout.println("Hello on old stdout");
}
/*
* gets a String from the clipboard
*
* @return null if not possible
*/
public String getStringFromClipboard() {
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
Transferable contents = clipboard.getContents(null);
String str = null;
try {
str = (String) contents.getTransferData(DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException e) {
if (contents.getTransferDataFlavors() != null
&& contents.getTransferDataFlavors().length > 0) {
Log.debug(contents.getTransferDataFlavors()[0]);
}
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
// **************************************************************************
// SOUNDS
// **************************************************************************
private SoundManagerD soundManager = null;
@Override
public SoundManagerD getSoundManager() {
if (soundManager == null) {
soundManager = new SoundManagerD(this);
}
return soundManager;
}
/*
* public void checkCommands(HashMap<String, CommandProcessor> map) {
* initTranslatedCommands();
*
* if (rbcommand == null) { return; // eg applet with no properties jar }
*
* Enumeration<String> e = rbcommand.getKeys(); while (e.hasMoreElements())
* { String s = e.nextElement(); if (!s.contains(syntaxStr) && (map.get(s)
* == null)) { boolean write = true; try { rbcommand.getString(s +
* syntaxStr); } catch (Exception ex) { write = false; } if (write) { debug(
* "checkCommands: " + s); } } } }
*/
@Override
public void setScrollToShow(boolean b) {
if (guiManager != null) {
guiManager.setScrollToShow(b);
}
}
DrawEquationD drawEquation;
@Override
public DrawEquationD getDrawEquation() {
if (drawEquation == null) {
drawEquation = new DrawEquationD();
}
return drawEquation;
}
// random id to identify ggb files
// eg so that GeoGebraTube can notice it's a version of the same file
@Override
public void resetUniqueId() {
uniqueId = "" + UUID.randomUUID();
setTubeId(0);
}
// //////////////////////////////////
// FILE VERSION HANDLING
// //////////////////////////////////
private DialogManager dialogManager;
private OpenFromGGTOperation openFromGGTOperation;
@Override
public void callAppletJavaScript(String string, Object[] args) {
getApplet().callJavaScript(string, args);
}
@Override
public boolean showView(int view) {
if (getGuiManager() == null) {
return view == App.VIEW_EUCLIDIAN;
}
return getGuiManager().showView(view);
}
@Override
public void evalJavaScript(App app, String script, String arg)
throws Exception {
((ScriptManagerD) getScriptManager()).evalJavaScript(app, script, arg);
}
@Override
public int getMD5folderLength(String fullPath) {
return fullPath.indexOf(File.separator);
}
// TODO: should be moved to ApplicationSettings
@Override
public void setTooltipTimeout(int ttt) {
if (ttt > 0) {
ToolTipManager.sharedInstance().setDismissDelay(ttt * 1000);
// make it fit into tooltipTimeouts array:
ToolTipManager.sharedInstance()
.setDismissDelay(getTooltipTimeout() * 1000);
} else {
ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE);
}
}
@Override
public double getWidth() {
if (isApplet()) {
AppletImplementation applet = getApplet();
return applet.width;
}
JPanel appCP = getCenterPanel();
return appCP != null ? appCP.getWidth() : 0;
}
@Override
public double getHeight() {
if (isApplet()) {
AppletImplementation applet = getApplet();
return applet.height;
}
JPanel appCP = getCenterPanel();
return appCP != null ? appCP.getHeight() : 0;
}
@Override
public GFont getFontCommon(boolean b, int i, int size) {
return new GFontD(getFont(b, i, size));
}
public GFont getBoldFontCommon() {
return new GFontD(getBoldFont());
}
@Override
public void repaintSpreadsheet() {
if (getGuiManager() != null && getGuiManager().hasSpreadsheetView()) {
getGuiManager().getSpreadsheetView().repaintView();
}
}
@Override
public UndoManagerD getUndoManager(Construction cons) {
return new UndoManagerD(cons);
}
@Override
public GeoElementGraphicsAdapter newGeoElementGraphicsAdapter() {
return new GeoElementGraphicsAdapterD(this);
}
@Override
public SpreadsheetTableModel getSpreadsheetTableModel() {
if (tableModel == null) {
tableModel = new SpreadsheetTableModelD(this, SPREADSHEET_INI_ROWS,
SPREADSHEET_INI_COLS);
}
return tableModel;
}
@Override
public boolean isRightClick(AbstractEvent e) {
return isRightClick(MouseEventD.getEvent(e));
}
@Override
public boolean isControlDown(AbstractEvent e) {
return e != null && isControlDown(e.isMetaDown(), e.isControlDown());
}
@Override
public boolean isMiddleClick(AbstractEvent e) {
return isMiddleClick((MouseEventND) e);
}
public Font getFontCanDisplayAwt(String string, boolean b, int plain,
int i) {
return getFontManager().getFontCanDisplayAwt(string, b, plain, i);
}
public Font getFontCanDisplayAwt(String string) {
return GFontD.getAwtFont(getFontCanDisplay(string));
}
public Font getFontCanDisplayAwt(String value, int plain) {
return GFontD.getAwtFont(getFontCanDisplay(value, plain));
}
@Override
public boolean isMacOS() {
return MAC_OS;
}
@Override
public boolean isWindows() {
return WINDOWS;
}
@Override
public boolean isWindowsVistaOrLater() {
return WINDOWS_VISTA_OR_LATER;
}
/**
* Whether we are using Java 7 (can't use clipboard on OSX)
*
* @return whether we are using Java 7
*/
public boolean isJava7() {
return System.getProperty("java.version").startsWith("1.7.");
}
/*
* current possible values http://mindprod.com/jgloss/properties.html AIX
* Digital Unix FreeBSD HP UX Irix Linux Mac OS Mac OS X MPE/iX Netware 4.11
* OS/2 Solaris Windows 2000 Windows 7 Windows 95 Windows 98 Windows NT
* Windows Vista Windows XP
*/
private static final String OS = StringUtil
.toLowerCase(System.getProperty("os.name"));
public static final boolean MAC_OS = OS.startsWith("mac");
public static final boolean WINDOWS = OS.startsWith("windows");
public static final boolean LINUX = OS.startsWith("linux");
// make sure still works in the future on eg Windows 10/11
// note Java 7u40 returns "Windows 8" for Windows 8.1 and Windows 10
private static final boolean WINDOWS_XP_OR_EARLIER = OS
.startsWith("windows 2000") || OS.startsWith("windows 95")
|| OS.startsWith("windows 98") || OS.startsWith("windows nt")
|| OS.startsWith("windows xp");
public static final boolean WINDOWS_VISTA_OR_LATER = WINDOWS
&& !WINDOWS_XP_OR_EARLIER;
public static final boolean WINDOWS_VISTA_OR_EARLIER = WINDOWS_XP_OR_EARLIER
|| OS.startsWith("windows vista");
@Override
public boolean isHTML5Applet() {
return false;
}
@Override
public DialogManagerMinimal getDialogManager() {
if (dialogManager == null) {
if (getGuiManager() == null) {
dialogManager = new DialogManagerMinimal(this);
} else {
dialogManager = getGuiManager().getDialogManager();
}
}
return (DialogManagerMinimal) dialogManager;
}
@Override
public void showURLinBrowser(String strURL) {
getGuiManager().showURLinBrowser(strURL);
}
@Override
public void uploadToGeoGebraTube() {
GeoGebraTubeExportD ggbtube = new GeoGebraTubeExportD(this);
ggbtube.uploadWorksheet(null);
}
@Override
public LowerCaseDictionary newLowerCaseDictionary() {
return new LowerCaseDictionary(Normalizer.getInstance());
}
public CommandLineArguments getCommandLineArgs() {
return cmdArgs;
}
/**
*
* return Left/Right as appropriate for eg Hebrew / Arabic
*
* return int rather than FlowLayout.LEFT so we're not dependent on awt
*/
public int flowLeft() {
if (!getLocalization().isRightToLeftReadingOrder()) {
return 0; // left
}
return 2; // right
}
/**
*
* return Left/Right as appropriate for eg Hebrew / Arabic
*
* return int rather than FlowLayout.RIGHT so we're not dependent on awt
*/
public int flowRight() {
if (getLocalization().isRightToLeftReadingOrder()) {
return 0; // left
}
return 2; // right
}
/**
* @param c
* component calling for repaint
*/
public void repaintEuclidianViews(Component c) {
ComponentEvent event = new ComponentEvent(c,
ComponentEvent.COMPONENT_RESIZED);
getEuclidianView1().dispatchEvent(event);
getEuclidianView2(1).dispatchEvent(event);
}
/**
*
* @return eg Java 1.7.0_03-64bit
*/
public static String getJavaVersion() {
return appendJavaVersion(new StringBuilder(19)).toString();
}
/**
*
* @param sb
* StringBuilder
* @return StringBuilder with eg "Java 1.7.0_03-64bit" added
*/
public static StringBuilder appendJavaVersion(StringBuilder sb) {
sb.append(System.getProperty("java.version"));
String arch = System.getProperty("os.arch");
if (arch == null || "".equals(arch)) {
return sb;
}
sb.append('-');
if ("x86".equals(arch) || "ppc".equals(arch) || "i386".equals(arch)) {
sb.append("32bit");
} else if ("amd64".equals(arch) || "x86_64".equals(arch)) {
sb.append("64bit");
} else {
sb.append(arch);
}
return sb;
}
@Override
public NormalizerMinimal getNormalizer() {
return Normalizer.getInstance();
}
@Override
public void runScripts(final GeoElement geo1, final String string) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
geo1.runClickScripts(string);
}
});
}
@Override
public CASFactory getCASFactory() {
CASFactory ret = CASFactory.getPrototype();
if (ret == null) {
ret = new CASFactoryD();
CASFactory.setPrototype(ret);
}
return ret;
}
@Override
public Factory getFactory() {
Factory ret = Factory.getPrototype();
if (ret == null) {
ret = new FactoryD();
Factory.setPrototype(ret);
}
return ret;
}
// **************************************************************************
// COMPONENT ORIENTATION
// **************************************************************************
public ComponentOrientation getComponentOrientation() {
return getLocalization().isRightToLeftReadingOrder()
? ComponentOrientation.RIGHT_TO_LEFT
: ComponentOrientation.LEFT_TO_RIGHT;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void setComponentOrientation(Component c) {
boolean rtl = getLocalization().isRightToLeftReadingOrder();
ComponentOrientation orientation = rtl
? ComponentOrientation.RIGHT_TO_LEFT
: ComponentOrientation.LEFT_TO_RIGHT;
c.setComponentOrientation(orientation);
// c.applyComponentOrientation(orientation);
if (c instanceof JMenu) {
JMenu menu = (JMenu) c;
int ncomponents = menu.getMenuComponentCount();
for (int i = 0; i < ncomponents; ++i) {
setComponentOrientation(menu.getMenuComponent(i));
}
} else if (c instanceof JTextField) {
((JTextField) c).setHorizontalAlignment(
rtl ? SwingConstants.RIGHT : SwingConstants.LEFT);
} else if (c instanceof JComboBox) {
JComboBox cb = (JComboBox) c;
ListCellRenderer renderer = cb.getRenderer();
if (!(renderer instanceof DashListRenderer
|| renderer instanceof DecorationListRenderer
|| renderer instanceof AxesStyleListRenderer
|| renderer instanceof PointStyleListRenderer)) {
// if we didn't load GUI yet, assume there is no tool creation
// dialog
if (getGuiManager() == null
|| !getGuiManager().belongsToToolCreator(renderer)) {
renderer = new DefaultListCellRenderer();
cb.setRenderer(renderer);
}
((JLabel) renderer).setHorizontalAlignment(
rtl ? SwingConstants.RIGHT : SwingConstants.LEFT);
}
} else if (c instanceof Container) {
Container container = (Container) c;
int ncomponents = container.getComponentCount();
for (int i = 0; i < ncomponents; ++i) {
setComponentOrientation(container.getComponent(i));
}
}
}
/**
* set a flow layout for the panel with correct orientation
*
* @param panel
*/
public void setFlowLayoutOrientation(JPanel panel) {
if (getLocalization().isRightToLeftReadingOrder()) {
panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
} else {
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
}
}
// **************************************************************************
// SINGULAR
// **************************************************************************
private class initializeSingularWS_thread implements Runnable {
protected initializeSingularWS_thread() {
}
@Override
public void run() {
// Display info about this particular thread
Log.debug(Thread.currentThread() + " running");
initializeSingularWS();
}
}
public void initializeSingularWSD() {
Thread t = new Thread(new initializeSingularWS_thread(), "compute");
long startTime = System.currentTimeMillis();
t.start();
int i = 0;
while (t.isAlive()) {
Log.debug("Waiting for the initialization: " + i++);
try {
t.join(250);
} catch (InterruptedException e) {
return;
}
if (((System.currentTimeMillis() - startTime) > SingularWSSettings
.getTimeout() * 1000L) && t.isAlive()) {
Log.debug("SingularWS startup timeout");
t.interrupt();
// t.join(); //
// http://docs.oracle.com/javase/tutorial/essential/concurrency/simple.html
return;
}
}
}
// **************************************************************************
// ConstructionProtocol
// **************************************************************************
public void exportAnimatedGIF(EuclidianView ev, FrameCollector gifEncoder,
AnimationExportSlider num, int n, double initVal, double min,
double max, double stepSize) {
double val = initVal;
double step = stepSize;
for (int i = 0; i < n; i++) {
// avoid values like 14.399999999999968
val = Kernel.checkDecimalFraction(val);
num.setValue(val);
num.updateRepaint();
Image img = GBufferedImageD.getAwtBufferedImage(
((EuclidianViewD) ev).getExportImage(1));
if (img == null) {
Log.error("image null");
} else {
gifEncoder.addFrame((BufferedImage) img);
}
val += step;
if (val > max + 0.00000001 || val < min - 0.00000001) {
val -= 2 * step;
step *= -1;
}
}
gifEncoder.finish();
}
@Override
public LocalizationD getLocalization() {
return loc;
}
@Override
public double getMillisecondTime() {
return System.nanoTime() / 1000000d;
}
// ** DON'T PUT IN COMMON OTHERWISE WEB PROJECT DOESN'T GET SPLIT UP **
@Override
public AlgoKimberlingWeightsInterface getAlgoKimberlingWeights() {
if (getKimberlingw() != null) {
return getKimberlingw();
}
return (setKimberlingw(new AlgoKimberlingWeights()));
}
// ** DON'T PUT IN COMMON OTHERWISE WEB PROJECT DOESN'T GET SPLIT UP **
@Override
public double kimberlingWeight(AlgoKimberlingWeightsParams kw) {
return getAlgoKimberlingWeights().weight(kw);
}
// ** DON'T PUT IN COMMON OTHERWISE WEB PROJECT DOESN'T GET SPLIT UP **
@Override
public AlgoCubicSwitchInterface getAlgoCubicSwitch() {
if (getCubicw() != null) {
return getCubicw();
}
return (setCubicw(new AlgoCubicSwitch()));
}
// ** DON'T PUT IN COMMON OTHERWISE WEB PROJECT DOESN'T GET SPLIT UP **
@Override
public String cubicSwitch(AlgoCubicSwitchParams kw) {
return getAlgoCubicSwitch().getEquation(kw);
}
/**
* Initializes the sign in Operation and tries to login in the user with the
* stored token
*/
protected void initSignInEventFlow() {
// Inizialize the login operation
loginOperation = new LoginOperationD();
// Try to login the stored user
loginOperation.performTokenLogin();
}
public void initOpenFromGGTEventFlow() {
if (openFromGGTOperation == null) {
openFromGGTOperation = new OpenFromGGTOperation(this);
}
}
public OpenFromGGTOperation getOpenFromGGTOperation() {
return openFromGGTOperation;
}
@Override
public CommandDispatcher getCommandDispatcher(Kernel kernel2) {
return new CommandDispatcher(kernel2) {
// nothing to override
};
}
/**
* only for 3D so thumbnail can be generated. Overridden in App3D
*/
public void uploadToGeoGebraTubeOnCallback() {
uploadToGeoGebraTube();
}
private SensorLogger udpLogger;
private String perspectiveParam = "";
@Override
public SensorLogger getSensorLogger() {
if (udpLogger == null) {
udpLogger = new UDPLoggerD(getKernel());
}
return udpLogger;
}
public void setPerspectiveParam(String perspective) {
this.perspectiveParam = perspective;
}
@Override
public void set1rstMode() {
setMode(((GuiManagerD) this.getGuiManager()).getToolbarPanel()
.getFirstToolbar().getFirstMode());
}
final public void insertFile(File file) {
// using code from newWindowAction, combined with
// Michael's suggestion
AppD ad = newAppForTemplateOrInsertFile();
// now, we have to load the file into AppD
ad.getGuiManager().loadFile(file, false);
// now we have to copy the macros from ad to app
// in order to make some advanced constructions work
// as it was hard to copy macro classes, let's use
// strings, but how to load them into the application?
try {
getXMLio().processXMLString(ad.getMacroXML(), false, true);
// alternative solution
// app.addMacroXML(ad.getKernel().getMacroXML(
// ad.getKernel().getAllMacros()));
} catch (Exception ex) {
Log.debug("Could not load any macros at \"Insert File\"");
ex.printStackTrace();
}
// afterwards, the file is loaded into "ad" in theory,
// so we have to use the CopyPaste class to copy it
getCopyPaste().copyToXML(ad, new ArrayList<GeoElement>(ad.getKernel()
.getConstruction().getGeoSetWithCasCellsConstructionOrder()),
true);
// and paste
getCopyPaste().pasteFromXML(this, true);
// forgotten something important!
// ad should be closed!
ad.exit();
// this is also needed to make it possible
// to load the same file once again
ad.getFrame().dispose();
}
protected AppD newAppForTemplateOrInsertFile() {
return new AppD(new CommandLineArguments(null), new JPanel(), true);
}
final public void applyTemplate(File file) {
// using code from newWindowAction, combined with
// Michael's suggestion
// true as undo info is necessary for copy-paste!
AppD ad = newAppForTemplateOrInsertFile();
// now, we have to load the file into AppD
ad.getGuiManager().loadFile(file, false);
setLabelingStyle(ad.getLabelingStyle());
getKernel().setConstructionDefaults(ad.getKernel());
getKernel().setVisualStyles(ad.getKernel());
getKernel().updateConstruction();
// almost forgotten something important!
// ad should be closed!
ad.exit();
// this is also needed to make it possible
// to load the same style file once again
ad.getFrame().dispose();
}
private boolean popupsDone = false;
public void showPopUps() {
LoginOperationD signIn = (LoginOperationD) getLoginOperation();
if (!signIn.isTubeCheckDone()) {
return;
}
if (isAllowPopups()) {
// Show login popup
if (!popupsDone) {
popupsDone = true;
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
boolean showDockPopup = true;
LoginOperationD signInOp = (LoginOperationD) getLoginOperation();
if (signInOp.isTubeAvailable()
&& !signInOp.isLoggedIn()) {
showDockPopup = showTubeLogin();
}
if (showDockPopup && isShowDockBar()) {
showPerspectivePopup();
}
}
});
}
}
}
protected boolean showTubeLogin() {
// for debugging only
// force sign-in popup if not logged in
// GeoGebraPreferencesD.getPref().savePreference(
// GeoGebraPreferencesD.USER_LOGIN_SKIP,
// "false");
boolean showDockPopup = true;
String skipLogin = GeoGebraPreferencesD.getPref()
.loadPreference(GeoGebraPreferencesD.USER_LOGIN_SKIP, "false");
if (!"true".equals(skipLogin)) {
showDockPopup = false;
GeoGebraPreferencesD.getPref().savePreference(
GeoGebraPreferencesD.USER_LOGIN_SKIP, "true");
getGuiManager().login();
}
return showDockPopup;
}
protected void showPerspectivePopup() {
getDockBar().showPopup();
}
/**
* resume 3D openGL renderer
*/
public void resume3DRenderer() {
// used in 3D
}
@Override
public void showCustomizeToolbarGUI() {
getDialogManager().showToolbarConfigDialog();
}
@Override
public boolean isSelectionRectangleAllowed() {
return true;
}
public ImageIcon getMenuIcon(ImageResourceD res) {
if (isMacOS()) {
// fixed-size, 16x16 icons for mac menu
return getScaledIcon(res, 16);
}
return getScaledIcon(res, null);
}
public Image getMenuInternalImage(ImageResourceD name) {
if (isMacOS()) {
// no scaling for mac menu
return getInternalImage(name);
}
return getScaledInternalImage(name);
}
public void needThumbnailFor3D() {
// nothing to do here
}
public boolean useHugeGuiForInput3D() {
return false;
}
/**
* huge size for undo/redo/etc. buttons when huge GUI is needed for some 3D
* inputs
*
*/
public static final int HUGE_UNDO_BUTTON_SIZE = 36;
@Override
public void closePopups() {
// TODO Auto-generated method stub
}
@Override
public GTimer newTimer(GTimerListener listener, int delay) {
return new GTimerD(listener, delay);
}
private final ScheduledExecutorService scheduler = Executors
.newScheduledThreadPool(1);
private ScheduledFuture<?> handler;
private PrintPreviewD printPreview;
@Override
public void schedulePreview(Runnable scheduledPreview) {
cancelPreview();
handler = scheduler.schedule(scheduledPreview,
SCHEDULE_PREVIEW_DELAY_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
}
@Override
public void cancelPreview() {
if (handler != null) {
handler.cancel(false);
}
}
private static GuiManagerD getGuiManager(AppD app) {
return (GuiManagerD) app.getGuiManager();
}
public static void initToolbar(AppD app, int toolbarPosition,
boolean showToolBarHelp, JPanel northPanel, JPanel eastPanel,
JPanel southPanel, JPanel westPanel) {
GuiManagerD guiManager = getGuiManager(app);
LocalizationD loc = app.getLocalization();
// initialize toolbar panel even if it's not used (hack)
guiManager.getToolbarPanelContainer();
ToolbarContainer toolBarContainer = (ToolbarContainer) guiManager
.getToolbarPanelContainer();
JComponent helpPanel = toolBarContainer.getToolbarHelpPanel();
toolBarContainer.setOrientation(toolbarPosition);
ToolbarContainer.setShowHelp(showToolBarHelp);
switch (toolbarPosition) {
default:
case SwingConstants.NORTH:
northPanel.add(toolBarContainer, BorderLayout.NORTH);
break;
case SwingConstants.SOUTH:
southPanel.add(toolBarContainer, BorderLayout.NORTH);
break;
case SwingConstants.EAST:
eastPanel.add(toolBarContainer, loc.borderEast());
if (showToolBarHelp && helpPanel != null) {
northPanel.add(helpPanel, BorderLayout.NORTH);
}
break;
case SwingConstants.WEST:
westPanel.add(toolBarContainer, loc.borderWest());
if (showToolBarHelp && helpPanel != null) {
northPanel.add(helpPanel, BorderLayout.NORTH);
}
break;
}
northPanel.revalidate();
southPanel.revalidate();
westPanel.revalidate();
eastPanel.revalidate();
toolBarContainer.buildGui();
if (helpPanel != null) {
helpPanel.revalidate();
}
}
public static void initInputBar(AppD app, boolean showInputTop,
JPanel northPanel, JPanel southPanel) {
GuiManagerD gui = (GuiManagerD) app.getGuiManager();
if (showInputTop) {
northPanel.add(gui.getAlgebraInput(), BorderLayout.SOUTH);
} else {
southPanel.add(gui.getAlgebraInput(), BorderLayout.SOUTH);
}
((AlgebraInputD) gui.getAlgebraInput()).updateOrientation(showInputTop);
}
public static JPanel getMenuBarPanel(AppD appD, JPanel applicationPanel) {
JPanel menuBarPanel = new JPanel(new BorderLayout());
menuBarPanel.add(appD.getGuiManager().getMenuBar(), BorderLayout.NORTH);
menuBarPanel.add(applicationPanel, BorderLayout.CENTER);
return menuBarPanel;
}
public static GuiManagerD newGuiManager(AppD appD) {
return new GuiManagerD(appD);
}
public static void loadFile(AppD app, File currentFile) {
app.getGuiManager().loadFile(currentFile, false);
}
public static void setActiveView(AppD app, int view) {
getGuiManager(app).getLayout().getDockManager().setFocusedPanel(view);
}
public static boolean inExternalWindow(AppD app, Component eventPane) {
return getGuiManager(app).getLayout().inExternalWindow(eventPane);
}
public static Component getRootComponent(AppD app) {
return getGuiManager(app).getLayout().getRootComponent();
}
public static void newLayout(AppD app) {
app.guiManager.setLayout(new LayoutD(app));
}
public static DockBarInterface newDockBar(AppD app) {
return new DockBar(app);
}
@Override
public boolean isDesktop() {
return true;
}
@Override
public CopyPaste getCopyPaste() {
if (copyPaste == null) {
copyPaste = new CopyPaste();
}
return copyPaste;
}
@Override
public void invokeLater(Runnable runnable) {
SwingUtilities.invokeLater(runnable);
}
@Override
public GeoGebraToPstricks newGeoGebraToPstricks() {
return new GeoGebraToPstricksD(this);
}
@Override
public GeoGebraToAsymptote newGeoGebraToAsymptote() {
return new GeoGebraToAsymptoteD(this);
}
@Override
public GeoGebraToPgf newGeoGebraToPgf() {
return new GeoGebraToPgfD(this);
}
public void setPrintPreview(PrintPreviewD printPreviewD) {
printPreview = printPreviewD;
}
public PrintPreviewD getPrintPreview(){
return printPreview;
}
}