package org.geogebra.desktop.plugin;
import java.awt.Toolkit;
/*
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.
*/
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.AccessController;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedAction;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.swing.JOptionPane;
import org.geogebra.common.GeoGebraConstants;
import org.geogebra.common.awt.GBufferedImage;
import org.geogebra.common.euclidian.EuclidianView;
import org.geogebra.common.jre.plugin.GgbAPIJre;
import org.geogebra.common.jre.util.Base64;
import org.geogebra.common.main.App.ExportType;
import org.geogebra.common.main.Localization;
import org.geogebra.common.util.FileExtensions;
import org.geogebra.common.util.StringUtil;
import org.geogebra.common.util.debug.Log;
import org.geogebra.desktop.awt.GBufferedImageD;
import org.geogebra.desktop.euclidianND.EuclidianViewInterfaceD;
import org.geogebra.desktop.export.GraphicExportDialog;
import org.geogebra.desktop.gui.util.ImageSelection;
import org.geogebra.desktop.io.MyImageIO;
import org.geogebra.desktop.main.AppD;
/**
* <h3>GgbAPI - API for PlugLets</h3>
*
* <pre>
* The Api the plugin program can use.
* </pre>
* <ul>
* <h4>Interface:</h4>
* <li>GgbAPI(Application) //Application owns it
* <li>getApplication()
* <li>getKernel()
* <li>getConstruction()
* <li>getAlgebraProcessor()
* <li>getPluginManager()
* <li>evalCommand(String)
* <li>and the rest of the methods from the Applet JavaScript/Java interface
* <li>...
* </ul>
*
* @author H-P Ulven
* @version 31.10.08 29.05.08: Tranferred applet interface methods (the relevant
* ones) from GeoGebraAppletBase
*/
public class GgbAPID extends GgbAPIJre {
/**
* Constructor: Makes the api with a reference to the GeoGebra program.
* Called from GeoGebra.
*
* @param app
* Application
*/
public GgbAPID(AppD app) {
super(app);
kernel = app.getKernel();
algebraprocessor = kernel.getAlgebraProcessor();
construction = kernel.getConstruction();
// pluginmanager=app.getPluginManager();
}
// /* JAVA SCRIPT INTERFACE */
/**
* Returns current construction as a ggb file in form of a byte array.
*
* @return null if something went wrong
*/
@Override
public synchronized byte[] getGGBfile() {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
((AppD) app).getXMLio().writeGeoGebraFile(bos, true);
bos.flush();
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* Turns showing of error dialogs on (true) or (off). Note: this is
* especially useful together with evalCommand().
*/
@Override
public synchronized void setErrorDialogsActive(boolean flag) {
((AppD) app).setErrorDialogsActive(flag);
}
/**
* Clears the construction and resets all views.
*/
public synchronized void fileNew() {
((AppD) app).fileNew();
}
/**
* Refreshs all views. Note: clears traces in geometry window.
*/
@Override
public synchronized void refreshViews() {
app.refreshViews();
}
/**
* Loads a construction from a file (given URL). Note that this method does
* NOT refresh the user interface.
*/
@Override
public synchronized void openFile(String strURL) {
try {
String lowerCase = StringUtil.toLowerCase(strURL);
URL url = new URL(strURL);
((AppD) app).loadXML(url, lowerCase
.endsWith(FileExtensions.GEOGEBRA_TOOL.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
private static volatile MessageDigest messageDigestMD5 = null;
/**
* @return reference to MD5 algorithm
* @throws NoSuchAlgorithmException
* if algorithm is not supported
*/
public static MessageDigest getMessageDigestMD5()
throws NoSuchAlgorithmException {
if (messageDigestMD5 == null) {
messageDigestMD5 = MessageDigest.getInstance("MD5");
}
return messageDigestMD5;
}
/*
* saves a PNG file signed applets only
*/
@Override
public synchronized boolean writePNGtoFile(String filename,
final double exportScale, final boolean transparent,
final double DPI) {
File file1 = null;
try {
file1 = new File(filename);
} catch (Throwable t) {
t.printStackTrace();
}
if (file1 == null) {
return false;
}
final File file = file1;
return (Boolean) AccessController
.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Boolean run() {
try {
// draw graphics view into image
GBufferedImage img = ((AppD) getApplication())
.getEuclidianView1()
.getExportImage(exportScale, transparent,
ExportType.PNG);
// write image to file
MyImageIO.write(
GBufferedImageD.getAwtBufferedImage(img),
"png", (float) DPI, file);
return true;
} catch (Exception ex) {
Log.debug(ex.toString());
return false;
} catch (Error ex) {
Log.debug(ex.toString());
return false;
}
}
});
}
@Override
protected void exportPNGClipboard(boolean transparent, int DPI,
double exportScale, EuclidianView ev) {
// more control but doesn't paste into eg Paint, Google Docs
GraphicExportDialog.exportPNGClipboard(transparent, DPI, exportScale,
(AppD) app, (EuclidianViewInterfaceD) ev);
}
@Override
protected void exportPNGClipboardDPIisNaN(boolean transparent,
double exportScale, EuclidianView ev) {
// pastes into more programs
GBufferedImage img = ev.getExportImage(exportScale, transparent,
ExportType.PNG);
ImageSelection imgSel = new ImageSelection(
GBufferedImageD.getAwtBufferedImage(img));
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(imgSel,
null);
}
@Override
protected String base64encodePNG(boolean transparent, double DPI,
double exportScale, EuclidianView ev) {
GBufferedImage img = ((EuclidianViewInterfaceD) ev)
.getExportImage(exportScale, transparent, ExportType.PNG);
return base64encode(GBufferedImageD.getAwtBufferedImage(img), DPI);
}
/**
* @param img
* image
* @return encoded image
*/
public static String base64encode(BufferedImage img, double DPI) {
if (img == null) {
return null;
}
try {
Iterator<ImageWriter> it = ImageIO
.getImageWritersByFormatName("png");
ImageWriter writer = it.next();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
writer.setOutput(ios);
MyImageIO.writeImage(writer, img, DPI);
String ret = Base64.encodeToString(baos.toByteArray(), false);
baos.close();
ios.close();
return ret;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* JavaScript-like prompt
*
* @param value0
* prompt text
* @param value1
* default value
* @return user's response
*/
public String prompt(Object value0, Object value1) {
return (String) JOptionPane.showInputDialog(((AppD) app).getFrame(),
value0, GeoGebraConstants.APPLICATION_NAME,
JOptionPane.PLAIN_MESSAGE, null, null, value1);
}
/**
* pops up message dialog with "OK" and "Stop Script"
*
* @param message
* to display
*/
public void alert(String message) {
Localization loc = app.getLocalization();
Object[] options = { loc.getMenu("StopScript"), loc.getMenu("OK") };
int n = JOptionPane.showOptionDialog(((AppD) app).getFrame(), message,
GeoGebraConstants.APPLICATION_NAME, 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 == 0) {
throw new Error("Script stopped by user");
}
}
/**
* Returns the dimensions of the real world coordinate system in the
* graphics view as [xmin, ymin, width, height]
*
* @return dimensions of the real world coordinate system
*/
public synchronized Rectangle2D.Double getCoordSystemRectangle() {
EuclidianView ev = app.getEuclidianView1();
return new Rectangle2D.Double(ev.getXmin(), ev.getYmin(),
ev.getXmax() - ev.getXmin(), ev.getYmax() - ev.getYmin());
}
}// class GgbAPI