/*
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.
*/
package org.geogebra.desktop.main;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Locale;
import java.util.Properties;
import org.geogebra.common.jre.util.Base64;
import org.geogebra.common.util.debug.Log;
/**
* Class GeoGebraPortablePreferences
*
* Stores user settings and options as a property file. For use in portable
* GeoGebra on usb and Cd/DVD.
*
* This class is returned by GeoGebraPreferences.getPrefs() instead of
* GeoGebraPreferences itself, if the file preferences.properties exists in the
* geogebra.jar-folder. This opens up for three modes: - Normal - Portable
* GeoGebra - Read-only network share or CD/DVD, where we want same setting for
* all
*
* geogebra.properties must have one line: is_read_only=true (or false)
*
* A cleaner implementation would be to rewrite GeoGebraPreferences to an
* abstract class, as an interface for GeoGebraSystemPreferences and
* GeoGebraPropertyFile, but as there probably never will be a demand for a
* third class later, I chose a solution which makes it unneccessary to change
* too many calling classes, by just making this one and do a small rewrite of
* getPrefs() and add a setPropertyFile() in GeoGebraPreferences which then
* behaves like a kind of "singleton factory".
*
* This class implements all the commands of GeoGebraPreferences, but stores in
* propertyfile given on the commandline: --settingsFile=<path>\
* <filename> (prefs.properties)
*
* Options/ToDo: Might as well store: xml in user.xml ggt in macro.bin to avoid
* escaping "=", b64 encode/decoding and save some time... Also useful to have
* the xml in a separate file for editing? On the other hand, this is done
* automatically in Properties, so not really a problem.
*
* @author Hans-Petter Ulven
* @version 2010-03-07
*/
public class GeoGebraPortablePreferences extends GeoGebraPreferencesD {
/*
* don't need, erase, have made protected in parentclass:
*
* private String XML_GGB_FACTORY_DEFAULT; // see loadPreferences()
*
* // special preference keys (copied from GeoGebraPreferences private final
* String XML_USER_PREFERENCES = "xml_user_preferences"; private final
* String TOOLS_FILE_GGT = "tools_file_ggt"; private final String APP_LOCALE
* = "app_locale"; private final String APP_CURRENT_IMAGE_PATH =
* "app_current_image_path"; private final String APP_FILE_ = "app_file_";
*/
// / --- --- ///
private final static String ERROR = "Error?"; // For debugging
private final static String COMMENT = "GeoGebra Portable preferences (GeoGebra settings file)";
// / --- Properties --- ///
// use parent class PROPERTY_FILEPATH private static String path=null;
private static Properties properties = new Properties();
private static GeoGebraPortablePreferences singleton = null;
// / --- Interface --- ///
/* private singleton constructor */
private GeoGebraPortablePreferences() {
}
/* Singleton getInstance()->getPref() */
public synchronized static GeoGebraPreferencesD getPref() {
if (singleton == null) {
singleton = new GeoGebraPortablePreferences();
singleton.loadPreferences();
} // if
return singleton;
}// getPref()
private void loadPreferences() {
try { // debug("path: "+GeoGebraPreferences.PROPERTY_FILEPATH);
File propertyfile = GeoGebraPreferencesD.getFile();
if (propertyfile.exists()) {
// path=propertyfile.getCanonicalPath();
BufferedInputStream fis = new BufferedInputStream(
new FileInputStream(propertyfile));
properties.load(fis);
fis.close(); // debug("loadPreferences():");properties.list(System.out);
} else {
// debug("Found no settings file...");
clearPreferences(); // clean and store a blank one.
} // if
} catch (Exception e) {
Log.debug("Problem loading settings file...");
e.printStackTrace();
} // try-catch
}// loadPreferences
private static void storePreferences() {
if (!get("read_only", "false").equals("true")) {
try {
BufferedOutputStream os = new BufferedOutputStream(
new FileOutputStream(GeoGebraPreferencesD.getFile()));
properties.store(os, COMMENT); // Application.debug("storePreferences():
// ");properties.list(System.out);
os.close();
} catch (Exception e) {
Log.debug("Problem with storing of preferences.properties..."
+ e.toString());
} // try-catch
} // if not read-only. (else do nothing...)
}// storePreferences()
// / --- GeoGebraPreferences interface --- ///
@Override
public String loadPreference(String key, String defaultValue) { // debug("loadPreferene()
// called
// with:
// "+key+",
// "+defaultValue);
return get(key, defaultValue);
}// loadPreference(key,def)
@Override
public void savePreference(String key, String value) { // debug("savePreferneces()
// called with:
// "+key+",
// "+value);
set(key, value);
}// savePreferences(key,val)
/**
* Returns the path of the first file in the file list
*/
@Override
public File getDefaultFilePath() {
File file = new File(properties.getProperty(APP_FILE_ + "1", "")); // debug("getDeafultFilepath():
// "+file.toString());
if (file.exists()) {
return file.getParentFile();
}
return null;
}// getDefaultFilePath()
/**
* Returns the default image path
*/
@Override
public File getDefaultImagePath() {
// image path
String pathName = properties.getProperty(APP_CURRENT_IMAGE_PATH, null);
if (pathName != null) {
return new File(pathName);
}
return null;
}
/**
* Saves the currently set locale.
*/
@Override
public void saveDefaultImagePath(File imgPath) {
try {
if (imgPath != null) {
set(APP_CURRENT_IMAGE_PATH, imgPath.getCanonicalPath());
}
} catch (Exception e) {
e.printStackTrace();
}
}// saveDefaultImagePath(File)
/**
* Returns the default locale
*/
@Override
public Locale getDefaultLocale() {
// language
String strLocale = get(APP_LOCALE, null);
if (strLocale != null) {
return AppD.getLocale(strLocale);
}
return null;
}// getDefaultLocale()
/**
* Saves the currently set locale.
*/
@Override
public void saveDefaultLocale(Locale locale) {
// save locale (language)
set(APP_LOCALE, locale.toString());
}// saveDefaultLocle(Locale)
/**
* Loads the names of the eight last used files from the preferences backing
* store.
*/
@Override
public void loadFileList() {
// load last four files
for (int i = AppD.MAX_RECENT_FILES; i >= 1; i--) {
File file = new File(get(APP_FILE_ + i, "")); // debug("loadFileList()
// called:
// "+file.toString());
AppD.addToFileList(file);
}
}// loadFileList()
/**
* Saves the names of the four last used files.
*/
@Override
public void saveFileList() {
String path;
try {
// save last four files
for (int i = 1; i <= AppD.MAX_RECENT_FILES; i++) {
File file = AppD.getFromFileList(i - 1);
if (file != null) {
path = file.getCanonicalPath(); // debug("saveFilelist():
// "+path.toString());
set(APP_FILE_ + i, path);
} else {
set(APP_FILE_ + i, "");
}
} // debug("list:");properties.list(System.out);
} catch (Exception e) {
e.printStackTrace();
}
// If this is the last call to the pref system and is always done on
// exit
// this should be enough: (??)
storePreferences();
}// saveFileList()
/**
* Saves preferences by taking the application's current values. Apparently
* no limit on property length! (# preferences: 8192), so no need to split
* up in pieces :-) But we have to convert byte[]--b64-->String
*/
@Override
public void saveXMLPreferences(AppD app) { // debug("saveXMLPreferences(app):");
// preferences xml
String xml = app.getPreferencesXML();
set(XML_USER_PREFERENCES, xml);
if (!(app.is3D())) // TODO: implement it in Application3D!
{
StringBuilder sb2d = new StringBuilder();
StringBuilder sb3d = new StringBuilder();
app.getKernel().getConstruction().getConstructionDefaults()
.getDefaultsXML(sb2d, sb3d);
String objectPrefsXML = sb2d.toString();
set(XML_DEFAULT_OBJECT_PREFERENCES, objectPrefsXML);
}
byte[] macrofile = app.getMacroFileAsByteArray();
String macrostring = Base64.encodeToString(macrofile, false);
set(TOOLS_FILE_GGT, macrostring);
// Force writing, "flush": //properties.list(System.out);
storePreferences();
}// saveXMLPreferences(Application)
/**
* Loads XML preferences (empty construction with GUI and kernel settings)
* and sets application accordingly. This method clears the current
* construction in the application. Note: the XML string used is the same as
* for ggb files.
*/
@Override
public void loadXMLPreferences(AppD app) {
app.setWaitCursor();
// load this preferences xml file in application
try {
// load tools from ggt file (byte array)
// Must convert String--b64-->byte
String ggtString = get(TOOLS_FILE_GGT, ERROR);
if (ggtString.equals(ERROR)) {
Log.debug("problem with getting GGT...");
} else {
byte[] ggtFile = Base64.decode(ggtString);
app.loadMacroFileFromByteArray(ggtFile, true);
} // if error
// load preferences xml
initDefaultXML(app); // This might not have been called before!
String xml = get(XML_USER_PREFERENCES, factoryDefaultXml);
app.setXML(xml, true);
if (!(app.is3D())) // TODO: implement it in Application3D!
{
String xmlDef = get(XML_DEFAULT_OBJECT_PREFERENCES,
factoryDefaultXml);
if (!xmlDef.equals(factoryDefaultXml)) {
boolean eda = app.getKernel().getElementDefaultAllowed();
app.getKernel().setElementDefaultAllowed(true);
app.setXML(xmlDef, false);
app.getKernel().setElementDefaultAllowed(eda);
}
}
} catch (Exception e) {
e.printStackTrace();
} // try-catch
app.setDefaultCursor(); // debug("loadXMLPreferences()
// called");properties.list(System.out);
}// loadXMLPreferences(Application)
/**
* Clears all user preferences.
*/
public void clearPreferences() {
try {
properties.clear();
// ggbPrefs.flush();
storePreferences();
} catch (Exception e) {
Log.debug(e + "");
}
}
// / --- Private --- ///
// get/set with check
private static String get(String key, String def) {
if (properties != null) {
return properties.getProperty(key, def);
}
return ERROR;
}// get()
public static final void set(String key, String val) {
if (properties != null) {
properties.setProperty(key, val);
}
}// set()
}// class GeoGebraPortablePreferences