Implements PXEGeek's http://wiki.synfig.com/Wish_list entry: "Optionally display...
[synfig.git] / synfig-studio / trunk / src / synfigapp / settings.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file settings.cpp
3 **      \brief Template File
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 */
21 /* ========================================================================= */
22
23 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 #       include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #       include <config.h>
30 #endif
31
32 #include <fstream>
33 #include <iostream>
34 #include "settings.h"
35 #include <synfig/general.h>
36
37 #endif
38
39 /* === U S I N G =========================================================== */
40
41 using namespace std;
42 using namespace etl;
43 using namespace synfig;
44 using namespace synfigapp;
45
46 /* === M A C R O S ========================================================= */
47
48 /* === G L O B A L S ======================================================= */
49
50 /* === P R O C E D U R E S ================================================= */
51
52 /* === M E T H O D S ======================================================= */
53
54 Settings::Settings()
55 {
56 }
57
58 Settings::~Settings()
59 {
60 }
61
62 synfig::String
63 Settings::get_value(const synfig::String& key)const
64 {
65         synfig::String value;
66         if(!get_value(key,value))
67                 return synfig::String();
68         return value;
69 }
70
71 void
72 Settings::add_domain(Settings* domain, const synfig::String& name)
73 {
74         domain_map[name]=domain;
75 }
76
77 void
78 Settings::remove_domain(const synfig::String& name)
79 {
80         domain_map.erase(name);
81 }
82
83 bool
84 Settings::get_value(const synfig::String& key, synfig::String& value)const
85 {
86         // Search for the value in any children domains
87         DomainMap::const_iterator iter;
88         for(iter=domain_map.begin();iter!=domain_map.end();++iter)
89         {
90                 // if we have a domain hit
91                 if(key.size()>iter->first.size() && String(key.begin(),key.begin()+iter->first.size())==iter->first)
92                 {
93                         synfig::String key_(key.begin()+iter->first.size()+1,key.end());
94
95                         // If the domain has it, then we have got a hit
96                         if(iter->second->get_value(key_,value))
97                                 return true;
98                 }
99         }
100
101         // Search for the value in our simple map
102         if(simple_value_map.count(key))
103         {
104                 value=simple_value_map.find(key)->second;
105                 return true;
106         }
107
108         // key not found
109         return false;
110 }
111
112 bool
113 Settings::set_value(const synfig::String& key,const synfig::String& value)
114 {
115         // Search for the key in any children domains
116         DomainMap::iterator iter;
117         for(iter=domain_map.begin();iter!=domain_map.end();++iter)
118         {
119                 // if we have a domain hit
120                 if(key.size()>iter->first.size() && String(key.begin(),key.begin()+iter->first.size())==iter->first)
121                 {
122                         synfig::String key_(key.begin()+iter->first.size()+1,key.end());
123
124                         return iter->second->set_value(key_,value);
125                 }
126         }
127
128         simple_value_map[key]=value;
129         return true;
130 }
131
132 Settings::KeyList
133 Settings::get_key_list()const
134 {
135         KeyList key_list;
136
137         // Get keys from the domains
138         {
139                 DomainMap::const_iterator iter;
140                 for(iter=domain_map.begin();iter!=domain_map.end();++iter)
141                 {
142                         KeyList sub_key_list(iter->second->get_key_list());
143                         KeyList::iterator key_iter;
144                         for(key_iter=sub_key_list.begin();key_iter!=sub_key_list.end();++key_iter)
145                                 key_list.push_back(iter->first+'.'+*key_iter);
146                 }
147         }
148
149         // Get keys from the simple variables
150         {
151                 ValueBaseMap::const_iterator iter;
152                 for(iter=simple_value_map.begin();iter!=simple_value_map.end();++iter)
153                         key_list.push_back(iter->first);
154         }
155
156         // Sort the keys
157         key_list.sort();
158
159         return key_list;
160 }
161
162 bool
163 Settings::save_to_file(const synfig::String& filename)const
164 {
165         synfig::String tmp_filename(filename+".TMP");
166
167         try
168         {
169                 std::ofstream file(tmp_filename.c_str());
170
171                 if(!file)return false;
172
173                 KeyList key_list(get_key_list());
174
175                 // Save the keys
176                 {
177                         KeyList::const_iterator iter;
178                         for(iter=key_list.begin();iter!=key_list.end();++iter)
179                         {
180                                 if(!file)return false;
181                                 file<<*iter<<'='<<get_value(*iter)<<endl;
182                         }
183                 }
184
185                 if(!file)
186                         return false;
187         }catch(...) { return false; }
188
189 #ifdef _WIN32
190         char old_file[80]="sif.XXXXXXXX";
191         mktemp(old_file);
192         rename(filename.c_str(),old_file);
193         if(rename(tmp_filename.c_str(),filename.c_str())!=0)
194         {
195                 rename(old_file,tmp_filename.c_str());
196                 return false;
197         }
198         remove(old_file);
199 #else
200         if(rename(tmp_filename.c_str(),filename.c_str())!=0)
201                 return false;
202 #endif
203
204         return true;
205 }
206
207 bool
208 Settings::load_from_file(const synfig::String& filename)
209 {
210         std::ifstream file(filename.c_str());
211         if(!file)
212                 return false;
213         while(file)
214         {
215                 std::string line;
216                 getline(file,line);
217                 if(!line.empty() && ((line[0]>='a' && line[0]<='z')||(line[0]>='A' && line[0]<='Z')))
218                 {
219                         std::string::iterator equal(find(line.begin(),line.end(),'='));
220                         if(equal==line.end())
221                                 continue;
222                         std::string key(line.begin(),equal);
223                         std::string value(equal+1,line.end());
224
225                         //synfig::info("Settings::load_from_file(): Trying Key \"%s\" with a value of \"%s\".",key.c_str(),value.c_str());
226                         try{
227                         if(!set_value(key,value))
228                                 synfig::warning("Settings::load_from_file(): Key \"%s\" with a value of \"%s\" was rejected.",key.c_str(),value.c_str());
229                         }
230                         catch(...)
231                         {
232                                 synfig::error("Settings::load_from_file(): Attept to set key \"%s\" with a value of \"%s\" has thrown an exception.",key.c_str(),value.c_str());
233                                 throw;
234                         }
235                 }
236         }
237         return true;
238 }