/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution 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, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.prefs;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Locale;
import java.util.prefs.BackingStoreException;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import javax.swing.JFrame;
import com.cburch.logisim.Main;
import com.cburch.logisim.circuit.RadixOption;
import com.cburch.logisim.data.Direction;
import com.cburch.logisim.gui.start.Startup;
import com.cburch.logisim.util.LocaleListener;
import com.cburch.logisim.util.LocaleManager;
import com.cburch.logisim.util.PropertyChangeWeakSupport;
public class AppPreferences {
//
// LocalePreference
//
private static class LocalePreference extends PrefMonitorString {
private static Locale findLocale(String lang) {
Locale[] check;
for (int set = 0; set < 2; set++) {
if (set == 0)
check = new Locale[] { Locale.getDefault(), Locale.ENGLISH };
else
check = Locale.getAvailableLocales();
for (int i = 0; i < check.length; i++) {
Locale loc = check[i];
if (loc != null && loc.getLanguage().equals(lang)) {
return loc;
}
}
}
return null;
}
public LocalePreference() {
super("locale", "");
String localeStr = this.get();
if (localeStr != null && !localeStr.equals("")) {
LocaleManager.setLocale(new Locale(localeStr));
}
LocaleManager.addLocaleListener(myListener);
myListener.localeChanged();
}
@Override
public void set(String value) {
if (findLocale(value) != null) {
super.set(value);
}
}
}
//
// methods for accessing preferences
//
private static class MyListener implements PreferenceChangeListener,
LocaleListener {
public void localeChanged() {
Locale loc = LocaleManager.getLocale();
String lang = loc.getLanguage();
if (LOCALE != null) {
LOCALE.set(lang);
}
}
public void preferenceChange(PreferenceChangeEvent event) {
Preferences prefs = event.getNode();
String prop = event.getKey();
if (ACCENTS_REPLACE.getIdentifier().equals(prop)) {
getPrefs();
LocaleManager.setReplaceAccents(ACCENTS_REPLACE.getBoolean());
} else if (prop.equals(TEMPLATE_TYPE)) {
int oldValue = templateType;
int value = prefs.getInt(TEMPLATE_TYPE, TEMPLATE_UNKNOWN);
if (value != oldValue) {
templateType = value;
propertySupport.firePropertyChange(TEMPLATE, oldValue,
value);
propertySupport.firePropertyChange(TEMPLATE_TYPE, oldValue,
value);
}
} else if (prop.equals(TEMPLATE_FILE)) {
File oldValue = templateFile;
File value = convertFile(prefs.get(TEMPLATE_FILE, null));
if (value == null ? oldValue != null : !value.equals(oldValue)) {
templateFile = value;
if (templateType == TEMPLATE_CUSTOM) {
customTemplate = null;
propertySupport.firePropertyChange(TEMPLATE, oldValue,
value);
}
propertySupport.firePropertyChange(TEMPLATE_FILE, oldValue,
value);
}
}
}
}
//
// PropertyChangeSource methods
//
public static void addPropertyChangeListener(PropertyChangeListener listener) {
propertySupport.addPropertyChangeListener(listener);
}
public static void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
propertySupport.addPropertyChangeListener(propertyName, listener);
}
public static void clear() {
Preferences p = getPrefs(true);
try {
p.clear();
} catch (BackingStoreException e) {
}
}
private static File convertFile(String fileName) {
if (fileName == null || fileName.equals("")) {
return null;
} else {
File file = new File(fileName);
return file.canRead() ? file : null;
}
}
private static <E> PrefMonitor<E> create(PrefMonitor<E> monitor) {
return monitor;
}
static void firePropertyChange(String property, boolean oldVal,
boolean newVal) {
propertySupport.firePropertyChange(property, oldVal, newVal);
}
static void firePropertyChange(String property, Object oldVal, Object newVal) {
propertySupport.firePropertyChange(property, oldVal, newVal);
}
private static Template getCustomTemplate() {
File toRead = templateFile;
if (customTemplateFile == null || !(customTemplateFile.equals(toRead))) {
if (toRead == null) {
customTemplate = null;
customTemplateFile = null;
} else {
FileInputStream reader = null;
try {
reader = new FileInputStream(toRead);
customTemplate = Template.create(reader);
customTemplateFile = templateFile;
} catch (Exception t) {
setTemplateFile(null);
customTemplate = null;
customTemplateFile = null;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
}
}
}
}
}
return customTemplate == null ? getPlainTemplate() : customTemplate;
}
public static Template getEmptyTemplate() {
if (emptyTemplate == null)
emptyTemplate = Template.createEmpty();
return emptyTemplate;
}
private static Template getPlainTemplate() {
if (plainTemplate == null) {
ClassLoader ld = Startup.class.getClassLoader();
InputStream in = ld
.getResourceAsStream("resources/logisim/default.templ");
if (in == null) {
plainTemplate = getEmptyTemplate();
} else {
try {
try {
plainTemplate = Template.create(in);
} finally {
in.close();
}
} catch (Exception e) {
plainTemplate = getEmptyTemplate();
}
}
}
return plainTemplate;
}
public static Preferences getPrefs() {
return getPrefs(false);
}
private static Preferences getPrefs(boolean shouldClear) {
if (prefs == null) {
synchronized (AppPreferences.class) {
if (prefs == null) {
Preferences p = Preferences.userNodeForPackage(Main.class);
if (shouldClear) {
try {
p.clear();
} catch (BackingStoreException e) {
}
}
myListener = new MyListener();
p.addPreferenceChangeListener(myListener);
prefs = p;
setTemplateFile(convertFile(p.get(TEMPLATE_FILE, null)));
setTemplateType(p.getInt(TEMPLATE_TYPE, TEMPLATE_PLAIN));
}
}
}
return prefs;
}
//
// recent projects
//
public static List<File> getRecentFiles() {
return recentProjects.getRecentFiles();
}
//
// template methods
//
public static Template getTemplate() {
getPrefs();
switch (templateType) {
case TEMPLATE_PLAIN:
return getPlainTemplate();
case TEMPLATE_EMPTY:
return getEmptyTemplate();
case TEMPLATE_CUSTOM:
return getCustomTemplate();
default:
return getPlainTemplate();
}
}
public static File getTemplateFile() {
getPrefs();
return templateFile;
}
//
// accessor methods
//
public static int getTemplateType() {
getPrefs();
int ret = templateType;
if (ret == TEMPLATE_CUSTOM && templateFile == null) {
ret = TEMPLATE_UNKNOWN;
}
return ret;
}
public static void handleGraphicsAcceleration() {
String accel = GRAPHICS_ACCELERATION.get();
try {
if (accel == ACCEL_NONE) {
System.setProperty("sun.java2d.opengl", "False");
System.setProperty("sun.java2d.d3d", "False");
} else if (accel == ACCEL_OPENGL) {
System.setProperty("sun.java2d.opengl", "True");
System.setProperty("sun.java2d.d3d", "False");
} else if (accel == ACCEL_D3D) {
System.setProperty("sun.java2d.opengl", "False");
System.setProperty("sun.java2d.d3d", "True");
}
} catch (Exception t) {
}
}
public static void removePropertyChangeListener(
PropertyChangeListener listener) {
propertySupport.removePropertyChangeListener(listener);
}
public static void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
propertySupport.removePropertyChangeListener(propertyName, listener);
}
public static void setTemplateFile(File value) {
getPrefs();
setTemplateFile(value, null);
}
public static void setTemplateFile(File value, Template template) {
getPrefs();
if (value != null && !value.canRead())
value = null;
if (value == null ? templateFile != null : !value.equals(templateFile)) {
try {
customTemplateFile = template == null ? null : value;
customTemplate = template;
getPrefs().put(TEMPLATE_FILE,
value == null ? "" : value.getCanonicalPath());
} catch (IOException ex) {
}
}
}
public static void setTemplateType(int value) {
getPrefs();
if (value != TEMPLATE_PLAIN && value != TEMPLATE_EMPTY
&& value != TEMPLATE_CUSTOM) {
value = TEMPLATE_UNKNOWN;
}
if (value != TEMPLATE_UNKNOWN && templateType != value) {
getPrefs().putInt(TEMPLATE_TYPE, value);
}
}
public static void updateRecentFile(File file) {
recentProjects.updateRecent(file);
}
// class variables for maintaining consistency between properties,
// internal variables, and other classes
private static Preferences prefs = null;
private static MyListener myListener = null;
private static PropertyChangeWeakSupport propertySupport = new PropertyChangeWeakSupport(
AppPreferences.class);
// Template preferences
public static final int TEMPLATE_UNKNOWN = -1;
public static final int TEMPLATE_EMPTY = 0;
public static final int TEMPLATE_PLAIN = 1;
public static final int TEMPLATE_CUSTOM = 2;
public static final String TEMPLATE = "template";
public static final String TEMPLATE_TYPE = "templateType";
public static final String TEMPLATE_FILE = "templateFile";
private static int templateType = TEMPLATE_PLAIN;
private static File templateFile = null;
private static Template plainTemplate = null;
private static Template emptyTemplate = null;
private static Template customTemplate = null;
private static File customTemplateFile = null;
// International preferences
public static final String SHAPE_SHAPED = "shaped";
public static final String SHAPE_RECTANGULAR = "rectangular";
public static final String SHAPE_DIN40700 = "din40700";
public static final PrefMonitor<String> GATE_SHAPE = create(new PrefMonitorStringOpts(
"gateShape", new String[] { SHAPE_SHAPED, SHAPE_RECTANGULAR,
SHAPE_DIN40700 }, SHAPE_SHAPED));
public static final PrefMonitor<String> LOCALE = create(new LocalePreference());
public static final PrefMonitor<Boolean> ACCENTS_REPLACE = create(new PrefMonitorBoolean(
"accentsReplace", false));
// Window preferences
public static final String TOOLBAR_HIDDEN = "hidden";
public static final String TOOLBAR_DOWN_MIDDLE = "downMiddle";
public static final PrefMonitor<Boolean> SHOW_TICK_RATE = create(new PrefMonitorBoolean(
"showTickRate", false));
public static final PrefMonitor<String> TOOLBAR_PLACEMENT = create(new PrefMonitorStringOpts(
"toolbarPlacement", new String[] { Direction.NORTH.toString(),
Direction.SOUTH.toString(), Direction.EAST.toString(),
Direction.WEST.toString(), TOOLBAR_DOWN_MIDDLE,
TOOLBAR_HIDDEN }, Direction.NORTH.toString()));
// Layout preferences
public static final String ADD_AFTER_UNCHANGED = "unchanged";
public static final String ADD_AFTER_EDIT = "edit";
public static final PrefMonitor<Boolean> PRINTER_VIEW = create(new PrefMonitorBoolean(
"printerView", false));
public static final PrefMonitor<Boolean> ATTRIBUTE_HALO = create(new PrefMonitorBoolean(
"attributeHalo", true));
public static final PrefMonitor<Boolean> COMPONENT_TIPS = create(new PrefMonitorBoolean(
"componentTips", true));
public static final PrefMonitor<Boolean> MOVE_KEEP_CONNECT = create(new PrefMonitorBoolean(
"keepConnected", true));
public static final PrefMonitor<Boolean> ADD_SHOW_GHOSTS = create(new PrefMonitorBoolean(
"showGhosts", true));
public static final PrefMonitor<Boolean> NAMED_CIRCUIT_BOXES = create(new PrefMonitorBoolean(
"namedBoxes", true));
public static final PrefMonitor<String> ADD_AFTER = create(new PrefMonitorStringOpts(
"afterAdd", new String[] { ADD_AFTER_EDIT, ADD_AFTER_UNCHANGED },
ADD_AFTER_EDIT));
public static PrefMonitor<String> POKE_WIRE_RADIX1;
public static PrefMonitor<String> POKE_WIRE_RADIX2;
static {
RadixOption[] radixOptions = RadixOption.OPTIONS;
String[] radixStrings = new String[radixOptions.length];
for (int i = 0; i < radixOptions.length; i++) {
radixStrings[i] = radixOptions[i].getSaveString();
}
POKE_WIRE_RADIX1 = create(new PrefMonitorStringOpts("pokeRadix1",
radixStrings, RadixOption.RADIX_2.getSaveString()));
POKE_WIRE_RADIX2 = create(new PrefMonitorStringOpts("pokeRadix2",
radixStrings, RadixOption.RADIX_10_SIGNED.getSaveString()));
}
// Experimental preferences
public static final String ACCEL_DEFAULT = "default";
public static final String ACCEL_NONE = "none";
public static final String ACCEL_OPENGL = "opengl";
public static final String ACCEL_D3D = "d3d";
public static final PrefMonitor<String> GRAPHICS_ACCELERATION = create(new PrefMonitorStringOpts(
"graphicsAcceleration", new String[] { ACCEL_DEFAULT, ACCEL_NONE,
ACCEL_OPENGL, ACCEL_D3D }, ACCEL_DEFAULT));
// Third party softwares preferences
public static final PrefMonitor<String> QUESTA_PATH = create(new PrefMonitorString(
"questaPath", ""));
public static final PrefMonitor<Boolean> QUESTA_VALIDATION = create(new PrefMonitorBoolean(
"questaValidation", false));
// hidden window preferences - not part of the preferences dialog, changes
// to preference does not affect current windows, and the values are not
// saved until the application is closed
public static final String RECENT_PROJECTS = "recentProjects";
private static final RecentProjects recentProjects = new RecentProjects();
public static final PrefMonitor<Double> TICK_FREQUENCY = create(new PrefMonitorDouble(
"tickFrequency", 1.0));
public static final PrefMonitor<Boolean> LAYOUT_SHOW_GRID = create(new PrefMonitorBoolean(
"layoutGrid", true));
public static final PrefMonitor<Double> LAYOUT_ZOOM = create(new PrefMonitorDouble(
"layoutZoom", 1.0));
public static final PrefMonitor<Boolean> APPEARANCE_SHOW_GRID = create(new PrefMonitorBoolean(
"appearanceGrid", true));
public static final PrefMonitor<Double> APPEARANCE_ZOOM = create(new PrefMonitorDouble(
"appearanceZoom", 1.0));
public static final PrefMonitor<Integer> WINDOW_STATE = create(new PrefMonitorInt(
"windowState", JFrame.NORMAL));
public static final PrefMonitor<Integer> WINDOW_WIDTH = create(new PrefMonitorInt(
"windowWidth", 640));
public static final PrefMonitor<Integer> WINDOW_HEIGHT = create(new PrefMonitorInt(
"windowHeight", 480));
public static final PrefMonitor<String> WINDOW_LOCATION = create(new PrefMonitorString(
"windowLocation", "0,0"));
public static final PrefMonitor<Double> WINDOW_MAIN_SPLIT = create(new PrefMonitorDouble(
"windowMainSplit", 0.25));
public static final PrefMonitor<Double> WINDOW_LEFT_SPLIT = create(new PrefMonitorDouble(
"windowLeftSplit", 0.5));
public static final PrefMonitor<Double> WINDOW_RIGHT_SPLIT = create(new PrefMonitorDouble(
"windowRightSplit", 0.75));
public static final PrefMonitor<String> DIALOG_DIRECTORY = create(new PrefMonitorString(
"dialogDirectory", ""));
}