/*
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.gui.app;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.dnd.DropTarget;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import org.geogebra.common.GeoGebraConstants;
import org.geogebra.common.euclidian.EuclidianView;
import org.geogebra.common.factories.UtilFactory;
import org.geogebra.common.jre.util.DownloadManager;
import org.geogebra.common.kernel.Kernel;
import org.geogebra.common.kernel.Macro;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoNumeric;
import org.geogebra.common.kernel.geos.GeoPoint;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Localization;
import org.geogebra.common.util.StringUtil;
import org.geogebra.common.util.debug.Log;
import org.geogebra.common.util.lang.Unicode;
import org.geogebra.desktop.AppId;
import org.geogebra.desktop.CommandLineArguments;
import org.geogebra.desktop.euclidianND.EuclidianViewInterfaceD;
import org.geogebra.desktop.export.GraphicExportDialog;
import org.geogebra.desktop.geogebra3D.euclidian3D.EuclidianView3DD;
import org.geogebra.desktop.gui.FileDropTargetListener;
import org.geogebra.desktop.gui.GuiManagerD;
import org.geogebra.desktop.gui.dialog.DialogManagerD;
import org.geogebra.desktop.gui.util.AnimatedGifEncoder;
import org.geogebra.desktop.main.AppD;
import org.geogebra.desktop.main.GeoGebraPreferencesD;
import org.geogebra.desktop.util.FrameCollector;
import org.geogebra.desktop.util.HttpRequestD;
import org.geogebra.desktop.util.UtilD;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* GeoGebra's main window.
*/
public class GeoGebraFrame extends JFrame
implements WindowFocusListener, Printable, ComponentListener {
private static final long serialVersionUID = 1L;
private static final int VERSION_CHECK_DAYS = 1;
// This works only for subversion numbers <= 999 (change 1000 to 10000 for
// 9999):
private static final int VERSION_TO_LONG_MULTIPLIER = 1000;
private static ArrayList<GeoGebraFrame> instances = new ArrayList<GeoGebraFrame>();
private static GeoGebraFrame activeInstance;
private static Object lock = new Object();
private static FileDropTargetListener dropTargetListener;
private static List<NewInstanceListener> instanceListener = new ArrayList<NewInstanceListener>();
protected AppD app;
private Timer timer;
private long born;
public GeoGebraFrame() {
instances.add(this);
setActiveInstance(this);
born = System.currentTimeMillis();
this.addComponentListener(this);
}
// public static void printInstances() {
// System.out.println("FRAMES: " + instances.size());
// for (int i=0; i < instances.size(); i++) {
// GeoGebraFrame frame = (GeoGebraFrame) instances.get(i);
// System.out.println(" " + (i+1) + ", applet: " + frame.app.isApplet() +
// ", "
// + frame);
// }
// }
/**
* Disposes this frame and removes it from the static instance list.
*/
@Override
public void dispose() {
instances.remove(this);
if (this == activeInstance) {
setActiveInstance(null);
}
}
public AppD getApplication() {
return app;
}
public void setApplication(AppD app) {
this.app = app;
}
public int getInstanceNumber() {
for (int i = 0; i < instances.size(); i++) {
if (this == instances.get(i)) {
return i;
}
}
return -1;
}
@Override
public void windowGainedFocus(WindowEvent arg0) {
setActiveInstance(this);
app.updateMenuWindow();
}
@Override
public void windowLostFocus(WindowEvent arg0) {
// fix for Mac OS bug: close open popups manually
Window[] w = this.getOwnedWindows();
for (Window win : w) {
if (win.getClass().getName()
.equals("javax.swing.Popup$HeavyWeightWindow")) {
win.setVisible(false);
}
}
}
@Override
public Locale getLocale() {
Locale defLocale = GeoGebraPreferencesD.getPref().getDefaultLocale();
if (defLocale == null) {
return super.getLocale();
}
return defLocale;
}
@Override
public void setVisible(boolean flag) {
if (flag) {
updateSize();
// set location
int instanceID = instances.size() - 1;
if (instanceID > 0) {
// move right and down of last instance
GeoGebraFrame prevInstance = getInstance(instanceID - 1);
Point loc = prevInstance.getLocation();
// make sure we stay on screen
Dimension d1 = getSize();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
loc.x = Math.min(loc.x + 20, dim.width - d1.width);
loc.y = Math.min(loc.y + 20, dim.height - d1.height - 25);
setLocation(loc);
} else {
// center
setLocationRelativeTo(null);
}
super.setVisible(true);
app.getActiveEuclidianView().requestFocusInWindow();
} else {
if (!isShowing()) {
return;
}
instances.remove(this);
GeoGebraPreferencesD.getPref().saveFileList();
if (instances.size() == 0) {
super.setVisible(false);
dispose();
if (!app.isApplet()) {
AppD.exit(0);
}
} else {
super.setVisible(false);
updateAllTitles();
}
}
}
/**
* Provide temporary information about window size (for applet designers)
*/
@Override
public void componentResized(ComponentEvent e) {
if (System.currentTimeMillis() < born + 5000) {
return;
}
this.setTitle((int) getSize().getWidth() + "" + Unicode.MULTIPLY + ""
+ (int) getSize().getHeight());
if (timer == null) {
timer = new Timer(3000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e1) {
String title = getPreferredTitle();
setTitle(title);
}
});
}
timer.setRepeats(false);
timer.restart();
}
String getPreferredTitle() {
// TODO Auto-generated method stub
return app.getCurrentFile() == null ? "GeoGebra"
: app.getCurrentFile().getName();
}
public void updateSize() {
// get frame size from layout manager
Dimension size = app.getPreferredSize();
// check if frame fits on screen
Rectangle screenSize = AppD.getScreenSize();
if (size.width > screenSize.width || size.height > screenSize.height) {
size.width = screenSize.width;
size.height = screenSize.height;
setLocation(0, 0);
}
setSize(size);
}
/**
* Main method to create initial GeoGebra window.
*
* @param args
* file name parameter
*/
public static synchronized void main(CommandLineArguments args) {
init(args, new GeoGebraFrame());
}
public static synchronized void init(CommandLineArguments args,
GeoGebraFrame wnd) {
// Fixing #3772. TODO: This could be moved to somewhat later (to have
// proper logging), but *before* any GUI operations.
if (AppD.WINDOWS_VISTA_OR_LATER) {
try {
AppId.setCurrentProcessExplicitAppUserModelID("geogebra.AppId");
System.out.println("AppID = "
+ AppId.getCurrentProcessExplicitAppUserModelID());
} catch (Throwable t) {
System.err.println("problem setting AppId: " + t.getMessage());
}
}
// check java version
double javaVersion = UtilD.getJavaVersion();
if (javaVersion < 1.5) {
JOptionPane.showMessageDialog(null,
"Sorry, GeoGebra cannot be used with your Java version "
+ javaVersion
+ "\nPlease visit http://www.java.com to get a newer version of Java.");
return;
}
if (AppD.MAC_OS) {
initMacSpecifics();
}
// set look and feel
if (args.containsArg("laf")) {
AppD.setLAF(args.getStringValue("laf").equals("system"));
} else {
// system LAF for Windows and Mac; cross-platform for LINUX, others
AppD.setLAF(AppD.MAC_OS || AppD.WINDOWS);
}
if (args.containsArg("resetSettings")) {
GeoGebraPreferencesD.getPref().clearPreferences(wnd.app);
}
// Set GeoGebraPreferences mode (system properties or property file)
// before it is called for the first time
String settingsFile = args.getStringValue("settingsfile");
if (settingsFile.length() > 0) {
GeoGebraPreferencesD.setPropertyFileName(settingsFile);
}
// load list of previously used files
GeoGebraPreferencesD.getPref().loadFileList();
// create first window and show it
createNewWindow(args, wnd);
}
/**
* Returns the active GeoGebra window.
*
* @return the active GeoGebra window.
*/
public static synchronized GeoGebraFrame getActiveInstance() {
return activeInstance;
}
private static void setActiveInstance(GeoGebraFrame frame) {
synchronized (lock) {
activeInstance = frame;
}
}
/**
* adds a NewInstanceListener, fired whenever a new Instance of
* GeoGebraFrame is created.
*
* @param l
*/
public static void addNewInstanceListener(NewInstanceListener l) {
instanceListener.add(l);
}
/**
* MacOS X specific initialization. Note: this method can only be run on a
* Mac!
*/
public static void initMacSpecifics() {
try {
// init mac application listener
MacApplicationListener.initMacApplicationListener();
// mac menu bar
// System.setProperty("com.apple.macos.useScreenMenuBar", "true");
System.setProperty("apple.laf.useScreenMenuBar", "true");
} catch (Exception e) {
Log.debug(e + "");
}
}
public static synchronized GeoGebraFrame createNewWindow(
CommandLineArguments args) {
return createNewWindow(args, new GeoGebraFrame());
}
/**
* Creates new GeoGebra window
*
* @param args
* Command line arguments
* @param wnd
* @return the new window
*/
// public abstract GeoGebra buildGeoGebra();
/**
* return the application running geogebra
*
* @param args
* @param frame
* @return the application running geogebra
*/
protected AppD createApplication(CommandLineArguments args, JFrame frame) {
return new AppD(args, frame, true);
}
public synchronized GeoGebraFrame createNewWindow(CommandLineArguments args,
Macro macro) {
return createNewWindow(args, copy());
}
protected GeoGebraFrame copy() {
return new GeoGebraFrame();
}
/**
* Creates new GeoGebra window
*
* @param args
* Command line arguments
* @param macro
* Macro to open (or null for file edit mode)
* @param wnd
* @return the new window
*/
public static synchronized GeoGebraFrame createNewWindow(
final CommandLineArguments args, GeoGebraFrame wnd) {
// set Application's size, position and font size
final AppD app = wnd.createApplication(args, wnd);
// app.openPopUps(true);
// app.getApplicationGUImanager().setMenubar(new
// geogebra.gui.menubar.GeoGebraMenuBar(app));
app.getGuiManager().initMenubar();
// init GUI
wnd.app = app;
wnd.getContentPane().add(app.buildApplicationPanel());
dropTargetListener = new FileDropTargetListener(app);
wnd.setGlassPane(((GuiManagerD) app.getGuiManager()).getLayout()
.getDockManager().getGlassPane());
wnd.setDropTarget(new DropTarget(wnd, dropTargetListener));
wnd.addWindowFocusListener(wnd);
updateAllTitles();
// handle application args visible
if (args != null) {
if (args.containsArg("showAlgebraWindow")) {
boolean showAlgebraWindow = args
.getBooleanValue("showAlgebraWindow", true);
app.getGuiManager().setShowView(showAlgebraWindow,
App.VIEW_ALGEBRA);
}
if (args.containsArg("showSpreadsheet")) {
boolean showSpreadsheet = args
.getBooleanValue("showSpreadsheet", true);
app.getGuiManager().setShowView(showSpreadsheet,
App.VIEW_SPREADSHEET);
}
if (args.containsArg("showCAS") && app.supportsView(App.VIEW_CAS)) {
boolean showCAS = args.getBooleanValue("showCAS", true);
app.getGuiManager().setShowView(showCAS, App.VIEW_CAS);
}
}
app.updateMenubar();
wnd.setVisible(true);
// init some things in the background
if (!app.isApplet()) {
/*
* Thread runner = new Thread() { public void run() { // init
* properties dialog
* ((GuiManagerD)app.getGuiManager()).initPropertiesDialog();
*
* // init file chooser
* ((GuiManagerD)app.getGuiManager()).initFileChooser();
*
* // init CAS app.getKernel().getGeoGebraCAS();
*
* // init JLaTeXMath Graphics2D g2d =
* app.getEuclidianView().g2Dtemp; Drawable.drawEquation(app,
* app.getEuclidianView().g2Dtemp, 0, 0, "x^{2}", g2d.getFont(),
* false, Color.BLACK, Color.WHITE); } };
*/
Thread runner = GeoGebraFrame.createAppThread(app);
runner.start();
}
checkCommandLineExport(app);
// open the sign-in and/or sidebar popup once the GUI has initialized
if (args != null && args.getNoOfFiles() == args.getNoOfTools()) {
app.setAllowPopups(true);
app.showPopUps();
}
for (NewInstanceListener l : instanceListener) {
l.newInstance(wnd);
}
return wnd;
}
private static AppThread createAppThread(AppD app) {
return new AppThread(app);
}
private static class AppThread extends Thread {
AppD app;
public AppThread(AppD app) {
this.app = app;
}
@Override
public void run() {
// init file chooser
((DialogManagerD) this.app.getDialogManager())
.initFileChooser();
// init singularWS
// No, we cannot do it here at the moment since it will break file
// loading containing Singular,
// so we do it AppD.java --- see [22746] which is reverted at the
// moment.
// app.initializeSingularWSD();
// init JLaTeXMath
// Graphics2D g2d =
// this.app.getEuclidianView1().getTempGraphics2D();
// app.getDrawEquation().drawEquation(this.app, null,
// new GGraphics2DD(g2d), 0, 0, "x^{2}",
// new GFontD(g2d.getFont()), false,
// GColor.BLACK, GColor.WHITE, false, false, null);
// check if newer version is available
// must be done last as internet may not be available
if (!app.isApplet()) {
checkVersion();
}
}
/**
* Downloads newest GeoGebra .jar files and puts them into the user's
* AppData directory. Also downloads license.txt.
*
* @throws IOException
*/
@SuppressFBWarnings({ "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE",
"don't need to check return value of mkdirs() or delete()" })
private static void downloadGeoGebraJars() throws IOException {
ZipInputStream zis = null;
try {
// Creating working directory:
String updateDir = System.getenv("APPDATA")
+ GeoGebraConstants.GEOGEBRA_JARS_UPDATE_DIR;
Log.debug("Creating " + updateDir);
new File(updateDir).mkdirs();
// Downloading newest .jar files in a .zip:
String filename = updateDir + File.separator
+ "geogebra-jars.zip";
File dest = new File(filename);
URL url = new URL(GeoGebraConstants.GEOGEBRA_ONLINE_JARS_ZIP);
Log.debug("Downloading "
+ GeoGebraConstants.GEOGEBRA_ONLINE_JARS_ZIP);
DownloadManager.copyURLToFile(url, dest);
// Unzipping:
// Borrowed from
// http://www.concretepage.com/java/read_zip_file_java.php:
InputStream is = new FileInputStream(filename);
zis = new ZipInputStream(is);
ZipEntry ze;
byte[] buff = new byte[1024];
while ((ze = zis.getNextEntry()) != null) {
// get file name
String name = ze.getName();
FileOutputStream fos = new FileOutputStream(
updateDir + File.separator + name);
Log.debug("Extracting " + name);
try {
int l = 0;
// write buffer to file
while ((l = zis.read(buff)) > 0) {
fos.write(buff, 0, l);
}
} finally {
fos.close();
}
}
dest.delete();
} catch (Exception e) {
Log.error("Unsuccessful update");
} finally {
if (zis != null) {
zis.close();
}
}
}
/**
* Checks if a newer version is available. It runs (at most) every day
* for major updates, but every run for minor updates.
*/
private void checkVersion() {
Log.debug("Checking version");
if (!app.getVersionCheckAllowed()) {
Log.debug("Version check is not allowed");
return;
}
String lastVersionCheck = GeoGebraPreferencesD.getPref()
.loadPreference(GeoGebraPreferencesD.VERSION_LAST_CHECK,
"");
Long nowL = new Date().getTime();
String nowLS = nowL.toString();
boolean checkNeeded = false;
if (lastVersionCheck == null || "".equals(lastVersionCheck)) {
checkNeeded = true;
Log.debug("major version check needed: no check was done yet");
}
else {
Long lastVersionCheckL = Long.valueOf(lastVersionCheck);
if (lastVersionCheckL
+ 1000L * 60 * 60 * 24 * VERSION_CHECK_DAYS < nowL) {
checkNeeded = true;
Log.debug("major version check needed: lastVersionCheckL="
+ lastVersionCheckL + " nowL=" + nowL);
} else {
Log.debug("no major version check needed: lastVersionCheck="
+ lastVersionCheckL + " nowL=" + nowL);
}
}
String myVersion = GeoGebraConstants.VERSION_STRING;
HttpRequestD httpr = (HttpRequestD) UtilFactory.getPrototype()
.newHttpRequest();
String newestVersion = null;
StringBuilder sb = new StringBuilder();
Long newestVersionL;
Long currentVersionL = versionToLong(myVersion);
try {
if (checkNeeded) {
sb.append(GeoGebraConstants.VERSION_URL);
sb.append("?ver=");
sb.append(myVersion);
sb.append("&os=");
if (AppD.WINDOWS) {
sb.append("win");
} else if (AppD.MAC_OS) {
sb.append("mac");
} else {
sb.append("linux");
}
sb.append("&java=");
AppD.appendJavaVersion(sb);
newestVersion = httpr
.sendRequestGetResponseSync(sb.toString());
if (newestVersion == null) {
// probably not online
Log.error("Problem fetching " + sb);
return;
}
newestVersion = newestVersion.replaceAll("-", ".");
newestVersionL = versionToLong(newestVersion);
Log.debug("current=" + currentVersionL + " newest="
+ newestVersionL);
if (currentVersionL < newestVersionL) {
Localization loc = app.getLocalization();
String q = loc.getMenu("NewerVersionA").replaceAll("%0",
newestVersion);
String dl = loc.getMenu("GoToDownloadPage");
Object[] options = { loc.getMenu("Cancel"), dl };
Component comp = app.getMainComponent();
int returnVal = JOptionPane.showOptionDialog(comp, q,
dl, JOptionPane.DEFAULT_OPTION,
JOptionPane.WARNING_MESSAGE, null, options,
options[0]);
// store date of current check only when notification
// has been shown:
GeoGebraPreferencesD.getPref().savePreference(
GeoGebraPreferencesD.VERSION_LAST_CHECK, nowLS);
if (returnVal == 1) {
app.getGuiManager().showURLinBrowser(
GeoGebraConstants.INSTALLERS_URL);
}
}
} // checkneeded
sb = new StringBuilder();
sb.append(GeoGebraConstants.VERSION_URL_MINOR);
sb.append("?ver=");
sb.append(myVersion);
sb.append("&os=");
if (AppD.WINDOWS) {
sb.append("win");
} else if (AppD.MAC_OS) {
sb.append("mac");
} else {
sb.append("linux");
}
sb.append("&java=");
AppD.appendJavaVersion(sb);
newestVersion = httpr.sendRequestGetResponseSync(sb.toString());
if (newestVersion == null) {
Log.error("problem fetching " + sb);
return;
}
newestVersion = newestVersion.replaceAll("-", ".");
newestVersionL = versionToLong(newestVersion);
Log.debug("newest_minor=" + newestVersionL);
// Windows only: automatic update
if (AppD.WINDOWS && currentVersionL < newestVersionL) {
downloadGeoGebraJars();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
/**
* Converts a version string to a long value (e.g. 4.1.2.3 to 4001002003)
*
* @param version
* string
* @return long value
*/
static Long versionToLong(String version) {
String[] subversions = version.split("\\.");
Long n = 0L;
int l = subversions.length;
for (int i = 0; i < l; ++i) {
String c = subversions[i];
n = n * VERSION_TO_LONG_MULTIPLIER + Integer.parseInt(c);
}
return n;
}
public static int getInstanceCount() {
return instances.size();
}
public static ArrayList<GeoGebraFrame> getInstances() {
return instances;
}
static GeoGebraFrame getInstance(int i) {
return instances.get(i);
}
public static void updateAllTitles() {
for (int i = 0; i < instances.size(); i++) {
AppD app = instances.get(i).app;
app.updateTitle();
}
}
/**
* Checks all opened GeoGebra instances if their current file is the given
* file.
*
* @param file
* @return GeoGebra instance with file open or null
*/
public static GeoGebraFrame getInstanceWithFile(File file) {
if (file == null) {
return null;
}
try {
String absPath = file.getCanonicalPath();
for (int i = 0; i < instances.size(); i++) {
GeoGebraFrame inst = instances.get(i);
AppD app = inst.app;
File currFile = app.getCurrentFile();
if (currFile != null) {
if (absPath.equals(currFile.getCanonicalPath())) {
return inst;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public boolean isIconified() {
return getExtendedState() == Frame.ICONIFIED;
}
/**
* Returns the dropTarget listener for this frame.
*
* @return the dropTarget listener for this frame.
*/
public FileDropTargetListener getDropTargetListener() {
return dropTargetListener;
}
@Override
public int print(Graphics g, PageFormat pf, int pageIndex)
throws PrinterException {
if (pageIndex > 0) {
return NO_SUCH_PAGE;
}
Graphics2D g2d = (Graphics2D) g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
double xScale = pf.getImageableWidth() / this.getWidth();
double yScale = pf.getImageableHeight() / this.getHeight();
double scale = Math.min(xScale, yScale);
g2d.scale(scale, scale);
this.printAll(g);
return PAGE_EXISTS;
}
public static void checkCommandLineExport(final AppD app) {
final CommandLineArguments args = app.getCommandLineArgs();
if (args != null && args.containsArg("exportAnimation")
&& args.containsArg("slider")) {
String dpiStr = args.getStringValue("dpi");
final int dpi = Integer
.parseInt("".equals(dpiStr) ? "300" : dpiStr);
final EuclidianView ev = app.getActiveEuclidianView();
final String filename0 = args.getStringValue("exportAnimation");
final String extension = StringUtil.getFileExtensionStr(filename0);
final String filename = StringUtil.removeFileExtension(filename0);
GeoPoint export1 = (GeoPoint) app.getKernel()
.lookupLabel(EuclidianView.EXPORT1);
GeoPoint export2 = (GeoPoint) app.getKernel()
.lookupLabel(EuclidianView.EXPORT2);
if ("gif".equals(extension) && export1 != null && export2 != null) {
// maximize window
// avoids clipping unless export size is especially large
// needed for Animated GIF export from GeoGebraWeb
// which runs this server-side
Frame frame = app.getFrame();
frame.setExtendedState(
frame.getExtendedState() | Frame.MAXIMIZED_BOTH);
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
String sliderName = args.getStringValue("slider");
GeoElement slider = app.getKernel().lookupLabel(sliderName);
if (slider == null || !slider.isGeoNumeric()
|| !((GeoNumeric) slider).isSlider()) {
Log.error(sliderName + " is not a slider");
AppD.exit(0);
}
app.getKernel().getAnimatonManager().stopAnimation();
GeoNumeric num = (GeoNumeric) slider;
int type = num.getAnimationType();
double min = num.getIntervalMin();
double max = num.getIntervalMax();
double val;
double step;
int n;
switch (type) {
case GeoElement.ANIMATION_DECREASING:
step = -num.getAnimationStep();
n = (int) ((max - min) / -step);
if (Kernel.isZero(((max - min) / -step) - n)) {
n++;
}
if (n == 0) {
n = 1;
}
val = max;
break;
case GeoElement.ANIMATION_OSCILLATING:
step = num.getAnimationStep();
n = (int) ((max - min) / step) * 2;
if (Kernel.isZero(((max - min) / step * 2) - n)) {
n++;
}
if (n == 0) {
n = 1;
}
val = min;
break;
default: // GeoElement.ANIMATION_INCREASING:
// GeoElement.ANIMATION_INCREASING_ONCE:
step = num.getAnimationStep();
n = (int) ((max - min) / step);
if (Kernel.isZero(((max - min) / step) - n)) {
n++;
}
if (n == 0) {
n = 1;
}
val = min;
}
if ("gif".equals(extension)) {
// "true" (default) or "false"
String loop = args.getStringValue("loop");
// time between frames in ms
String delayStr = args.getStringValue("delay");
final int delay = Integer.parseInt(
"".equals(delayStr) ? "10" : delayStr);
final AnimatedGifEncoder gifEncoder = new AnimatedGifEncoder();
gifEncoder.setQuality(1);
gifEncoder.start(new File(filename + ".gif"));
gifEncoder.setDelay(delay); // miliseconds
if (!"false".equals(loop)) {
// repeat forever
gifEncoder.setRepeat(0);
}
FrameCollector collector = new FrameCollector() {
@Override
public void addFrame(BufferedImage img) {
gifEncoder.addFrame(img);
}
@Override
public void finish() {
gifEncoder.finish();
}
};
app.exportAnimatedGIF(ev, collector, num, n, val, min,
max, step);
Log.debug("animated GIF exported successfully");
AppD.exit(0);
}
double printingScale = ev.getPrintingScale();
double exportScale = (printingScale * dpi) / 2.54
/ ev.getXscale();
boolean textAsShapes = true;
boolean transparent = true;
boolean useEMFplus = true;
int pixelWidth = (int) Math
.floor(ev.getExportWidth() * exportScale);
int pixelHeight = (int) Math
.floor(ev.getExportHeight() * exportScale);
for (int i = 0; i < n; i++) {
Log.debug("exporting frame " + i + "of " + n);
// avoid values like 14.399999999999968
val = Kernel.checkDecimalFraction(val);
num.setValue(val);
num.updateRepaint();
File file = new File(filename + i + "." + extension);
GraphicExportDialog.export(extension,
(EuclidianViewInterfaceD) ev, file, transparent,
dpi, exportScale, textAsShapes, useEMFplus,
pixelWidth, pixelHeight, app);
val += step;
if (val > max + 0.00000001 || val < min - 0.00000001) {
val -= 2 * step;
step *= -1;
}
}
AppD.exit(0);
}
});
}
if (args != null && args.containsArg("export")) {
final String filename = args.getStringValue("export");
final String extension = StringUtil.getFileExtensionStr(filename);
String dpiStr = args.getStringValue("dpi");
final int dpi = Integer
.parseInt("".equals(dpiStr) ? "300" : dpiStr);
Log.debug("attempting to export: " + filename + " at " + dpiStr
+ "dpi");
// wait for EuclidianView etc to initialize before export
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
EuclidianViewInterfaceD ev = (EuclidianViewInterfaceD) app
.getActiveEuclidianView();
try {
boolean export3D = false;
// if 3D view exists, assume that we should export
// that
// (only PNG supported right now for 3D)
if (app.isEuclidianView3Dinited()
&& app.hasEuclidianView3D()) {
if ("png".equals(extension)) {
Log.debug("exporting 3D View");
ev = (EuclidianView3DD) app
.getEuclidianView3D();
export3D = true;
}
}
double printingScale = ev.getPrintingScale();
double exportScale = (printingScale * dpi) / 2.54
/ ev.getXscale();
final boolean transparent = true;
final boolean textAsShapes = true;
final boolean useEMFplus = true;
int pixelWidth = (int) Math
.floor(ev.getExportWidth() * exportScale);
int pixelHeight = (int) Math
.floor(ev.getExportHeight() * exportScale);
int dpi2 = dpi;
String maxSizeStr = args.getStringValue("maxSize");
if (maxSizeStr != null && !"".equals(maxSizeStr)) {
// ************************
double maxSize = Integer.parseInt(maxSizeStr);
Log.debug("desiredSize = " + maxSize);
double size = Math.max(ev.getExportWidth(),
ev.getExportHeight());
Log.debug("size = " + size);
exportScale = Math.min(
maxSize / Math.floor(ev.getExportWidth()),
maxSize / Math.floor(ev.getExportHeight()));
Log.debug("exportScale = " + exportScale);
pixelWidth = (int) Math
.floor(ev.getExportWidth() * exportScale);
Log.debug("pixelWidth = " + pixelWidth);
pixelHeight = (int) Math
.floor(ev.getExportHeight() * exportScale);
Log.debug("pixelHeight = " + pixelHeight);
dpi2 = (int) (exportScale * ev.getXscale() * 2.54
/ printingScale);
Log.debug("dpi2 = " + dpi2);
}
final File file = new File(filename);
GraphicExportDialog.export(extension, ev, file,
transparent, dpi2, exportScale, textAsShapes,
useEMFplus, pixelWidth, pixelHeight, app);
// HACK
// do it again for 3D, first call initializes JOGL
if (export3D) {
GraphicExportDialog.export(extension, ev, file,
transparent, dpi2, exportScale,
textAsShapes, useEMFplus, pixelWidth,
pixelHeight, app);
}
Log.debug("Graphics View exported successfully to "
+ file.getAbsolutePath());
} catch (Throwable t) {
t.printStackTrace();
}
AppD.exit(0);
}
});
}
}
@Override
public void componentMoved(ComponentEvent e) {
// TODO Auto-generated method stub
}
@Override
public void componentShown(ComponentEvent e) {
// TODO Auto-generated method stub
}
@Override
public void componentHidden(ComponentEvent e) {
// TODO Auto-generated method stub
}
}