Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-studio / tags / synfigstudio_0_61_06 / 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 //! Compare two key names, putting pref.* keys first
133 static bool
134 compare_pref_first (synfig::String first, synfig::String second)
135 {
136         return  first.substr(0, 5) == "pref."
137                         ?       second.substr(0, 5) == "pref."
138                                 ?       first < second
139                                 :       true
140                         :       second.substr(0, 5) == "pref."
141                                 ?       false
142                                 :       first < second;
143 }
144
145 Settings::KeyList
146 Settings::get_key_list()const
147 {
148         KeyList key_list;
149
150         // Get keys from the domains
151         {
152                 DomainMap::const_iterator iter;
153                 for(iter=domain_map.begin();iter!=domain_map.end();++iter)
154                 {
155                         KeyList sub_key_list(iter->second->get_key_list());
156                         KeyList::iterator key_iter;
157                         for(key_iter=sub_key_list.begin();key_iter!=sub_key_list.end();++key_iter)
158                                 key_list.push_back(iter->first+'.'+*key_iter);
159                 }
160         }
161
162         // Get keys from the simple variables
163         {
164                 ValueBaseMap::const_iterator iter;
165                 for(iter=simple_value_map.begin();iter!=simple_value_map.end();++iter)
166                         key_list.push_back(iter->first);
167         }
168
169         // Sort the keys
170         // We make sure the 'pref.*' keys come first to fix bug 1694393,
171         // where windows were being created before the parameter
172         // specifying which window manager hint to use had been loaded
173         key_list.sort(compare_pref_first);
174
175         return key_list;
176 }
177
178 bool
179 Settings::save_to_file(const synfig::String& filename)const
180 {
181         synfig::String tmp_filename(filename+".TMP");
182
183         try
184         {
185                 std::ofstream file(tmp_filename.c_str());
186
187                 if(!file)return false;
188
189                 KeyList key_list(get_key_list());
190
191                 // Save the keys
192                 {
193                         KeyList::const_iterator iter;
194                         for(iter=key_list.begin();iter!=key_list.end();++iter)
195                         {
196                                 if(!file)return false;
197                                 file<<*iter<<'='<<get_value(*iter)<<endl;
198                         }
199                 }
200
201                 if(!file)
202                         return false;
203         }catch(...) { return false; }
204
205 #ifdef _WIN32
206         char old_file[80]="sif.XXXXXXXX";
207         mktemp(old_file);
208         rename(filename.c_str(),old_file);
209         if(rename(tmp_filename.c_str(),filename.c_str())!=0)
210         {
211                 rename(old_file,tmp_filename.c_str());
212                 return false;
213         }
214         remove(old_file);
215 #else
216         if(rename(tmp_filename.c_str(),filename.c_str())!=0)
217                 return false;
218 #endif
219
220         return true;
221 }
222
223 bool
224 Settings::load_from_file(const synfig::String& filename)
225 {
226         std::ifstream file(filename.c_str());
227         if(!file)
228                 return false;
229         while(file)
230         {
231                 std::string line;
232                 getline(file,line);
233                 if(!line.empty() && ((line[0]>='a' && line[0]<='z')||(line[0]>='A' && line[0]<='Z')))
234                 {
235                         std::string::iterator equal(find(line.begin(),line.end(),'='));
236                         if(equal==line.end())
237                                 continue;
238                         std::string key(line.begin(),equal);
239                         std::string value(equal+1,line.end());
240
241                         //synfig::info("Settings::load_from_file(): Trying Key \"%s\" with a value of \"%s\".",key.c_str(),value.c_str());
242                         try{
243                         if(!set_value(key,value))
244                                 synfig::warning("Settings::load_from_file(): Key \"%s\" with a value of \"%s\" was rejected.",key.c_str(),value.c_str());
245                         }
246                         catch(...)
247                         {
248                                 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());
249                                 throw;
250                         }
251                 }
252         }
253         return true;
254 }