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