Added: Configuration in TOML format

This commit is contained in:
Jindra Petřík
2025-05-18 13:53:54 +02:00
parent ca54060785
commit 0408fc645b
16 changed files with 802 additions and 48 deletions

View File

@@ -44,6 +44,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -61,11 +62,13 @@ import javax.swing.JOptionPane;
*/
public final class Configuration {
private static final String CONFIG_NAME = "config.bin";
private static final ConfigurationStorage legacyStorage = new LegacyConfigurationStorage();
private static final File unspecifiedFile = new File("unspecified");
private static final ConfigurationStorage storage = new TomlConfigurationStorage();
private static File directory = unspecifiedFile;
private static final File UNSPECIFIED_FILE = new File("unspecified");
private static File directory = UNSPECIFIED_FILE;
/**
* Log level
@@ -168,6 +171,7 @@ public final class Configuration {
public static ConfigurationItem<Boolean> openFolderAfterFlaExport = null;
@ConfigurationCategory("export")
@ConfigurationDefaultString("")
public static ConfigurationItem<String> overrideTextExportFileName = null;
@ConfigurationDefaultBoolean(false)
@@ -1144,10 +1148,32 @@ public final class Configuration {
@ConfigurationCategory("display")
public static ConfigurationItem<Boolean> snapAlignCenterAlignmentVertical = null;
private static Map<String, String> configurationDescriptions = new LinkedHashMap<>();
private static Map<String, String> configurationTitles = new LinkedHashMap<>();
private enum OSId {
WINDOWS, OSX, UNIX
}
public static void setConfigurationDescriptions(Map<String, String> configurationDescriptions) {
Configuration.configurationDescriptions = configurationDescriptions;
}
public static void setConfigurationTitles(Map<String, String> configurationTitles) {
Configuration.configurationTitles = configurationTitles;
}
public static String getConfigurationTitle(String confirationName) {
return configurationTitles.get(confirationName);
}
public static String getConfigurationDescription(String confirationName) {
return configurationDescriptions.get(confirationName);
}
private static OSId getOSId() {
String OS = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
if ((OS.indexOf("mac") >= 0) || (OS.indexOf("darwin") >= 0)) {
@@ -1165,7 +1191,7 @@ public final class Configuration {
* @return FFDec home directory
*/
public static String getFFDecHome() {
if (directory == unspecifiedFile) {
if (directory == UNSPECIFIED_FILE) {
directory = null;
String userHome = null;
try {
@@ -1379,52 +1405,24 @@ public final class Configuration {
}
private static String getConfigFile() throws IOException {
return getFFDecHome() + CONFIG_NAME;
return getFFDecHome() + storage.getConfigName();
}
private static HashMap<String, Object> loadFromFile(String file) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
@SuppressWarnings("unchecked")
HashMap<String, Object> cfg = (HashMap<String, Object>) ois.readObject();
return cfg;
} catch (ClassNotFoundException | IOException ex) {
// ignore
}
return new HashMap<>();
private static String getLegacyConfigFile() throws IOException {
return getFFDecHome() + legacyStorage.getConfigName();
}
private static void saveToFile(String file) {
HashMap<String, Object> config = new HashMap<>();
for (Entry<String, Field> entry : getConfigurationFields(false, true).entrySet()) {
try {
String name = entry.getKey();
Field field = entry.getValue();
ConfigurationItem item = (ConfigurationItem) field.get(null);
if (item.hasValue) {
config.put(name, item.get());
}
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
}
}
try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
oos.writeObject(config);
} catch (IOException ex) {
//TODO: move this to GUI
ex.printStackTrace();
JOptionPane.showMessageDialog(null, "Cannot save configuration.", "Error", JOptionPane.ERROR_MESSAGE);
Logger.getLogger(Configuration.class.getName()).severe("Configuration directory is read only.");
}
}
/**
* Save configuration to file
*/
public static void saveConfig() {
try {
saveToFile(getConfigFile());
storage.saveToFile(getConfigFile());
} catch (IOException ex) {
// ignore
}
try {
legacyStorage.saveToFile(getLegacyConfigFile());
} catch (IOException ex) {
// ignore
}
@@ -1449,7 +1447,14 @@ public final class Configuration {
@SuppressWarnings("unchecked")
public static void setConfigurationFields() {
try {
HashMap<String, Object> config = loadFromFile(getConfigFile());
Map<String, Object> config;
if (new File(getConfigFile()).exists()) {
config = storage.loadFromFile(getConfigFile());
} else {
config = legacyStorage.loadFromFile(getLegacyConfigFile());
}
for (Entry<String, Field> entry : getConfigurationFields(false, true).entrySet()) {
String name = entry.getKey();
Field field = entry.getValue();
@@ -1544,6 +1549,18 @@ public final class Configuration {
defaultValue = Color.black;
}
}
if (defaultValue == null) {
Class<?> type = ConfigurationItem.getConfigurationFieldType(field);
if (type.isEnum()) {
@SuppressWarnings("unchecked")
Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) type;
defaultValue = enumClass.getEnumConstants()[0];
}
if (type == String.class) {
defaultValue = "";
}
}
return defaultValue;
}
@@ -1562,7 +1579,7 @@ public final class Configuration {
*/
public static Map<String, Field> getConfigurationFields(boolean lowerCaseNames, boolean alsoRemoved) {
Field[] fields = Configuration.class.getDeclaredFields();
Map<String, Field> result = new HashMap<>();
Map<String, Field> result = new LinkedHashMap<>();
for (Field field : fields) {
if (!alsoRemoved) {
ConfigurationRemoved removedAnnotation = field.getAnnotation(ConfigurationRemoved.class);

View File

@@ -0,0 +1,31 @@
/*
* Copyright (C) 2010-2024 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.configuration;
import java.util.Map;
/**
*
* @author JPEXS
*/
public interface ConfigurationStorage {
public String getConfigName();
public Map<String, Object> loadFromFile(String file);
public void saveToFile(String file);
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (C) 2010-2024 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.configuration;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
/**
*
* @author JPEXS
*/
public class LegacyConfigurationStorage implements ConfigurationStorage {
@Override
public String getConfigName() {
return "config.bin";
}
@Override
public Map<String, Object> loadFromFile(String file) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
@SuppressWarnings("unchecked")
Map<String, Object> cfg = (HashMap<String, Object>) ois.readObject();
return cfg;
} catch (ClassNotFoundException | IOException ex) {
// ignore
}
return new HashMap<>();
}
public void saveToFile(String file) {
Map<String, Object> config = new HashMap<>();
for (Map.Entry<String, Field> entry : Configuration.getConfigurationFields(false, true).entrySet()) {
try {
String name = entry.getKey();
Field field = entry.getValue();
ConfigurationItem item = (ConfigurationItem) field.get(null);
if (item.hasValue) {
config.put(name, item.get());
}
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
}
}
try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) {
oos.writeObject(config);
} catch (IOException ex) {
//TODO: move this to GUI
ex.printStackTrace();
JOptionPane.showMessageDialog(null, "Cannot save configuration.", "Error", JOptionPane.ERROR_MESSAGE);
Logger.getLogger(Configuration.class.getName()).severe("Configuration directory is read only.");
}
}
}

View File

@@ -36,6 +36,10 @@ public class SwfSpecificCustomConfiguration implements Serializable {
public static final String LIST_SEPARATOR = "{*sep*}";
public Map<String, String> getAllCustomData() {
return customData;
}
public List<String> getCustomDataAsList(String key) {
String data = getCustomData(key, "");
String[] parts = (data + LIST_SEPARATOR).split(Pattern.quote(LIST_SEPARATOR));

View File

@@ -0,0 +1,556 @@
/*
* Copyright (C) 2010-2024 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.configuration;
import com.jpexs.decompiler.flash.AppResources;
import com.jpexs.decompiler.flash.ApplicationInfo;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.helpers.Helper;
import java.awt.Color;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.tomlj.Toml;
import org.tomlj.TomlParseError;
import org.tomlj.TomlParseResult;
import org.tomlj.TomlTable;
/**
*
* @author JPEXS
*/
public class TomlConfigurationStorage implements ConfigurationStorage {
public String getConfigName() {
return "config.toml";
}
@Override
public Map<String, Object> loadFromFile(String file) {
Map<String, Object> result = new LinkedHashMap<>();
TomlParseResult tomlResult;
try {
tomlResult = Toml.parse(Paths.get(file));
} catch (IOException ex) {
return result;
}
if (!tomlResult.errors().isEmpty()) {
System.err.println("Error parsing configuration file:");
for (TomlParseError error : tomlResult.errors()) {
System.err.println("- " + error);
}
}
TomlTable configurationTable = tomlResult.getTable("configuration");
if (configurationTable == null) {
return result;
}
for (Map.Entry<String, Field> entry : Configuration.getConfigurationFields(false, true).entrySet()) {
try {
String name = entry.getKey();
Field field = entry.getValue();
ConfigurationItem item = (ConfigurationItem) field.get(null);
ConfigurationName nameAnnotation = field.getAnnotation(ConfigurationName.class);
if (nameAnnotation != null) {
name = nameAnnotation.value();
}
String key = name;
if (key.contains(".")) {
key = "\"" + key + "\"";
}
Object value = null;
switch (name) {
case "fontPairingMap":
TomlTable fontPairingTable = configurationTable.getTable(key);
if (fontPairingTable != null) {
Map<String, String> fontPairingMap = new LinkedHashMap<>();
for (Map.Entry<String, Object> fontEntry : fontPairingTable.entrySet()) {
if (fontEntry.getValue() instanceof String) {
fontPairingMap.put(fontEntry.getKey(), (String) fontEntry.getValue());
}
}
value = fontPairingMap;
}
break;
case "swfSpecificConfigs":
TomlTable swfSpecificConfigsTable = configurationTable.getTable(key);
if (swfSpecificConfigsTable != null) {
Map<String, SwfSpecificConfiguration> swfSpecificConfigs = new LinkedHashMap<>();
for (Map.Entry<String, Object> swfEntry : swfSpecificConfigsTable.entrySet()) {
String swfKey = swfEntry.getKey();
if (swfEntry.getValue() instanceof TomlTable) {
SwfSpecificConfiguration swfSpecificConfig = new SwfSpecificConfiguration();
TomlTable configsTable = (TomlTable) swfEntry.getValue();
TomlTable swfSpecificFontPairingTable = configsTable.getTable("fontPairingMap");
Map<String, String> swfSpecificFontPairingMap = new LinkedHashMap<>();
for (Map.Entry<String, Object> fontEntry : swfSpecificFontPairingTable.entrySet()) {
if (fontEntry.getValue() instanceof String) {
swfSpecificFontPairingMap.put(fontEntry.getKey(), (String) fontEntry.getValue());
}
}
swfSpecificConfig.fontPairingMap = swfSpecificFontPairingMap;
swfSpecificConfig.lastSelectedPath = configsTable.getString("lastSelectedPath");
swfSpecificConfigs.put(swfKey, swfSpecificConfig);
}
}
value = swfSpecificConfigs;
}
break;
case "swfSpecificCustomConfigs":
TomlTable swfSpecificCustomConfigsTable = configurationTable.getTable(key);
if (swfSpecificCustomConfigsTable != null) {
Map<String, SwfSpecificCustomConfiguration> swfSpecificCustomConfigs = new LinkedHashMap<>();
for (Map.Entry<String, Object> swfEntry : swfSpecificCustomConfigsTable.entrySet()) {
String swfKey = swfEntry.getKey();
if (swfEntry.getValue() instanceof TomlTable) {
SwfSpecificCustomConfiguration swfSpecificCustomConfig = new SwfSpecificCustomConfiguration();
Map<String, String> swfSpecificCustomConfigMap = swfSpecificCustomConfig.getAllCustomData();
TomlTable configsTable = (TomlTable) swfEntry.getValue();
for (Map.Entry<String, Object> customDataEntry : configsTable.entrySet()) {
if (customDataEntry.getValue() instanceof String) {
swfSpecificCustomConfigMap.put(customDataEntry.getKey(), (String) customDataEntry.getValue());
}
}
swfSpecificCustomConfigs.put(swfKey, swfSpecificCustomConfig);
}
}
value = swfSpecificCustomConfigs;
}
break;
default:
Type type = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
if (type instanceof Class) {
switch (((Class) type).getSimpleName()) {
case "Boolean":
value = configurationTable.getBoolean(key);
break;
case "Calendar":
OffsetDateTime offsetDateTime = configurationTable.getOffsetDateTime(key);
if (offsetDateTime != null) {
Date date = Date.from(offsetDateTime.toInstant());
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
value = calendar;
}
break;
case "Color":
String colorString = configurationTable.getString(key);
if (colorString != null) {
Pattern colorPattern = Pattern.compile("#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$");
Matcher m = colorPattern.matcher(colorString);
if (m.matches()) {
value = new Color(Integer.parseInt(m.group(1), 16), Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16));
}
}
break;
case "Double":
value = configurationTable.getDouble(key);
break;
case "Integer":
Long longValue = configurationTable.getLong(key);
if (longValue != null) {
value = (Integer) (int) (long) longValue;
}
break;
case "String":
value = configurationTable.getString(key);
break;
}
}
}
if (value != null) {
result.put(name, value);
}
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
}
}
return result;
}
private static List<String> wordWrap(String text, int maxLineLength) {
List<String> lines = new ArrayList<>();
String[] words = text.split(" ");
StringBuilder line = new StringBuilder();
for (String word : words) {
if (line.length() + word.length() + 1 > maxLineLength) {
lines.add(line.toString().trim());
line = new StringBuilder();
}
line.append(word).append(" ");
}
if (!line.toString().isEmpty()) {
lines.add(line.toString().trim());
}
return lines;
}
private static String stringOfChar(char c, int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(c);
}
return sb.toString();
}
private static String comment(String comment) {
return "# " + String.join(System.lineSeparator() + "# ", wordWrap(comment, 80 - 2));
}
@Override
public void saveToFile(String file) {
boolean showComments = false;
boolean modifiedOnly = true;
if (new File(file).exists()) {
TomlParseResult tomlResult;
try {
tomlResult = Toml.parse(Paths.get(file));
TomlTable metaTable = tomlResult.getTable("meta");
if (metaTable != null) {
showComments = metaTable.getBoolean("showComments") == Boolean.TRUE;
modifiedOnly = metaTable.getBoolean("modifiedOnly") == Boolean.TRUE;
}
} catch (IOException ex) {
//ignore
}
}
try (
Writer w = new FileWriter(file); PrintWriter pw = new PrintWriter(w)) {
String header = AppResources.translate("configurationFile").replace("%app%", ApplicationInfo.APPLICATION_NAME);
String splitter = stringOfChar('-', header.length());
pw.println("# " + splitter);
pw.println("# " + header);
pw.println("# " + splitter);
pw.println();
pw.println(comment(AppResources.translate("configurationFile.comment")));
pw.println();
pw.println(comment(AppResources.translate("configurationFile.modify")));
pw.println();
pw.println(comment(AppResources.translate("configurationFile.meta")));
pw.println("[meta]");
pw.println();
Calendar generatedCalendarValue = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssXXX");
sdf.setTimeZone(generatedCalendarValue.getTimeZone());
String generatedValue = sdf.format(generatedCalendarValue.getTime());
pw.println(comment(AppResources.translate("configurationFile.meta.saveDate")));
pw.println("saveDate = " + generatedValue);
pw.println();
pw.println(comment(AppResources.translate("configurationFile.meta.appVersion")));
pw.println("appVersion = \"" + ApplicationInfo.version + "\"");
pw.println();
pw.println(comment(AppResources.translate("configurationFile.meta.showComments")));
pw.println("showComments = " + (showComments ? "true" : "false") + "");
pw.println();
pw.println(comment(AppResources.translate("configurationFile.meta.modifiedOnly")));
pw.println("modifiedOnly = " + (modifiedOnly ? "true" : "false") + "");
pw.println();
pw.println(comment(AppResources.translate("configurationFile.configuration")));
pw.println("[configuration]");
pw.println();
for (Map.Entry<String, Field> entry : Configuration.getConfigurationFields(false, true).entrySet()) {
try {
String name = entry.getKey();
Field field = entry.getValue();
ConfigurationItem item = (ConfigurationItem) field.get(null);
ConfigurationName nameAnnotation = field.getAnnotation(ConfigurationName.class);
if (nameAnnotation != null) {
name = nameAnnotation.value();
}
String key = name;
if (key.contains(".")) {
key = "\"" + key + "\"";
}
if (!item.hasValue && modifiedOnly) {
continue;
}
String title = Configuration.getConfigurationTitle(name);
String description = Configuration.getConfigurationDescription(name);
if (showComments) {
if (title != null && !title.isEmpty()) {
pw.println("# " + title.replace("\n", "\n# "));
}
if (description != null && !description.isEmpty()) {
List<String> descriptionLines = wordWrap(description, 80 - 4);
boolean first = true;
for (String descriptionLine : descriptionLines) {
pw.println("#" + (first ? " - " : " ") + descriptionLine);
first = false;
}
}
pw.println("#");
}
Object value = item.get();
Object defaultValue = Configuration.getDefaultValue(field);
String savedValue = null;
String savedDefaultValue = null;
StringBuilder sb = new StringBuilder();
boolean first = true;
String valueType = null;
if (value == null) {
savedValue = "";
} else {
switch (name) {
case "fontPairingMap":
@SuppressWarnings("unchecked") HashMap<String, String> fontPairingMap = (HashMap<String, String>) value;
sb.append("{");
for (String fontKey : fontPairingMap.keySet()) {
if (!first) {
sb.append(", ");
}
sb.append("\"");
sb.append(Helper.escapeJavaString(fontKey));
sb.append("\" = \"");
sb.append(Helper.escapeJavaString(fontPairingMap.get(fontKey)));
sb.append("\"");
first = false;
}
sb.append("}");
break;
case "swfSpecificConfigs":
@SuppressWarnings("unchecked") HashMap<String, SwfSpecificConfiguration> swfSpecificConfigs = (HashMap<String, SwfSpecificConfiguration>) value;
sb.append("{");
for (String swfKey : swfSpecificConfigs.keySet()) {
if (!first) {
sb.append(", ");
}
sb.append("\"");
sb.append(Helper.escapeJavaString(swfKey));
sb.append("\" = {");
SwfSpecificConfiguration swfSpecificConf = swfSpecificConfigs.get(swfKey);
sb.append("fontPairingMap = {");
boolean first2 = true;
for (String fontKey : swfSpecificConf.fontPairingMap.keySet()) {
if (!first2) {
sb.append(", ");
}
sb.append("\"");
sb.append(Helper.escapeJavaString(fontKey));
sb.append("\" = \"");
sb.append(Helper.escapeJavaString(swfSpecificConf.fontPairingMap.get(fontKey)));
sb.append("\"");
first2 = false;
}
sb.append("}, lastSelectedPath = \"");
if (swfSpecificConf.lastSelectedPath != null) {
sb.append(Helper.escapeJavaString(swfSpecificConf.lastSelectedPath));
}
sb.append("\"");
sb.append("}");
first = false;
}
sb.append("}");
savedValue = sb.toString();
break;
case "swfSpecificCustomConfigs":
@SuppressWarnings("unchecked") HashMap<String, SwfSpecificCustomConfiguration> swfSpecificCustomConfigs = (HashMap<String, SwfSpecificCustomConfiguration>) value;
sb.append("{");
for (String swfKey : swfSpecificCustomConfigs.keySet()) {
if (!first) {
sb.append(", ");
}
sb.append("\"");
sb.append(Helper.escapeJavaString(swfKey));
sb.append("\" = {");
SwfSpecificCustomConfiguration swfSpecificCustomConf = swfSpecificCustomConfigs.get(swfKey);
boolean first2 = true;
for (String customKey : swfSpecificCustomConf.getAllCustomData().keySet()) {
if (!first2) {
sb.append(", ");
}
sb.append("\"");
sb.append(Helper.escapeJavaString(customKey));
sb.append("\" = \"");
sb.append(Helper.escapeJavaString(swfSpecificCustomConf.getAllCustomData().get(customKey)));
sb.append("\"");
first2 = false;
}
sb.append("}");
first = false;
}
sb.append("}");
savedValue = sb.toString();
break;
default:
Type type = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
if (type instanceof Class) {
switch (((Class) type).getSimpleName()) {
case "Boolean":
Boolean booleanValue = (Boolean) value;
savedValue = booleanValue == Boolean.TRUE ? "true" : "false";
savedDefaultValue = defaultValue == Boolean.TRUE ? "true" : "false";
valueType = "Boolean";
break;
case "Calendar":
Calendar calendarValue = (Calendar) value;
sdf.setTimeZone(calendarValue.getTimeZone());
savedValue = sdf.format(calendarValue.getTime());
if (defaultValue != null) {
savedDefaultValue = sdf.format(((Calendar) defaultValue).getTime());
}
valueType = "Calendar";
break;
case "Color":
Color colorValue = (Color) value;
savedValue = "\"" + new RGB(colorValue).toHexRGB() + "\"";
if (defaultValue != null) {
savedDefaultValue = "\"" + new RGB((Color) defaultValue).toHexRGB() + "\"";
}
valueType = "Color";
break;
case "Double":
savedValue = "" + value;
if (defaultValue != null) {
savedDefaultValue = "" + defaultValue;
}
valueType = "Double";
break;
case "Integer":
savedValue = "" + value;
if (defaultValue != null) {
savedDefaultValue = "" + defaultValue;
}
valueType = "Integer";
break;
case "String":
String stringValue = value.toString();
if (stringValue.contains("\\") && !stringValue.matches("^.*[\b\t\n\f\r\"'\\x00-\\x08\\x1A-\\x1F\\x7F].*$")) {
savedValue = "'" + stringValue + "'";
} else {
savedValue = "\"" + Helper.escapeJavaString(stringValue) + "\"";
}
if (defaultValue != null) {
stringValue = defaultValue.toString();
if (stringValue.contains("\\") && !stringValue.matches("^.*[\b\t\n\f\r\"'\\x00-\\x08\\x1A-\\x1F\\x7F].*$")) {
savedDefaultValue = "'" + stringValue + "'";
} else {
savedDefaultValue = "\"" + Helper.escapeJavaString(stringValue) + "\"";
}
}
valueType = "String";
break;
default:
String stringOtherValue = value.toString();
savedValue = "\"" + Helper.escapeJavaString(stringOtherValue) + "\"";
if (defaultValue != null) {
savedDefaultValue = "" + "\"" + Helper.escapeJavaString(defaultValue.toString()) + "\"";
}
break;
}
}
}
}
if (showComments && valueType != null) {
pw.println("# " + AppResources.translate("valueType") + " " + AppResources.translate("valueType." + valueType));
}
Type type = ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0];
if (showComments && type instanceof Class) {
Class c = (Class) type;
if (c.isEnum()) {
@SuppressWarnings("unchecked")
Class<? extends Enum<?>> enumType = (Class<? extends Enum<?>>) type;
Enum<?>[] values = enumType.getEnumConstants();
sb = new StringBuilder();
first = true;
for (Enum<?> enumValue : values) {
if (!first) {
sb.append(", ");
}
sb.append("\"");
sb.append(enumValue.toString());
sb.append("\"");
first = false;
}
pw.println("# " + AppResources.translate("valueType") + " " + enumType.getSimpleName());
pw.println("# " + AppResources.translate("possibleValues") + " " + sb.toString());
}
}
if (showComments && savedDefaultValue != null) {
pw.println("# " + AppResources.translate("defaultValue") + " " + savedDefaultValue);
}
ConfigurationRemoved removed = field.getAnnotation(ConfigurationRemoved.class);
if (showComments && removed != null) {
pw.println("# " + AppResources.translate("configuration.removed"));
}
if (showComments) {
pw.println();
}
if (!item.hasValue || savedValue.isEmpty()) {
pw.print("# ");
}
pw.print(key + " = ");
if (item.hasValue) {
pw.println(savedValue);
} else {
pw.println(savedDefaultValue);
}
if (showComments) {
pw.println();
}
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(Configuration.class.getName()).log(Level.SEVERE, null, ex);
}
}
} catch (IOException ex) {
Logger.getLogger(TomlConfigurationStorage.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

View File

@@ -41,3 +41,23 @@ error.swf.invalid = Invalid SWF file, wrong signature.
error.swf.headerTooShort = SWF header is too short.
error.abc.invalid = Invalid ABC file.
error.swf.decryptionProblem = Invalid SWF file, decryption failed.
#after 23.0.1
defaultValue = Default value:
possibleValues = Possible values:
valueType = Value type:
valueType.Double = Floating point
valueType.Boolean = true/false
valueType.Calendar = DateTime
valueType.Color = Color
valueType.Integer = Integer
valueType.String = String
configurationFile = Configuration file of %app%
configurationFile.comment = Line starting with hash is a comment
configurationFile.modify = WARNING: This file is overwritten on every application exit. If you make changes to values, make sure FFDec is not running.
configurationFile.meta = Section - Meta info of how configuration is stored
configurationFile.meta.saveDate = When this file was last modified by the app
configurationFile.meta.appVersion = Last version of tha app that modified this file
configurationFile.meta.showComments = Show configuration comments - set to true (and exit app again to resave) to show configuration titles and descriptions.
configurationFile.meta.modifiedOnly = Store modified items only in this file - set to false (and exit app again to resave) to show all.
configurationFile.configuration = Section - Actual configuration
configuration.removed = WARNING: This configuration was REMOVED. It is unused.

View File

@@ -41,4 +41,24 @@ error.swf.invalid = Neplatn\u00fd SWF soubor, \u0161patn\u00e1 signatura.
error.swf.headerTooShort = SWF hlavi\u010dka je p\u0159\u00edli\u0161 kr\u00e1tk\u00e1.
error.abc.invalid = Neplatn\u00fd ABC soubor.
#after 18.4.1
error.swf.decryptionProblem = Neplatn\u00fd SWF soubor, selhalo de\u0161ifrov\u00e1n\u00ed.
error.swf.decryptionProblem = Neplatn\u00fd SWF soubor, selhalo de\u0161ifrov\u00e1n\u00ed.
#after 23.0.1
defaultValue = V\u00fdchoz\u00ed hodnota:
possibleValues = Mo\u017en\u00e9 hodnoty:
valueType = Typ hodnoty:
valueType.Double = Desetinn\u00e9 \u010d\u00edslo
valueType.Boolean = true/false
valueType.Calendar = Datum + \u010das
valueType.Color = Barva
valueType.Integer = Cel\u00e9 \u010d\u00edslo
valueType.String = \u0158et\u011bzec
configurationFile = Konfigura\u010dn\u00ed soubor programu %app%
configurationFile.comment = \u0158\u00e1dek za\u010d\u00ednaj\u00edc\u00ed na m\u0159\u00ed\u017eku je koment\u00e1\u0159
configurationFile.modify = VAROV\u00c1N\u00cd: Tento soubor je p\u0159episov\u00e1n p\u0159i ka\u017ed\u00e9m ukon\u010den\u00ed aplikace. Pokud prov\u00e1d\u00edte zm\u011bny hodnot, ujist\u011bte se, \u017ee aplikace neb\u011b\u017e\u00ed.
configurationFile.meta = Sekce - Metainformace o tom, jak je konfigurace ulo\u017een\u00e1
configurationFile.meta.saveDate = Kdy byl tento soubor naposledy upraven aplikac\u00ed
configurationFile.meta.appVersion = Posledn\u00ed verze aplikace, kter\u00e1 tento soubor upravila
configurationFile.meta.showComments = Zobrazit koment\u00e1\u0159e ke konfiguraci - nastavte to na true (a ukon\u010dete aplikaci pro nov\u00e9 ulo\u017een\u00ed) pro zobrazen\u00ed n\u00e1zv\u016f a popis\u016f konfigurace.
configurationFile.meta.modifiedOnly = Ukl\u00e1dat do tohoto souboru pouze zm\u011bn\u011bn\u00e9 hodnoty - nastavte na false (a ukon\u010dete aplikaci pro nov\u00e9 ulo\u017een\u00ed) pro zobrazen\u00ed v\u0161eho.
configurationFile.configuration = Sekce - Vlastn\u00ed konfigurace
configuration.removed = VAROV\u00c1N\u00cd: Tato konfigurace byla ODSTRAN\u011aNA. Nepou\u017e\u00edv\u00e1 se.