![JAR search and dependency download from the Maven repository](/logo.png)
com.sun.electric.database.text.Setting Maven / Gradle / Ivy
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: Setting.java
*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) 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.
*
* Electric(tm) 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 Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.database.text;
import com.sun.electric.database.Environment;
import com.sun.electric.database.id.IdReader;
import com.sun.electric.database.id.IdWriter;
import com.sun.electric.database.variable.Variable;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.prefs.Preferences;
/**
* This class manages meaning options.
* There are two types of options: appearance and meaning.
* Appearance options affect the way that the design is presented to the user.
* Meaning options affect the way that a design is produced (for fabrication,
* simulation, and other outputs). Examples are CIF layer names, technology
* options, etc.)
* Settings are grouped in a Setting Trees. Each Tree consists of a RootGroup and lower Groups.
*/
public class Setting {
/**
* This class manages a group of Settings.
*/
public static class Group {
public final String xmlPath;
private final RootGroup root;
private final LinkedHashMap children = new LinkedHashMap();
private final LinkedHashMap settings = new LinkedHashMap();
private Group(RootGroup root, String xmlPath) {
this.root = root;
this.xmlPath = xmlPath;
}
private Group() {
root = (RootGroup) this;
xmlPath = "";
}
/**
* Returns subnode with specified node name
* @param nodeName simple node name
* @return subnode with specified node name
* @throws IllegalStateException if the Setting
*/
public Group node(String nodeName) {
assert nodeName.indexOf('.') == -1;
if (nodeName.length() == 0) {
return this;
}
Group child = children.get(nodeName);
if (child == null) {
if (root.isLocked()) {
throw new IllegalStateException();
}
child = new Group(root, xmlPath + nodeName + '.');
children.put(nodeName, child);
}
return child;
}
/**
* Dot-spearated path from the Root of the tree to this Group
* @return path from the Root of the tree to this Group
*/
public String getXmlPath() {
return xmlPath;
}
/**
* Factory methods to create a boolean project preferences objects.
* @param prefName preference name of this Setting.
* @param prefGroup preference Group of this Setting.
* @param xmlName Xml name of this Setting.
* @param location the user-command that can affect this meaning option.
* @param description the description of this meaning option.
* @param factory the "factory" default value (if nothing is stored).
*/
public Setting makeBooleanSetting(String prefName, String prefGroup, String xmlName,
String location, String description, boolean factory) {
return new Setting(prefName, prefGroup, this, xmlName, location, description, Boolean.valueOf(factory));
}
/**
* Factory methods to create an integer project preferences objects.
* @param prefName preference name of this Setting.
* @param prefGroup preference Group of this Setting.
* @param xmlName Xml name of this Setting.
* @param location the user-command that can affect this meaning option.
* @param description the description of this meaning option.
* @param factory the "factory" default value (if nothing is stored).
*/
public Setting makeIntSetting(String prefName, String prefGroup, String xmlName,
String location, String description, int factory, String... trueMeaning) {
return new Setting(prefName, prefGroup, this, xmlName, location, description, Integer.valueOf(factory), trueMeaning);
}
/**
* Factory methods to create a long project preferences objects.
* @param prefName preference name of this Setting.
* @param prefGroup preference Group of this Setting.
* @param xmlName Xml name of this Setting.
* @param location the user-command that can affect this meaning option.
* @param description the description of this meaning option.
* @param factory the "factory" default value (if nothing is stored).
*/
public Setting makeLongSetting(String prefName, String prefGroup, String xmlName,
String location, String description, long factory) {
return new Setting(prefName, prefGroup, this, xmlName, location, description, Long.valueOf(factory));
}
/**
* Factory methods to create a double project preferences objects.
* @param prefName preference name of this Setting.
* @param prefGroup preference Group of this Setting.
* @param xmlName Xml name of this Setting.
* @param location the user-command that can affect this meaning option.
* @param description the description of this meaning option.
* @param factory the "factory" default value (if nothing is stored).
*/
public Setting makeDoubleSetting(String prefName, String prefGroup, String xmlName,
String location, String description, double factory) {
return new Setting(prefName, prefGroup, this, xmlName, location, description, Double.valueOf(factory));
}
/**
* Factory methods to create a string project preferences objects.
* @param prefName preference name of this Setting.
* @param prefGroup preference Group of this Setting.
* @param xmlName Xml name of this Setting.
* @param location the user-command that can affect this meaning option.
* @param description the description of this meaning option.
* @param factory the "factory" default value (if nothing is stored).
*/
public Setting makeStringSetting(String prefName, String prefGroup, String xmlName,
String location, String description, String factory) {
return new Setting(prefName, prefGroup, this, xmlName, location, description, factory);
}
/**
* Returns Setting from this Group or a subgroup by its relative path
* @param xmlPath dot-separated relative path
* @return Setting by relative path or null
*/
public Setting getSetting(String xmlPath) {
int pos = xmlPath.indexOf('.');
if (pos < 0) {
return settings.get(xmlPath);
}
Group child = children.get(xmlPath.substring(0, pos));
if (child == null) {
return null;
}
return child.getSetting(xmlPath.substring(pos + 1));
}
/**
* Returns all Settings from this Group and its subgroups
* @return all Settings from this Group and its subgroups
*/
public Collection getSettings() {
ArrayList list = new ArrayList();
gatherSettings(list);
return list;
}
private void gatherSettings(ArrayList list) {
list.addAll(settings.values());
for (Group child : children.values()) {
child.gatherSettings(list);
}
}
/**
* Method to get a list of project preferences from this Group
* which should be written to disk libraries
* @return a collection of project preferences
*/
public Map getDiskSettings(Map settingValues) {
Map result = new TreeMap(SETTINGS_BY_PREF_NAME);
for (Setting setting : getSettings()) {
Object value = settingValues.get(setting);
if (!setting.isValidOption()) {
continue;
}
if (value.equals(setting.getFactoryValue())) {
continue;
}
result.put(setting, value);
}
return result;
}
@Override
public String toString() {
return xmlPath;
}
void write(IdWriter writer) throws IOException {
writer.writeInt(settings.size());
for (Map.Entry e : settings.entrySet()) {
String key = e.getKey();
Setting setting = e.getValue();
writer.writeString(key);
setting.writeSetting(writer);
}
writer.writeInt(children.size());
for (Map.Entry e : children.entrySet()) {
String key = e.getKey();
Group child = e.getValue();
writer.writeString(key);
child.write(writer);
}
}
void read(IdReader reader) throws IOException {
int numSettings = reader.readInt();
for (int i = 0; i < numSettings; i++) {
String key = reader.readString();
Setting.readSetting(reader, this, key);
}
int numChildren = reader.readInt();
for (int i = 0; i < numChildren; i++) {
String key = reader.readString();
Group child = node(key);
child.read(reader);
}
}
}
/**
* This class manages a tree of Settings.
*/
public static class RootGroup extends Group {
private boolean locked;
/**
* Constructs a root of empty tree of Settings
*/
public RootGroup() {
}
/**
* Returns empty locked RootGroup
* @return empty locked RootGroup
*/
public static RootGroup newEmptyGroup() {
RootGroup rootGroup = new RootGroup();
rootGroup.lock();
return rootGroup;
}
/**
* Returns true if tree can't be modified anymore
* @return true if tree is locked
*/
public boolean isLocked() {
return locked;
}
/**
* Locks the tree
*/
public void lock() {
locked = true;
}
/**
* Writes this Tree of Settings to IdManager writer
* @param writer IdManager writer
* @throws java.io.IOException om writer error
*/
@Override
public void write(IdWriter writer) throws IOException {
super.write(writer);
}
}
/**
* Reads a Tree of Settings fro, IdManager reader
* @param reader IdManager reader
* @throws java.io.IOException om reader error
*/
public static RootGroup read(IdReader reader) throws IOException {
RootGroup root = new RootGroup();
root.read(reader);
root.lock();
return root;
}
private final Group xmlGroup;
private final String xmlPath;
private final Object factoryObj;
private final String prefNode;
private final String prefName;
private boolean valid;
private final String description, location;
private final String[] trueMeaning;
/** Creates a new instance of Setting */
protected Setting(String prefName, String prefGroup, Group xmlGroup, String xmlName,
String location, String description, Object factoryObj, String... trueMeaning) {
if (xmlGroup == null) {
throw new NullPointerException();
}
if (xmlGroup.root.isLocked()) {
throw new IllegalStateException();
}
if (xmlName == null) {
xmlName = prefName;
}
assert xmlName.length() > 0;
assert xmlName.indexOf('.') == -1;
assert !xmlGroup.settings.containsKey(xmlName);
xmlPath = xmlGroup + xmlName;
this.xmlGroup = xmlGroup;
this.factoryObj = factoryObj;
this.prefName = prefName;
prefNode = prefGroup;
xmlGroup.settings.put(xmlName, this);
valid = true;
this.description = description;
this.location = location;
this.trueMeaning = trueMeaning != null && trueMeaning.length > 0 ? trueMeaning.clone() : null;
}
/**
* Method to get the boolean value on this Setting object.
* The object must have been created as "boolean".
* @return the boolean value on this TechSetting object.
*/
public boolean getBoolean() {
return ((Boolean) getValue()).booleanValue();
}
/**
* Method to get the integer value on this Setting object.
* The object must have been created as "integer".
* @return the integer value on this TechSetting object.
*/
public int getInt() {
return ((Integer) getValue()).intValue();
}
/**
* Method to get the long value on this Setting object.
* The object must have been created as "long".
* @return the long value on this TechSetting object.
*/
public long getLong() {
return ((Long) getValue()).longValue();
}
/**
* Method to get the double value on this Setting object.
* The object must have been created as "double".
* @return the double value on this TechSetting object.
*/
public double getDouble() {
return ((Double) getValue()).doubleValue();
}
/**
* Method to get the string value on this Setting object.
* The object must have been created as "string".
* @return the string value on this TechSetting object.
*/
public String getString() {
String s = (String) getValue();
if (s == null) {
throw new NullPointerException();
}
return s;
}
/**
* Method to get the value of this Setting object as an Object.
* The proper way to get the current value is to use one of the type-specific
* methods such as getInt(), getBoolean(), etc.
* @return the Object value of this Setting object.
*/
public Object getValue() {
return Environment.getThreadEnvironment().getValue(this);
}
@Override
public String toString() {
return getXmlPath();
}
/**
* Method to get the xml name of this Setting object.
* @return the xml name of this Setting object.
*/
public String getXmlPath() {
return xmlPath;
}
/**
* Method to get the name of this Setting object.
* @return the name of this Setting object.
*/
public String getPrefName() {
return prefName;
}
/**
* Method to get the pref name of this Setting object.
* @return the name of this Setting object.
*/
public String getPrefPath() {
return prefNode + "/" + prefName;
}
/**
* Method to return the user-command that can affect this Meaning option.
* @return the user-command that can affect this Meaning option.
*/
public String getLocation() {
return location;
}
/**
* Method to return the description of this Meaning option.
* @return the Pref description of this Meaning option.
*/
public String getDescription() {
return description;
}
/**
* Method to set whether this Meaning option is valid and should be reconciled.
* Some should not, for example, the scale value on technologies that
* don't use scaling (such as Schematics, Artwork, etc.)
* @param valid true if this Meaning option is valid and should be reconciled.
*/
public void setValidOption(boolean valid) {
if (xmlGroup.root.isLocked()) {
throw new IllegalStateException();
}
this.valid = valid;
}
/**
* Method to tell whether this Meaning option is valid and should be reconciled.
* Some should not, for example, the scale value on technologies that
* don't use scaling (such as Schematics, Artwork, etc.)
* @return true if this Meaning option is valid and should be reconciled.
*/
public boolean isValidOption() {
return valid;
}
/**
* Method to return an array of strings to be used for integer Meaning options.
* Some options are multiple-choice, for example the MOSIS CMOS rule set which can be
* 0, 1, or 2 depending on whether the set is SCMOS, Submicron, or Deep.
* By giving an array of 3 strings to this method, a proper description of the option
* can be given to the user.
* @return the array of strings that should be used for this integer Meaning option.
*/
public String[] getTrueMeaning() {
return trueMeaning != null ? trueMeaning.clone() : null;
}
/**
* Method to get the factory-default value of this Pref object.
* @return the factory-default value of this Pref object.
*/
public Object getFactoryValue() {
return factoryObj;
}
/**
* Method to get the factory-default double value of this Pref object.
* @return the factory-default double value of this Pref object.
*/
public double getDoubleFactoryValue() {
return ((Double) factoryObj).doubleValue();
}
/**
* Method to get the factory-default int value of this Pref object.
* @return the factory-default int value of this Pref object.
*/
public int getIntFactoryValue() {
return ((Integer) factoryObj).intValue();
}
private static Comparator SETTINGS_BY_PREF_NAME = new Comparator() {
public int compare(Setting s1, Setting s2) {
String n1 = s1.getPrefName();
String n2 = s2.getPrefName();
return n1.compareTo(n2);
}
};
public void saveToPreferences(Preferences prefRoot, Object v) {
assert v.getClass() == factoryObj.getClass();
Preferences prefs = prefRoot.node(prefNode);
if (v.equals(factoryObj)) {
prefs.remove(prefName);
return;
}
if (v instanceof Boolean) {
prefs.putBoolean(prefName, ((Boolean) v).booleanValue());
} else if (v instanceof Integer) {
prefs.putInt(prefName, ((Integer) v).intValue());
} else if (v instanceof Long) {
prefs.putLong(prefName, ((Long) v).longValue());
} else if (v instanceof Double) {
prefs.putDouble(prefName, ((Double) v).doubleValue());
} else if (v instanceof String) {
prefs.put(prefName, (String) v);
} else {
assert false;
}
}
public Object getValueFromPreferences(Preferences prefRoot) {
Preferences prefs = prefRoot.node(prefNode);
Object cachedObj = null;
if (factoryObj instanceof Boolean) {
cachedObj = Boolean.valueOf(prefs.getBoolean(prefName, ((Boolean) factoryObj).booleanValue()));
} else if (factoryObj instanceof Integer) {
cachedObj = Integer.valueOf(prefs.getInt(prefName, ((Integer) factoryObj).intValue()));
} else if (factoryObj instanceof Long) {
cachedObj = Long.valueOf(prefs.getLong(prefName, ((Long) factoryObj).longValue()));
} else if (factoryObj instanceof Double) {
cachedObj = Double.valueOf(prefs.getDouble(prefName, ((Double) factoryObj).doubleValue()));
} else if (factoryObj instanceof String) {
cachedObj = prefs.get(prefName, (String) factoryObj);
}
assert cachedObj != null;
return cachedObj;
}
private void writeSetting(IdWriter writer) throws IOException {
// xmlPath
Variable.writeObject(writer, factoryObj);
writer.writeString(prefNode);
writer.writeString(prefName);
writer.writeBoolean(valid);
writer.writeString(description);
writer.writeString(location);
boolean hasTrueMeaning = trueMeaning != null;
writer.writeBoolean(hasTrueMeaning);
if (hasTrueMeaning) {
writer.writeInt(trueMeaning.length);
for (String s : trueMeaning) {
writer.writeString(s);
}
}
}
private static Setting readSetting(IdReader reader, Group group, String xmlName) throws IOException {
Object factoryObj = Variable.readObject(reader);
String prefGroup = reader.readString();
String prefName = reader.readString();
boolean valid = reader.readBoolean();
String description = reader.readString();
String location = reader.readString();
String[] trueMeaning = null;
boolean hasTrueMeaning = reader.readBoolean();
if (hasTrueMeaning) {
trueMeaning = new String[reader.readInt()];
for (int i = 0; i < trueMeaning.length; i++) {
trueMeaning[i] = reader.readString();
}
}
Setting setting = new Setting(prefName, prefGroup, group, xmlName, location, description, factoryObj, trueMeaning);
setting.setValidOption(valid);
return setting;
}
public static class SettingChangeBatch implements Serializable {
public HashMap changesForSettings = new HashMap();
public void add(Setting setting, Object newValue) {
changesForSettings.put(setting.xmlPath, newValue);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy