001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.util;
020:
021: import java.awt.Color;
022: import java.awt.Dimension;
023: import java.awt.Font;
024: import java.awt.Point;
025: import java.awt.Rectangle;
026: import java.io.File;
027: import java.io.FileInputStream;
028: import java.io.FileOutputStream;
029: import java.io.IOException;
030: import java.net.MalformedURLException;
031: import java.net.URL;
032: import java.security.AccessControlException;
033: import java.util.ArrayList;
034: import java.util.Map;
035: import java.util.Properties;
036: import java.util.StringTokenizer;
037:
038: /**
039: * This class allows to manage users preferences.
040: * <p>
041: * Here is a short usage example:
042: * <p>
043: * <blockquote><pre>
044: * // at application intialization
045: * HashMap defaults = new HashMap();
046: * defaults.put("windowSize", new Dimension(640, 480));
047: * defaults.put("antialias", Boolean.TRUE);
048: * PreferenceManager prefs = new PreferenceManager("application.ini", defaults);
049: * try {
050: * prefs.load();
051: * } catch (IOException e) {
052: * //
053: * }
054: * myApplication.setSize(prefs.getDimension("windowSize"));
055: * myApplication.setAntialiasingOn(prefs.getBoolean("antialias"));
056: *
057: * // later a dialog box may customize preferences
058: * myApplication.setAntialiasingOn(antialiasCheckBox.getState());
059: * prefs.setBoolean("antialias", antialiasCheckBox.getState());
060: *
061: * // when leaving the application we need to save the preferences
062: * prefs.setDimension("windowSize", myApplication.getSize());
063: * prefs.setFiles("history", lastVisitedFileArray);
064: * try {
065: * prefs.save()
066: * } catch (IOException e) {
067: * //
068: * }
069: * </pre></blockquote>
070: * <p>
071: * @author <a href="mailto:cjolif@ilog.fr">Christophe Jolif</a>
072: * @version $Id: PreferenceManager.java 478169 2006-11-22 14:23:24Z dvholten $
073: */
074: public class PreferenceManager {
075: protected Properties internal = null;
076: protected Map defaults = null;
077: protected String prefFileName = null;
078: protected String fullName = null;
079:
080: protected static final String USER_HOME = getSystemProperty("user.home");
081: protected static final String USER_DIR = getSystemProperty("user.dir");
082: protected static final String FILE_SEP = getSystemProperty("file.separator");
083:
084: private static String PREF_DIR = null;
085:
086: /**
087: * Gets a System property if accessible. Returns an empty string
088: * otherwise
089: */
090: protected static String getSystemProperty(String prop) {
091: try {
092: return System.getProperty(prop);
093: } catch (AccessControlException e) {
094: return "";
095: }
096: }
097:
098: /**
099: * Creates a preference manager.
100: * @param prefFileName the name of the preference file.
101: */
102: public PreferenceManager(String prefFileName) {
103: this (prefFileName, null);
104: }
105:
106: /**
107: * Creates a preference manager with a default values
108: * initialization map.
109: * @param prefFileName the name of the preference file.
110: * @param defaults where to get defaults value if the value is
111: * not specified in the file.
112: */
113: public PreferenceManager(String prefFileName, Map defaults) {
114: this .prefFileName = prefFileName;
115: this .defaults = defaults;
116: internal = new Properties();
117: }
118:
119: /**
120: * Sets a <code>String</code> representing the directory
121: * where <code>PreferenceManager</code> instances should look
122: * for preferences files. The default value is <code>null</code>
123: * which means the automatic mechanism for looking for preferences
124: * is used.
125: * @see #load
126: */
127: public static void setPreferenceDirectory(String dir) {
128: PREF_DIR = dir;
129: }
130:
131: /**
132: * Returns a <code>String</code> representing the directory
133: * where <code>PreferenceManager</code> instances should look
134: * for preferences.
135: * @see #load
136: * @see #setPreferenceDirectory
137: */
138: public static String getPreferenceDirectory() {
139: return PREF_DIR;
140: }
141:
142: /**
143: * Loads the preference file. If the file has already been previously
144: * sucessfuly loaded or saved, it will first try to reaload it from
145: * this location. Otherwise, it will try to find the file
146: * in the following order: in the directory set by
147: * {@link #setPreferenceDirectory} if it exists, in the user
148: * home directory and then in the current user directory.
149: * @exception IOException if an error occured when reading the file.
150: * @see #save
151: */
152: public void load() throws IOException {
153: FileInputStream fis = null;
154: if (fullName != null)
155: try {
156: fis = new FileInputStream(fullName);
157: } catch (IOException e1) {
158: fullName = null;
159: }
160: if (fullName == null) {
161: if (PREF_DIR != null) {
162: try {
163: fis = new FileInputStream(fullName = PREF_DIR
164: + FILE_SEP + prefFileName);
165: } catch (IOException e2) {
166: fullName = null;
167: }
168: }
169: if (fullName == null) {
170: try {
171: fis = new FileInputStream(fullName = USER_HOME
172: + FILE_SEP + prefFileName);
173: } catch (IOException e3) {
174: try {
175: fis = new FileInputStream(fullName = USER_DIR
176: + FILE_SEP + prefFileName);
177: } catch (IOException e4) {
178: fullName = null;
179: }
180: }
181: }
182: }
183: if (fullName != null) {
184: try {
185: internal.load(fis);
186: } finally {
187: fis.close();
188: }
189: }
190: }
191:
192: /**
193: * Saves the preference file. If it has previously sucessfuly been
194: * loaded or save it will save it at the same location. In other cases
195: * it will save it in the directory set by {@link #setPreferenceDirectory}
196: * if has been set and exists, otherwise in the user home directory.
197: * @exception IOException if an error occured when writing the file or
198: * if is impossible to write the file at all available locations.
199: * @see #load
200: */
201: public void save() throws IOException {
202: FileOutputStream fos = null;
203: if (fullName != null)
204: try {
205: fos = new FileOutputStream(fullName);
206: } catch (IOException e1) {
207: fullName = null;
208: }
209: if (fullName == null) {
210: if (PREF_DIR != null) {
211: try {
212: fos = new FileOutputStream(fullName = PREF_DIR
213: + FILE_SEP + prefFileName);
214: } catch (IOException e2) {
215: fullName = null;
216: }
217: }
218: if (fullName == null) {
219: try {
220: fos = new FileOutputStream(fullName = USER_HOME
221: + FILE_SEP + prefFileName);
222: } catch (IOException e3) {
223: fullName = null;
224: throw e3;
225: }
226: }
227: }
228: try {
229: internal.store(fos, prefFileName);
230: } finally {
231: fos.close();
232: }
233: }
234:
235: private Object getDefault(String key) {
236: if (defaults != null)
237: return defaults.get(key);
238: else
239: return null;
240: }
241:
242: /**
243: * Returns a Rectangle preference.
244: */
245: public Rectangle getRectangle(String key) {
246: Rectangle defaultValue = (Rectangle) getDefault(key);
247: String sp = internal.getProperty(key);
248: if (sp == null) {
249: return defaultValue;
250: }
251: Rectangle result = new Rectangle();
252: try {
253: int x, y, w, h;
254: String token;
255: StringTokenizer st = new StringTokenizer(sp, " ", false);
256: if (!st.hasMoreTokens()) {
257: // the value is not correctly formated => remove it
258: internal.remove(key);
259: return defaultValue;
260: }
261: token = st.nextToken();
262: x = Integer.parseInt(token);
263: if (!st.hasMoreTokens()) {
264: internal.remove(key);
265: return defaultValue;
266: }
267: token = st.nextToken();
268: y = Integer.parseInt(token);
269: if (!st.hasMoreTokens()) {
270: internal.remove(key);
271: return defaultValue;
272: }
273: token = st.nextToken();
274: w = Integer.parseInt(token);
275: if (!st.hasMoreTokens()) {
276: internal.remove(key);
277: return defaultValue;
278: }
279: token = st.nextToken();
280: h = Integer.parseInt(token);
281: result.setBounds(x, y, w, h);
282: return result;
283: } catch (NumberFormatException e) {
284: internal.remove(key);
285: return defaultValue;
286: }
287: }
288:
289: /**
290: * Returns a Dimension preference.
291: */
292: public Dimension getDimension(String key) {
293: Dimension defaultValue = (Dimension) getDefault(key);
294: String sp = internal.getProperty(key);
295: if (sp == null)
296: return defaultValue;
297: Dimension result = new Dimension();
298: try {
299: int w, h;
300: String token;
301: StringTokenizer st = new StringTokenizer(sp, " ", false);
302: if (!st.hasMoreTokens()) {
303: // the value is not correctly formated => remove it
304: internal.remove(key);
305: return defaultValue;
306: }
307: token = st.nextToken();
308: w = Integer.parseInt(token);
309: if (!st.hasMoreTokens()) {
310: internal.remove(key);
311: return defaultValue;
312: }
313: token = st.nextToken();
314: h = Integer.parseInt(token);
315: result.setSize(w, h);
316: return result;
317: } catch (NumberFormatException e) {
318: internal.remove(key);
319: return defaultValue;
320: }
321: }
322:
323: /**
324: * Returns a point preference.
325: */
326: public Point getPoint(String key) {
327: Point defaultValue = (Point) getDefault(key);
328: String sp = internal.getProperty(key);
329: if (sp == null) {
330: return defaultValue;
331: }
332: Point result = new Point();
333: try {
334: int x, y;
335: String token;
336: StringTokenizer st = new StringTokenizer(sp, " ", false);
337: if (!st.hasMoreTokens()) {
338: // the value is not correctly formated => remove it
339: internal.remove(key);
340: return defaultValue;
341: }
342: token = st.nextToken();
343: x = Integer.parseInt(token);
344: if (!st.hasMoreTokens()) {
345: internal.remove(key);
346: return defaultValue;
347: }
348: token = st.nextToken();
349: y = Integer.parseInt(token);
350: if (!st.hasMoreTokens()) {
351: internal.remove(key);
352: return defaultValue;
353: }
354: result.setLocation(x, y);
355: return result;
356: } catch (NumberFormatException e) {
357: internal.remove(key);
358: return defaultValue;
359: }
360: }
361:
362: /**
363: * Retruns a Color preference.
364: */
365: public Color getColor(String key) {
366: Color defaultValue = (Color) getDefault(key);
367: String sp = internal.getProperty(key);
368: if (sp == null) {
369: return defaultValue;
370: }
371: try {
372: int r, g, b, a;
373: String token;
374: StringTokenizer st = new StringTokenizer(sp, " ", false);
375: if (!st.hasMoreTokens()) {
376: // the value is not correctly formated => remove it
377: internal.remove(key);
378: return defaultValue;
379: }
380: token = st.nextToken();
381: r = Integer.parseInt(token);
382: if (!st.hasMoreTokens()) {
383: internal.remove(key);
384: return defaultValue;
385: }
386: token = st.nextToken();
387: g = Integer.parseInt(token);
388: if (!st.hasMoreTokens()) {
389: internal.remove(key);
390: return defaultValue;
391: }
392: token = st.nextToken();
393: b = Integer.parseInt(token);
394: if (!st.hasMoreTokens()) {
395: internal.remove(key);
396: return defaultValue;
397: }
398: token = st.nextToken();
399: a = Integer.parseInt(token);
400: return new Color(r, g, b, a);
401: } catch (NumberFormatException e) {
402: internal.remove(key);
403: return defaultValue;
404: }
405: }
406:
407: /**
408: * Returns a font preference.
409: */
410: public Font getFont(String key) {
411: Font defaultValue = (Font) getDefault(key);
412: String sp = internal.getProperty(key);
413: if (sp == null) {
414: return defaultValue;
415: }
416: try {
417: int size, type;
418: String name;
419: String token;
420: StringTokenizer st = new StringTokenizer(sp, " ", false);
421: if (!st.hasMoreTokens()) {
422: // the value is not correctly formated => remove it
423: internal.remove(key);
424: return defaultValue;
425: }
426: name = st.nextToken();
427: if (!st.hasMoreTokens()) {
428: internal.remove(key);
429: return defaultValue;
430: }
431: token = st.nextToken();
432: size = Integer.parseInt(token);
433: if (!st.hasMoreTokens()) {
434: internal.remove(key);
435: return defaultValue;
436: }
437: token = st.nextToken();
438: type = Integer.parseInt(token);
439: return new Font(name, type, size);
440: } catch (NumberFormatException e) {
441: internal.remove(key);
442: return defaultValue;
443: }
444:
445: }
446:
447: /**
448: * Returns a String preference.
449: */
450: public String getString(String key) {
451: String sp = internal.getProperty(key);
452: if (sp == null) {
453: sp = (String) getDefault(key);
454: }
455: return sp;
456: }
457:
458: /**
459: * Returns an array of String preference.
460: */
461: public String[] getStrings(String mkey) {
462: String last;
463: int i = 0;
464: ArrayList v = new ArrayList();
465: while (true) {
466: last = getString(mkey + i);
467: i++;
468: if (last == null)
469: break;
470: v.add(last);
471: }
472: if (v.size() != 0) {
473: String[] str = new String[v.size()];
474: return (String[]) v.toArray(str);
475: } else {
476: return (String[]) getDefault(mkey);
477: }
478: }
479:
480: /**
481: * Returns an URL preference.
482: */
483: public URL getURL(String key) {
484: URL defaultValue = (URL) getDefault(key);
485: String sp = internal.getProperty(key);
486: if (sp == null) {
487: return defaultValue;
488: }
489: URL url = null;
490: try {
491: url = new URL(sp);
492: } catch (MalformedURLException ex) {
493: internal.remove(key);
494: return defaultValue;
495: }
496: return url;
497: }
498:
499: /**
500: * Returns an array of URLs preference.
501: */
502: public URL[] getURLs(String mkey) {
503: URL last;
504: int i = 0;
505: ArrayList v = new ArrayList();
506: while (true) {
507: last = getURL(mkey + i);
508: i++;
509: if (last == null)
510: break;
511: v.add(last);
512: }
513: if (v.size() != 0) {
514: URL[] path = new URL[v.size()];
515: return (URL[]) v.toArray(path);
516: } else {
517: return (URL[]) getDefault(mkey);
518: }
519: }
520:
521: /**
522: * Returns a File preference.
523: */
524: public File getFile(String key) {
525: File defaultValue = (File) getDefault(key);
526: String sp = internal.getProperty(key);
527: if (sp == null) {
528: return defaultValue;
529: }
530: File file = new File(sp);
531: if (file.exists())
532: return file;
533: else {
534: internal.remove(key);
535: return defaultValue;
536: }
537: }
538:
539: /**
540: * Returns an array of Files preference.
541: */
542: public File[] getFiles(String mkey) {
543: File last;
544: int i = 0;
545: ArrayList v = new ArrayList();
546: while (true) {
547: last = getFile(mkey + i);
548: i++;
549: if (last == null)
550: break;
551: v.add(last);
552: }
553: if (v.size() != 0) {
554: File[] path = new File[v.size()];
555: return (File[]) v.toArray(path);
556: } else {
557: return (File[]) getDefault(mkey);
558: }
559: }
560:
561: /**
562: * Gets an int preference.
563: */
564: public int getInteger(String key) {
565: int defaultValue = 0;
566: if (getDefault(key) != null)
567: defaultValue = ((Integer) getDefault(key)).intValue();
568: String sp = internal.getProperty(key);
569: if (sp == null) {
570: return defaultValue;
571: }
572: int value;
573: try {
574: value = Integer.parseInt(sp);
575: } catch (NumberFormatException ex) {
576: internal.remove(key);
577: return defaultValue;
578: }
579: return value;
580: }
581:
582: /**
583: * Gets a float preference.
584: */
585: public float getFloat(String key) {
586: float defaultValue = 0;
587: if (getDefault(key) != null)
588: defaultValue = ((Float) getDefault(key)).floatValue();
589: String sp = internal.getProperty(key);
590: if (sp == null) {
591: return defaultValue;
592: }
593: float value;
594: try {
595: value = Float.parseFloat(sp);
596: } catch (NumberFormatException ex) {
597: setFloat(key, defaultValue);
598: return defaultValue;
599: }
600: return value;
601: }
602:
603: /**
604: * Gets a boolean preference. If not found and no default returns false.
605: */
606: public boolean getBoolean(String key) {
607: if (internal.getProperty(key) != null)
608: return internal.getProperty(key).equals("true");
609: else if (getDefault(key) != null)
610: return ((Boolean) getDefault(key)).booleanValue();
611: else
612: return false;
613: }
614:
615: /**
616: * Sets a Rectangle preference. If null removes it.
617: */
618: public void setRectangle(String key, Rectangle value) {
619: if (value != null && !value.equals(getDefault(key)))
620: internal.setProperty(key, value.x + " " + value.y + " "
621: + value.width + ' ' + value.height);
622: else
623: internal.remove(key);
624: }
625:
626: /**
627: * Sets a Dimension preference. If null removes it.
628: */
629: public void setDimension(String key, Dimension value) {
630: if (value != null && !value.equals(getDefault(key)))
631: internal.setProperty(key, value.width + " " + value.height);
632: else
633: internal.remove(key);
634: }
635:
636: /**
637: * Sets a Point preference. If null removes it.
638: */
639: public void setPoint(String key, Point value) {
640: if (value != null && !value.equals(getDefault(key)))
641: internal.setProperty(key, value.x + " " + value.y);
642: else
643: internal.remove(key);
644: }
645:
646: /**
647: * Sets a Color preference. If null removes it.
648: */
649: public void setColor(String key, Color value) {
650: if (value != null && !value.equals(getDefault(key)))
651: internal.setProperty(key, value.getRed() + " "
652: + value.getGreen() + " " + value.getBlue() + " "
653: + value.getAlpha());
654: else
655: internal.remove(key);
656: }
657:
658: /**
659: * Sets a Font preference. If null removes it.
660: */
661: public void setFont(String key, Font value) {
662: if (value != null && !value.equals(getDefault(key)))
663: internal.setProperty(key, value.getName() + " "
664: + value.getSize() + " " + value.getStyle());
665: else
666: internal.remove(key);
667: }
668:
669: /**
670: * Sets a String preference. If null removes it.
671: */
672: public void setString(String key, String value) {
673: if (value != null && !value.equals(getDefault(key)))
674: internal.setProperty(key, value);
675: else
676: internal.remove(key);
677: }
678:
679: /**
680: * Sets a String array preference. If null or size null removes
681: * previous preference.
682: */
683: public void setStrings(String mkey, String[] values) {
684: int j = 0;
685: if (values != null)
686: for (int i = 0; i < values.length; i++) {
687: if (values[i] != null) {
688: setString(mkey + j, values[i]);
689: j++;
690: }
691: }
692: // erase other elements
693: String last;
694: while (true) {
695: last = getString(mkey + j);
696: if (last == null)
697: break;
698: setString(mkey + j, null);
699: j++;
700: }
701: }
702:
703: /**
704: * Sets an URL property. If null removes it.
705: */
706: public void setURL(String key, URL value) {
707: if (value != null && !value.equals(getDefault(key)))
708: internal.setProperty(key, value.toString());
709: else
710: internal.remove(key);
711: }
712:
713: /**
714: * Sets an array of URLs property. If null or size null removes
715: * previous preference.
716: */
717: public void setURLs(String mkey, URL[] values) {
718: int j = 0;
719: if (values != null)
720: for (int i = 0; i < values.length; i++) {
721: if (values[i] != null) {
722: setURL(mkey + j, values[i]);
723: j++;
724: }
725: }
726: // erase other elements
727: String last;
728: while (true) {
729: last = getString(mkey + j);
730: if (last == null)
731: break;
732: setString(mkey + j, null);
733: j++;
734: }
735: }
736:
737: /**
738: * Sets a File property. If null removes it.
739: */
740: public void setFile(String key, File value) {
741: if (value != null && !value.equals(getDefault(key)))
742: internal.setProperty(key, value.getAbsolutePath());
743: else
744: internal.remove(key);
745: }
746:
747: /**
748: * Sets an array of Files property. If null or size null removes
749: * previous preference.
750: */
751: public void setFiles(String mkey, File[] values) {
752: int j = 0;
753: if (values != null)
754: for (int i = 0; i < values.length; i++) {
755: if (values[i] != null) {
756: setFile(mkey + j, values[i]);
757: j++;
758: }
759: }
760: // erase other elements
761: String last;
762: while (true) {
763: last = getString(mkey + j);
764: if (last == null)
765: break;
766: setString(mkey + j, null);
767: j++;
768: }
769: }
770:
771: /**
772: * Sets an int property.
773: */
774: public void setInteger(String key, int value) {
775: if (getDefault(key) != null
776: && ((Integer) getDefault(key)).intValue() != value)
777: internal.setProperty(key, Integer.toString(value));
778: else
779: internal.remove(key);
780: }
781:
782: /**
783: * Sets a float property.
784: */
785: public void setFloat(String key, float value) {
786: if (getDefault(key) != null
787: && ((Float) getDefault(key)).floatValue() != value)
788: internal.setProperty(key, Float.toString(value));
789: else
790: internal.remove(key);
791: }
792:
793: /**
794: * Sets a boolean property.
795: */
796: public void setBoolean(String key, boolean value) {
797: if (getDefault(key) != null
798: && ((Boolean) getDefault(key)).booleanValue() != value) {
799: internal.setProperty(key, value ? "true" : "false");
800: } else {
801: internal.remove(key);
802: }
803: }
804: }
|