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