compile
[duncan/yast2-qt4.git] / src / QY2Settings.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                          contributed Qt classes                      |
10 |                                                    (C) SuSE Linux AG |
11 \----------------------------------------------------------------------/
12
13   File:       QY2Settings.cpp
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17   This is a pure Qt class - it can be used independently of YaST2.
18
19 /-*/
20
21
22
23 #include "QY2Settings.h"
24
25 #include <QFile>
26 #include <QRegExp>
27
28 #include <iostream>
29
30 using std::cout;
31 using std::cerr;
32 using std::endl;
33
34
35 QY2Settings::QY2Settings( const QString & fileName, AccessMode accessMode )
36     : _fileName( fileName )
37     , _accessMode( accessMode )
38 {
39     if ( _accessMode == ReadOnly || _accessMode == ReadWrite )
40         load();
41     else
42         initSections();
43 }
44
45 void QY2Settings::initSections()
46 {
47     _defaultSection = new Section( "" );
48     Q_CHECK_PTR( _defaultSection );
49
50     _currentSection = _defaultSection;
51     _sections.insert( "", _defaultSection );
52 }
53
54
55
56 QY2Settings::~QY2Settings()
57 {
58     if ( _dirty && _accessMode != ReadOnly )
59         save();
60 }
61
62
63 bool QY2Settings::selectSection( const QString & sectionName )
64 {
65     _currentSection = _sections[ sectionName ];
66
67     if ( _currentSection )
68     {
69         return true;
70     }
71     else
72     {
73         _currentSection = _defaultSection;
74         return false;
75     }
76 }
77
78
79 void QY2Settings::selectDefaultSection()
80 {
81     _currentSection = _defaultSection;
82 }
83
84
85 QStringList QY2Settings::sections( bool includeUnnamed ) const
86 {
87     QStringList sectionList;
88     SectionIterator it( _sections );
89
90     while ( it.hasNext() )
91     {
92         QString sectionName = (it.value())->name();
93
94         if ( includeUnnamed || ! sectionName.isEmpty() )
95             sectionList.append( sectionName );
96
97         it.next();
98     }
99
100     return sectionList;
101 }
102
103
104 QString QY2Settings::get( const QString & key, const QString & fallback ) const
105 {
106     // Can't use operator[] here since we have a pointer
107
108     Section::const_iterator it = _currentSection->find( key );
109
110     if ( it == _currentSection->constEnd() )
111         return fallback;
112
113     return it.value();
114 }
115
116
117 QString QY2Settings::operator[] ( const QString & key )
118 {
119     return get( key );
120 }
121
122
123 bool QY2Settings::hasKey( const QString & key )
124 {
125     return _currentSection->contains( key );
126 }
127
128
129 QStringList QY2Settings::keys() const
130 {
131     QStringList keyList;
132
133     for ( Section::const_iterator it = _currentSection->constBegin();
134           it != _currentSection->constEnd();
135           ++it )
136     {
137         keyList.append( it.key() );
138     }
139
140     return keyList;
141 }
142
143
144 bool QY2Settings::load()
145 {
146     initSections();
147     _readError = false;
148     
149     if ( _accessMode == WriteOnly )
150         return false;
151
152     
153     QFile file( _fileName );
154
155     if ( ! file.open( QIODevice::ReadOnly ) )
156     {
157         cerr << "Can't load settings from " << qPrintable(_fileName)
158              << ": " << qPrintable(file.errorString())
159              << endl;
160         
161         _readError = true;
162         
163         return false;
164     }
165     
166     QTextStream str( &file );
167     str.setAutoDetectUnicode(true);
168     QString line;
169     int lineCount = 0;
170
171     while ( ! file.atEnd() )
172     {
173         line = str.readLine().trimmed();
174         lineCount++;
175         
176         
177         // Skip empty lines
178         
179         if ( line.isEmpty() ) continue;
180
181         
182         // Skip comment lines
183
184         if ( line.startsWith( "#"  ) ) continue;
185         if ( line.startsWith( ";"  ) ) continue;
186         if ( line.startsWith( "//" ) ) continue;
187
188
189         if ( line.startsWith( "[" ) )
190         {
191             // New section
192
193             line.replace( QRegExp( "^\\[\\s*" ), "" );
194             line.replace( QRegExp( "\\s*\\].*$" ), "" );
195             addSection( line );
196         }
197         else if ( line.contains( "=" ) )
198         {
199             // key=value pair
200
201             QString key   = line.section( "=", 0, 0 ).trimmed();
202             QString value = line.section( "=", 1, 1 ).trimmed();
203
204             value.replace( QRegExp( "^\"" ), "" );      // strip leading "
205             value.replace( QRegExp( "\"$" ), "" );      // strip trailing "
206             value.replace( "\\\"", "\"" );              // un-escape "
207
208             // qDebug( "Read %s=%s", (const char *) key, (const char *) value );
209             set( key, value );
210         }
211         else
212         {
213             qWarning( "%s:%d: Syntax error: %s",
214                       qPrintable( _fileName), lineCount, qPrintable(line) );
215         }
216     }
217
218     _dirty = false;
219
220     return true;
221 }
222
223
224 bool QY2Settings::save()
225 {
226     if ( _accessMode == ReadOnly )
227         return false;
228
229     QFile file( _fileName );
230
231     if ( ! file.open( QIODevice::WriteOnly ) )
232     {
233         cerr << "Can't save settings to " << qPrintable(_fileName)
234              << ": " << qPrintable(file.errorString())
235              << endl;
236         
237         return false;
238     }
239     
240     QTextStream str( &file );
241     str.setAutoDetectUnicode(true);
242
243     // The default section must be saved first since it doesn't have a section
244     // name that could be used for a headline
245     saveSection( str, _defaultSection );
246     
247     SectionIterator sectIt( _sections );
248     
249     while ( sectIt.hasNext() )
250     {
251         if ( sectIt.value() != _defaultSection )
252             saveSection( str, sectIt.value() );
253             sectIt.next();
254     }
255
256     _dirty = false;
257
258     return true;
259 }
260
261
262 void QY2Settings::saveSection( QTextStream & str, Section * sect )
263 {
264     // Section header
265
266     if ( ! sect->name().isEmpty() )
267         str << "[" << sect->name() << "]" << endl;
268
269     // value=key pairs for this section
270
271     for ( Section::iterator it = sect->begin();
272           it != sect->end();
273           ++it )
274     {
275         QString value = it.value();
276         value.replace( "\"", "\\\"" );  // Escape embedded " with \"
277
278         str << it.key() << "= \"" << value << "\"" << endl;
279     }
280
281     str << endl;
282 }
283
284
285 void QY2Settings::set( const QString & key, const QString & value )
286 {
287     _currentSection->insert( key, value );
288     _dirty = true;
289 }
290
291
292 void QY2Settings::addSection( const QString & sectionName )
293 {
294     _currentSection = _sections[ sectionName ]; // already there?
295
296     if ( _currentSection )                      // -> use it
297         return;
298
299     _currentSection = new Section( sectionName );
300     Q_CHECK_PTR( _currentSection );
301
302     _sections.insert( sectionName, _currentSection );
303     _dirty = true;
304 }
305
306
307 void QY2Settings::clearSection()
308 {
309     _currentSection->clear();
310     _dirty = true;
311 }
312
313