Skip to content

Commit a8d342a

Browse files
committed
delegate app.Preferences storage to utils.Preferences
app keeps fonts/colors, dialogs, and proxy/native-chooser side effects in their original startup order; loading and saving now go through the standalone class, with the settings folder passed in from Base.
1 parent e924d99 commit a8d342a

1 file changed

Lines changed: 36 additions & 210 deletions

File tree

‎app/src/processing/app/Preferences.java‎

Lines changed: 36 additions & 210 deletions
Original file line numberDiff line numberDiff line change
@@ -23,62 +23,34 @@
2323

2424
import processing.app.ui.Toolkit;
2525
import processing.core.PApplet;
26-
import processing.core.PConstants;
2726

28-
import java.awt.*;
29-
import java.io.*;
30-
import java.util.HashMap;
31-
import java.util.Map;
27+
import java.awt.Color;
28+
import java.awt.Font;
29+
import java.awt.SystemColor;
30+
import java.io.IOException;
31+
import java.io.InputStream;
3232

3333

3434
/**
35-
* Storage class for user preferences and environment settings.
36-
* <P>
37-
* This class does not use the Properties class because .properties files use
38-
* ISO 8859-1 encoding, which is highly likely to be a problem when trying to
39-
* save sketch folders and locations. Like the rest of Processing, we use UTF8.
40-
* <p>
41-
* We don't use the Java Preferences API because it would entail writing to
42-
* the registry (on Windows), or an obscure file location (on Mac OS X) and
43-
* make it far more difficult (impossible) to remove the preferences.txt to
44-
* reset them (when they become corrupt), or to find the the file to make
45-
* edits for numerous obscure preferences that are not part of the preferences
46-
* window. If we added a generic editor (e.g. about:config in Mozilla) for
47-
* such things, we could start using the Java Preferences API. But wow, that
48-
* sounds like a lot of work. Not unlike writing this paragraph.
35+
* The app-facing side of the preferences. The actual storage (loading and
36+
* saving preferences.txt, the bundled defaults, platform-specific keys)
37+
* lives in the standalone {@link processing.utils.Preferences}; this class
38+
* delegates to it and keeps the pieces that only make sense inside the
39+
* full application: fonts and colors, error dialogs, and environment
40+
* side effects like proxies and the native file chooser.
4941
*/
5042
public class Preferences {
51-
// had to rename the defaults file because people were editing it
52-
static final String DEFAULTS_FILE = "defaults.txt"; //$NON-NLS-1$
53-
static final String PREFS_FILE = "preferences.txt"; //$NON-NLS-1$
5443

55-
static Map<String, String> defaults;
56-
static Map<String, String> table = new HashMap<>();
57-
static File preferencesFile;
58-
private static boolean initialized = false;
59-
60-
61-
// /** @return true if the sketchbook file did not exist */
62-
// static public boolean init() {
6344
static public void init() {
64-
initialized = true;
6545
// start by loading the defaults, in case something
6646
// important was deleted from the user prefs
6747
try {
68-
var defaultsStream = Preferences
69-
.class
70-
.getClassLoader()
71-
.getResourceAsStream(DEFAULTS_FILE);
72-
load(defaultsStream);
73-
} catch (Exception e) {
48+
processing.utils.Preferences.loadDefaults();
49+
} catch (IOException e) {
7450
Messages.showError(null, "Could not read default settings.\n" +
7551
"You'll need to reinstall Processing.", e);
7652
}
7753

78-
// Clone the defaults, then override any them with the user's preferences.
79-
// This ensures that any new/added preference will be present.
80-
defaults = new HashMap<>(table);
81-
8254
// other things that have to be set explicitly for the defaults
8355
setColor("run.window.bgcolor", SystemColor.control); //$NON-NLS-1$
8456

@@ -87,32 +59,15 @@ static public void init() {
8759
setBoolean("editor.input_method_support", true);
8860
}
8961

90-
91-
// next load user preferences file
92-
preferencesFile = Base.getSettingsFile(PREFS_FILE);
93-
var preferencesFileOverride = System.getProperty("processing.app.preferences.file");
94-
if (preferencesFileOverride != null && !preferencesFileOverride.isEmpty()) {
95-
preferencesFile = new File(preferencesFileOverride);
96-
}
97-
boolean firstRun = !preferencesFile.exists();
98-
if (!firstRun) {
99-
try {
100-
load(new FileInputStream(preferencesFile));
101-
102-
} catch (Exception ex) {
103-
Messages.showError("Error reading preferences",
104-
"Error reading the preferences file. " +
105-
"Please delete (or move)\n" +
106-
preferencesFile.getAbsolutePath() +
107-
" and restart Processing.", ex);
108-
}
109-
}
110-
111-
if (checkSketchbookPref() || firstRun) {
112-
// if (firstRun) {
113-
// create a new preferences file if none exists
114-
// saves the defaults out to the file
115-
save();
62+
// next load user preferences file over the defaults
63+
try {
64+
processing.utils.Preferences.loadUserPrefs(Base.getSettingsFolder());
65+
} catch (IOException ex) {
66+
Messages.showError("Error reading preferences",
67+
"Error reading the preferences file. " +
68+
"Please delete (or move)\n" +
69+
processing.utils.Preferences.getPreferencesPath() +
70+
" and restart Processing.", ex);
11671
}
11772

11873
PApplet.useNativeSelect =
@@ -140,15 +95,15 @@ static public void init() {
14095
* For testing, pretend to load preferences without a real file.
14196
*/
14297
static public void skipInit() {
143-
initialized = true;
98+
processing.utils.Preferences.skipInit();
14499
}
145100

146101
/**
147102
* Check whether Preferences.init() has been called. If not, we are probably not running the full application.
148103
* @return true if Preferences has been initialized
149104
*/
150105
static public boolean isInitialized() {
151-
return initialized;
106+
return processing.utils.Preferences.isInitialized();
152107
}
153108

154109

@@ -165,120 +120,24 @@ static void handleProxy(String protocol, String hostProp, String portProp) {
165120

166121

167122
static public String getPreferencesPath() {
168-
return preferencesFile.getAbsolutePath();
123+
return processing.utils.Preferences.getPreferencesPath();
169124
}
170125

171126

172127
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
173128

174129

175-
/**
176-
* Load a set of key/value pairs from a UTF-8 encoded file into 'table'.
177-
* For 3.0a6, this removes any platform-specific extensions from keys, so
178-
* that we don't have platform-specific entries in a user's preferences.txt
179-
* file, which would require all prefs to be changed twice, or risk being
180-
* overwritten by the unchanged platform-specific version on reload.
181-
*/
182130
static public void load(InputStream input) throws IOException {
183-
HashMap<String, String> platformSpecific = new HashMap<>();
184-
185-
String[] lines = PApplet.loadStrings(input); // Reads as UTF-8
186-
for (String line : lines) {
187-
if ((line.isEmpty()) ||
188-
(line.charAt(0) == '#')) continue;
189-
190-
line = line.replace("\\", "/"); // normalize slashes in paths
191-
192-
// this won't properly handle = signs being in the text
193-
int equals = line.indexOf('=');
194-
if (equals != -1) {
195-
String key = line.substring(0, equals).trim();
196-
String value = line.substring(equals + 1).trim();
197-
if (!isPlatformSpecific(key, value, platformSpecific)) {
198-
table.put(key, value);
199-
}
200-
}
201-
}
202-
// Now override the keys with any platform-specific defaults we've found.
203-
for (String key : platformSpecific.keySet()) {
204-
table.put(key, platformSpecific.get(key));
205-
}
131+
processing.utils.Preferences.load(input);
206132
}
207133

208134

209-
/**
210-
* @param key original key (may include platform extension)
211-
* @param value the value that goes with the key
212-
* @param specific where to put the key/value pairs for *this* platform
213-
* @return true if a platform-specific key
214-
*/
215-
static protected boolean isPlatformSpecific(String key, String value,
216-
Map<String, String> specific) {
217-
for (String platform : PConstants.platformNames) {
218-
String ext = "." + platform;
219-
if (key.endsWith(ext)) {
220-
String thisPlatform = PConstants.platformNames[PApplet.platform];
221-
if (platform.equals(thisPlatform)) {
222-
key = key.substring(0, key.lastIndexOf(ext));
223-
// store this for later overrides
224-
specific.put(key, value);
225-
//} else {
226-
// ignore platform-specific defaults for other platforms,
227-
// but return 'true' because it needn't be added to the big list
228-
}
229-
return true;
230-
}
231-
}
232-
return false;
233-
}
234-
235-
236-
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
237-
238-
239135
static public void save() {
240-
// On startup, this is null, but ignore it. It's trying to update the
241-
// prefs for the open sketch before Preferences.init() has been called.
242-
if (preferencesFile != null) {
243-
try {
244-
File dir = preferencesFile.getParentFile();
245-
File preferencesTemp = File.createTempFile("preferences", ".txt", dir);
246-
if (!preferencesTemp.setWritable(true, false)) {
247-
throw new IOException("Could not set " + preferencesTemp + " writable");
248-
}
249-
250-
// Fix for 0163 to properly use Unicode when writing preferences.txt
251-
PrintWriter writer = PApplet.createWriter(preferencesTemp);
252-
253-
String[] keyList = table.keySet().toArray(new String[0]);
254-
// Sorting is really helpful for debugging, diffing, and finding keys
255-
keyList = PApplet.sort(keyList);
256-
for (String key : keyList) {
257-
writer.println(key + "=" + table.get(key)); //$NON-NLS-1$
258-
}
259-
writer.flush();
260-
writer.close();
261-
262-
// Rename preferences.txt to preferences.old
263-
File oldPreferences = new File(dir, "preferences.old");
264-
if (oldPreferences.exists()) {
265-
if (!oldPreferences.delete()) {
266-
throw new IOException("Could not delete preferences.old");
267-
}
268-
}
269-
if (preferencesFile.exists() &&
270-
!preferencesFile.renameTo(oldPreferences)) {
271-
throw new IOException("Could not replace preferences.old");
272-
}
273-
// Make the temporary file into the real preferences
274-
if (!preferencesTemp.renameTo(preferencesFile)) {
275-
throw new IOException("Could not move preferences file into place");
276-
}
277-
278-
} catch (IOException e) {
279-
Messages.showWarning("Preferences",
280-
"Could not save the Preferences file.", e);
281-
}
136+
try {
137+
processing.utils.Preferences.save();
138+
} catch (IOException e) {
139+
Messages.showWarning("Preferences",
140+
"Could not save the Preferences file.", e);
282141
}
283142
}
284143

@@ -289,44 +148,31 @@ static public void save() {
289148
// all the information from preferences.txt
290149

291150
static public String get(String attribute /*, String defaultValue */) {
292-
if (!initialized) {
151+
if (!isInitialized()) {
293152
init();
294153
}
295-
return table.get(attribute);
154+
return processing.utils.Preferences.get(attribute);
296155
}
297156

298157

299158
static public String getDefault(String attribute) {
300-
return defaults.get(attribute);
159+
return processing.utils.Preferences.getDefault(attribute);
301160
}
302161

303162

304163
static public void set(String attribute, String value) {
305-
table.put(attribute, value);
164+
processing.utils.Preferences.set(attribute, value);
306165
}
307166

308167

309168
static public void unset(String attribute) {
310-
table.remove(attribute);
169+
processing.utils.Preferences.unset(attribute);
311170
}
312171

313172

314173
static public boolean getBoolean(String attribute) {
315174
String value = get(attribute); //, null);
316175
return Boolean.parseBoolean(value);
317-
318-
/*
319-
supposedly not needed, because anything besides 'true'
320-
(ignoring case) will just be false.. so if malformed -> false
321-
if (value == null) return defaultValue;
322-
323-
try {
324-
return (new Boolean(value)).booleanValue();
325-
} catch (NumberFormatException e) {
326-
System.err.println("expecting an integer: " + attribute + " = " + value);
327-
}
328-
return defaultValue;
329-
*/
330176
}
331177

332178

@@ -385,26 +231,6 @@ static public Font getFont(String familyAttr, String sizeAttr, int style) {
385231
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
386232

387233

388-
/**
389-
* Check for a 4.0 sketchbook location, and if none exists,
390-
* try to grab it from the 3.0 sketchbook location.
391-
* @return true if a location was found and the pref didn't exist
392-
*/
393-
static protected boolean checkSketchbookPref() {
394-
// If a 4.0 sketchbook location has never been inited
395-
if (getSketchbookPath() == null) {
396-
String threePath = get("sketchbook.path.three"); //$NON-NLS-1$
397-
// If they've run the 3.0 version, start with that location
398-
if (threePath != null) {
399-
setSketchbookPath(threePath);
400-
return true; // save the sketchbook right away
401-
}
402-
// Otherwise it'll be null, and reset properly by Base
403-
}
404-
return false;
405-
}
406-
407-
408234
static public String getOldSketchbookPath() {
409235
return get("sketchbook.path.three"); //$NON-NLS-1$
410236
}

0 commit comments

Comments
 (0)