summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--library/config.cpp231
-rw-r--r--library/config.h6
2 files changed, 168 insertions, 69 deletions
diff --git a/library/config.cpp b/library/config.cpp
index 61ff089..bdfcb3f 100644
--- a/library/config.cpp
+++ b/library/config.cpp
@@ -25,44 +25,92 @@
25#endif 25#endif
26#include <qtextstream.h> 26#include <qtextstream.h>
27 27
28#include <sys/stat.h> 28#include <sys/stat.h>
29#include <sys/types.h> 29#include <sys/types.h>
30#include <fcntl.h> 30#include <fcntl.h>
31#include <stdlib.h> 31#include <stdlib.h>
32#include <unistd.h> 32#include <unistd.h>
33 33
34#define QTOPIA_INTERNAL_LANGLIST 34#define QTOPIA_INTERNAL_LANGLIST
35#include "config.h" 35#include "config.h"
36#include "global.h" 36#include "global.h"
37#include "qpeapplication.h"
37 38
38 39
40/*
41 * Internal Class
42 */
43class ConfigPrivate {
44public:
45 ConfigPrivate() : multilang(FALSE) {}
46 ConfigPrivate(const ConfigPrivate& o) :
47 trfile(o.trfile),
48 trcontext(o.trcontext),
49 multilang(o.multilang)
50 {}
51 ConfigPrivate& operator=(const ConfigPrivate& o)
52 {
53 trfile = o.trfile;
54 trcontext = o.trcontext;
55 multilang = o.multilang;
56 return *this;
57 }
58
59 QString trfile;
60 QCString trcontext;
61 bool multilang;
62};
63
64/////////////////////////////////////////////////////////////////
65/////////////////////////////////////////////////////////////////
66
39/*! 67/*!
40 \internal 68 \internal
41*/ 69*/
42QString Config::configFilename(const QString& name, Domain d) 70QString Config::configFilename(const QString& name, Domain d)
43{ 71{
44 switch (d) { 72 switch (d) {
45 case File: 73 case File:
46 return name; 74 return name;
47 case User: { 75 case User: {
48 QDir dir = (QString(getenv("HOME")) + "/Settings"); 76 QDir dir = (QString(getenv("HOME")) + "/Settings");
49 if ( !dir.exists() ) 77 if ( !dir.exists() )
50 mkdir(dir.path().local8Bit(),0700); 78 mkdir(dir.path().local8Bit(),0700);
51 return dir.path() + "/" + name + ".conf"; 79 return dir.path() + "/" + name + ".conf";
52 } 80 }
53 } 81 }
54 return name; 82 return name;
55} 83}
56 84
85/* This cannot be made public because of binary compat issues */
86void Config::read( QTextStream &s )
87{
88#if QT_VERSION <= 230 && defined(QT_NO_CODECS)
89 // The below should work, but doesn't in Qt 2.3.0
90 s.setCodec( QTextCodec::codecForMib( 106 ) );
91#else
92 s.setEncoding( QTextStream::UnicodeUTF8 );
93#endif
94
95 QStringList list = QStringList::split('\n', s.read() );
96
97 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
98 if ( !parse( *it ) ) {
99 git = groups.end();
100 return;
101 }
102 }
103}
104
57/*! 105/*!
58 \class Config config.h 106 \class Config config.h
59 \brief The Config class provides for saving application cofniguration state. 107 \brief The Config class provides for saving application cofniguration state.
60 108
61 You should keep a Config in existence only while you do not want others 109 You should keep a Config in existence only while you do not want others
62 to be able to change the state. There is no locking currently, but there 110 to be able to change the state. There is no locking currently, but there
63 may be in the future. 111 may be in the future.
64*/ 112*/
65 113
66/*! 114/*!
67 \enum Config::ConfigGroup 115 \enum Config::ConfigGroup
68 \internal 116 \internal
@@ -85,59 +133,66 @@ QString Config::configFilename(const QString& name, Domain d)
85 133
86 In the default Domain, \e User, 134 In the default Domain, \e User,
87 the configuration is user-specific. \a name should not contain "/" in 135 the configuration is user-specific. \a name should not contain "/" in
88 this case, and in general should be the name of the C++ class that is 136 this case, and in general should be the name of the C++ class that is
89 primarily responsible for maintaining the configuration. 137 primarily responsible for maintaining the configuration.
90 138
91 In the File Domain, \a name is an absolute filename. 139 In the File Domain, \a name is an absolute filename.
92*/ 140*/
93Config::Config( const QString &name, Domain domain ) 141Config::Config( const QString &name, Domain domain )
94 : filename( configFilename(name,domain) ) 142 : filename( configFilename(name,domain) )
95{ 143{
96 git = groups.end(); 144 git = groups.end();
145 d = 0;
97 read(); 146 read();
98 QStringList l = Global::languageList();
99 lang = l[0];
100 glang = l[1];
101} 147}
102 148
103 149
104// Sharp ROM compatibility 150// Sharp ROM compatibility
105Config::Config ( const QString &name, bool what ) 151Config::Config ( const QString &name, bool what )
106 : filename( configFilename(name,what ? User : File) ) 152 : filename( configFilename(name,what ? User : File) )
107{ 153{
108 git = groups.end(); 154 git = groups.end();
155 d = 0;
109 read(); 156 read();
110 QStringList l = Global::languageList();
111 lang = l[0];
112 glang = l[1];
113} 157}
114 158
115/*! 159/*!
116 Writes any changes to disk and destroys the in-memory object. 160 Writes any changes to disk and destroys the in-memory object.
117*/ 161*/
118Config::~Config() 162Config::~Config()
119{ 163{
120 if ( changed ) 164 if ( changed )
121 write(); 165 write();
166
167 delete d;
122} 168}
123 169
124/*! 170/*!
125 Returns whether the current group has an entry called \a key. 171 Returns whether the current group has an entry called \a key.
126*/ 172*/
127bool Config::hasKey( const QString &key ) const 173bool Config::hasKey( const QString &key ) const
128{ 174{
129 if ( groups.end() == git ) 175 if ( groups.end() == git )
130 return FALSE; 176 return FALSE;
131 ConfigGroup::ConstIterator it = ( *git ).find( key ); 177 ConfigGroup::ConstIterator it = ( *git ).find( key );
178 if ( it == ( *git ).end() ) {
179 if ( d && !d->trcontext.isNull() ) {
180 it = ( *git ).find( key + "[]" );
181 } else if ( d && d->multilang ) {
182 it = ( *git ).find( key + "["+lang+"]" );
183 if ( it == ( *git ).end() && !glang.isEmpty() )
184 it = ( *git ).find( key + "["+glang+"]" );
185 }
186 }
132 return it != ( *git ).end(); 187 return it != ( *git ).end();
133} 188}
134 189
135/*! 190/*!
136 Sets the current group for subsequent reading and writing of 191 Sets the current group for subsequent reading and writing of
137 entries to \a gname. Grouping allows the application to partition the namespace. 192 entries to \a gname. Grouping allows the application to partition the namespace.
138 193
139 This function must be called prior to any reading or writing 194 This function must be called prior to any reading or writing
140 of entries. 195 of entries.
141 196
142 The \a gname must not be empty. 197 The \a gname must not be empty.
143*/ 198*/
@@ -300,66 +355,83 @@ void Config::removeEntry( const QString &key )
300/*! 355/*!
301 \fn bool Config::operator == ( const Config & other ) const 356 \fn bool Config::operator == ( const Config & other ) const
302 357
303 Tests for equality with \a other. Config objects are equal if they refer to the same filename. 358 Tests for equality with \a other. Config objects are equal if they refer to the same filename.
304*/ 359*/
305 360
306/*! 361/*!
307 \fn bool Config::operator != ( const Config & other ) const 362 \fn bool Config::operator != ( const Config & other ) const
308 363
309 Tests for inequality with \a other. Config objects are equal if they refer to the same filename. 364 Tests for inequality with \a other. Config objects are equal if they refer to the same filename.
310*/ 365*/
311 366
367
312/*! 368/*!
313 \fn QString Config::readEntry( const QString &key, const QString &deflt ) const 369 \fn QString Config::readEntry( const QString &key, const QString &deflt ) const
314 370
315 Reads a string entry stored with \a key, defaulting to \a deflt if there is no entry. 371 Reads a string entry stored with \a key, defaulting to \a deflt if there is no entry.
316*/ 372*/
317 373
374/*
375 * ### !LocalTranslator::translate was kept out!
376 *
377 */
378
318/*! 379/*!
319 \internal 380 \internal
320 For compatibility, non-const version. 381 For compatibility, non-const version.
321*/ 382*/
322QString Config::readEntry( const QString &key, const QString &deflt ) 383QString Config::readEntry( const QString &key, const QString &deflt )
323{ 384{
324 QString res = readEntryDirect( key+"["+lang+"]" ); 385 QString r;
325 if ( !res.isNull() ) 386 if ( d && !d->trcontext.isNull() ) {
326 return res; 387 // Still try untranslated first, becuase:
327 if ( !glang.isEmpty() ) { 388 // 1. It's the common case
328 res = readEntryDirect( key+"["+glang+"]" ); 389 // 2. That way the value can be WRITTEN (becoming untranslated)
329 if ( !res.isNull() ) 390 r = readEntryDirect( key );
330 return res; 391 if ( !r.isNull() )
392 return r;
393 r = readEntryDirect( key + "[]" );
394 if ( !r.isNull() )
395 return qApp->translate(d->trfile,d->trcontext,r);
396 } else if ( d && d->multilang ) {
397 // For compatibilitity
398 r = readEntryDirect( key + "["+lang+"]" );
399 if ( !r.isNull() )
400 return r;
401 if ( !glang.isEmpty() ) {
402 r = readEntryDirect( key + "["+glang+"]" );
403 if ( !r.isNull() )
404 return r;
405 }
331 } 406 }
332 return readEntryDirect( key, deflt ); 407 r = readEntryDirect( key, deflt );
408 return r;
333} 409}
334 410
335/*! 411/*!
336 \fn QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const 412 \fn QString Config::readEntryCrypt( const QString &key, const QString &deflt ) const
337 413
338 Reads an encrypted string entry stored with \a key, defaulting to \a deflt if there is no entry. 414 Reads an encrypted string entry stored with \a key, defaulting to \a deflt if there is no entry.
339*/ 415*/
340 416
341/*! 417/*!
342 \internal 418 \internal
343 For compatibility, non-const version. 419 For compatibility, non-const version.
344*/ 420*/
345QString Config::readEntryCrypt( const QString &key, const QString &deflt ) 421QString Config::readEntryCrypt( const QString &key, const QString &deflt )
346{ 422{
347 QString res = readEntryDirect( key+"["+lang+"]" ); 423 QString res = readEntry( key );
348 if ( res.isNull() && glang.isEmpty() )
349 res = readEntryDirect( key+"["+glang+"]" );
350 if ( res.isNull() )
351 res = readEntryDirect( key, QString::null );
352 if ( res.isNull() ) 424 if ( res.isNull() )
353 return deflt; 425 return deflt;
354 return decipher(res); 426 return decipher(res);
355} 427}
356 428
357/*! 429/*!
358 \fn QString Config::readEntryDirect( const QString &key, const QString &deflt ) const 430 \fn QString Config::readEntryDirect( const QString &key, const QString &deflt ) const
359 \internal 431 \internal
360*/ 432*/
361 433
362/*! 434/*!
363 \internal 435 \internal
364 For compatibility, non-const version. 436 For compatibility, non-const version.
365*/ 437*/
@@ -480,110 +552,135 @@ void Config::write( const QString &fn )
480 QMessageBox::critical( 0, QObject::tr("Out of Space"), 552 QMessageBox::critical( 0, QObject::tr("Out of Space"),
481 QObject::tr("There was a problem creating\nConfiguration Information \nfor this program.\n\nPlease free up some space and\ntry again.") ); 553 QObject::tr("There was a problem creating\nConfiguration Information \nfor this program.\n\nPlease free up some space and\ntry again.") );
482 f.close(); 554 f.close();
483 QFile::remove( strNewFile ); 555 QFile::remove( strNewFile );
484 return; 556 return;
485 } 557 }
486 558
487 f.close(); 559 f.close();
488 // now rename the file... 560 // now rename the file...
489 if ( rename( strNewFile, filename ) < 0 ) { 561 if ( rename( strNewFile, filename ) < 0 ) {
490 qWarning( "problem renaming the file %s to %s", strNewFile.latin1(), 562 qWarning( "problem renaming the file %s to %s", strNewFile.latin1(),
491 filename.latin1() ); 563 filename.latin1() );
492 QFile::remove( strNewFile ); 564 QFile::remove( strNewFile );
565 return;
493 } 566 }
567
568 changed = FALSE;
494} 569}
495 570
496/*! 571/*!
497 Returns whether the Config is in a valid state. 572 Returns whether the Config is in a valid state.
498*/ 573*/
499bool Config::isValid() const 574bool Config::isValid() const
500{ 575{
501 return groups.end() != git; 576 return groups.end() != git;
502} 577}
503 578
504/*! 579/*!
505 \internal 580 \internal
506*/ 581*/
507void Config::read() 582void Config::read()
508{ 583{
509 changed = FALSE; 584 changed = FALSE;
510 585
511 if ( !QFileInfo( filename ).exists() ) { 586 QString readFilename(filename);
512 git = groups.end(); 587
513 return; 588 if ( !QFile::exists(filename) ) {
589 bool failed = TRUE;
590 QFileInfo fi(filename);
591 QString settingsDir = QDir::homeDirPath() + "/Settings";
592 if (fi.dirPath(TRUE) == settingsDir) {
593 // User setting - see if there is a default in $OPIEDIR/etc/default/
594 QString dftlFile = QPEApplication::qpeDir() + "etc/default/" + fi.fileName();
595 if (QFile::exists(dftlFile)) {
596 readFilename = dftlFile;
597 failed = FALSE;
598 }
599 }
600 if (failed) {
601 git = groups.end();
602 return;
603 }
514 } 604 }
515 605
516 QFile f( filename ); 606
607 QFile f( readFilename );
517 if ( !f.open( IO_ReadOnly ) ) { 608 if ( !f.open( IO_ReadOnly ) ) {
518 git = groups.end(); 609 git = groups.end();
519 return; 610 return;
520 } 611 }
521 612
522 613 if (f.getch()!='[') {
523 // hack to avoid problems if big files are passed to test
524 // if they are valid configs ( like passing a mp3 ... )
525 // I just hope that there are no conf files > 100000 byte
526 // not the best solution, find something else later
527 if ( f.getch()!='[' ||f.size() > 100000 ) {
528 git = groups.end(); 614 git = groups.end();
529 return; 615 return;
530 } 616 }
531 f.ungetch('['); 617 f.ungetch('[');
532 618
533
534 QTextStream s( &f ); 619 QTextStream s( &f );
535#if QT_VERSION <= 230 && defined(QT_NO_CODECS) 620 read( s );
536 // The below should work, but doesn't in Qt 2.3.0
537 s.setCodec( QTextCodec::codecForMib( 106 ) );
538#else
539 s.setEncoding( QTextStream::UnicodeUTF8 );
540#endif
541
542 QStringList list = QStringList::split('\n', s.read() );
543 f.close(); 621 f.close();
544
545 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
546 if ( !parse( *it ) ) {
547 git = groups.end();
548 return;
549 }
550 }
551} 622}
552 623
553/*! 624/*!
554 \internal 625 \internal
555*/ 626*/
556bool Config::parse( const QString &l ) 627bool Config::parse( const QString &l )
557{ 628{
558 QString line = l.stripWhiteSpace(); 629 QString line = l.stripWhiteSpace();
559
560 if ( line [0] == QChar ( '#' ))
561 return true; // ignore comments
562
563 if ( line[ 0 ] == QChar( '[' ) ) { 630 if ( line[ 0 ] == QChar( '[' ) ) {
564 QString gname = line; 631 QString gname = line;
565 gname = gname.remove( 0, 1 ); 632 gname = gname.remove( 0, 1 );
566 if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) ) 633 if ( gname[ (int)gname.length() - 1 ] == QChar( ']' ) )
567 gname = gname.remove( gname.length() - 1, 1 ); 634 gname = gname.remove( gname.length() - 1, 1 );
568 git = groups.insert( gname, ConfigGroup() ); 635 git = groups.insert( gname, ConfigGroup() );
569 } else if ( !line.isEmpty() ) { 636 } else if ( !line.isEmpty() ) {
570 if ( git == groups.end() ) 637 if ( git == groups.end() )
571 return FALSE; 638 return FALSE;
572 int eq = line.find( '=' ); 639 int eq = line.find( '=' );
573 if ( eq == -1 ) 640 if ( eq == -1 )
574 return FALSE; 641 return FALSE;
575 QString key = line.left(eq).stripWhiteSpace(); 642 QString key = line.left(eq).stripWhiteSpace();
576 QString value = line.mid(eq+1).stripWhiteSpace(); 643 QString value = line.mid(eq+1).stripWhiteSpace();
577 ( *git ).insert( key, value ); 644
645 if ( git.key() == "Translation" ) {
646 if ( key == "File" ) {
647 if ( !d )
648 d = new ConfigPrivate;
649 d->trfile = value;
650 } else if ( key == "Context" ) {
651 if ( !d )
652 d = new ConfigPrivate;
653 d->trcontext = value.latin1();
654 } else if ( key.startsWith("Comment") ) {
655 return TRUE; // ignore comment for ts file
656 } else {
657 return FALSE; // Unrecognized
658 }
659 }
660
661 int kl = key.length();
662 if ( kl > 1 && key[kl-1] == ']' && key[kl-2] != '[' ) {
663 // Old-style translation (inefficient)
664 if ( !d )
665 d = new ConfigPrivate;
666 if ( !d->multilang ) {
667 QStringList l = Global::languageList();
668 lang = l[0];
669 glang = l[1];
670 d->multilang = TRUE;
671 }
672 }
673
674 ( *git ).insert( key, value );
578 } 675 }
579 return TRUE; 676 return TRUE;
580} 677}
581 678
582 679
583 680
584bool Config::hasGroup( const QString& name )const { 681bool Config::hasGroup( const QString& name )const {
585 return ( groups. find ( name ) != groups. end ( )); 682 return ( groups. find ( name ) != groups. end ( ));
586}; 683};
587 684
588QStringList Config::groupList()const { 685QStringList Config::groupList()const {
589 QStringList sl; 686 QStringList sl;
diff --git a/library/config.h b/library/config.h
index 29ba0d6..f8d3bf7 100644
--- a/library/config.h
+++ b/library/config.h
@@ -22,24 +22,25 @@
22#define CONFIG_H 22#define CONFIG_H
23 23
24// ##### could use QSettings with Qt 3.0 24// ##### could use QSettings with Qt 3.0
25 25
26#include <qpe/qpeglobal.h> 26#include <qpe/qpeglobal.h>
27 27
28#include <qmap.h> 28#include <qmap.h>
29#include <qstringlist.h> 29#include <qstringlist.h>
30 30
31typedef QMap< QString, QString > ConfigGroup; 31typedef QMap< QString, QString > ConfigGroup;
32typedef QMap< QString, ConfigGroup> ConfigGroupMap; 32typedef QMap< QString, ConfigGroup> ConfigGroupMap;
33 33
34class QTextStream;
34class ConfigPrivate; 35class ConfigPrivate;
35class Config 36class Config
36{ 37{
37public: 38public:
38 39
39 enum Domain { File, User }; 40 enum Domain { File, User };
40 Config( const QString &name, Domain domain=User ); 41 Config( const QString &name, Domain domain=User );
41 ~Config(); 42 ~Config();
42 43
43 QTOPIA_MERGED_METHOD(static long timeStamp( const QString &name, Domain domain=User ), "2.1"); 44 QTOPIA_MERGED_METHOD(static long timeStamp( const QString &name, Domain domain=User ), "2.1");
44 45
45 bool operator == ( const Config & other ) const { return (filename == other.filename); } 46 bool operator == ( const Config & other ) const { return (filename == other.filename); }
@@ -83,26 +84,27 @@ public:
83 84
84 void clearGroup(); 85 void clearGroup();
85 QTOPIA_MERGED_METHOD(void removeGroup(), "2.1.0"); 86 QTOPIA_MERGED_METHOD(void removeGroup(), "2.1.0");
86 QTOPIA_MERGED_METHOD(void removeGroup(const QString&), "2.1.0"); 87 QTOPIA_MERGED_METHOD(void removeGroup(const QString&), "2.1.0");
87 QTOPIA_MERGED_METHOD(QStringList allGroups() const, "2.1.0"); 88 QTOPIA_MERGED_METHOD(QStringList allGroups() const, "2.1.0");
88 89
89 void write( const QString &fn = QString::null ); 90 void write( const QString &fn = QString::null );
90 91
91protected: 92protected:
92 void read(); 93 void read();
93 bool parse( const QString &line ); 94 bool parse( const QString &line );
94 95
95 QMap< QString, ConfigGroup > groups; 96 ConfigGroupMap groups;
96 QMap< QString, ConfigGroup >::Iterator git; 97 ConfigGroupMap::Iterator git;
97 QString filename; 98 QString filename;
98 QString lang; 99 QString lang;
99 QString glang; 100 QString glang;
100 bool changed; 101 bool changed;
101 ConfigPrivate *d; 102 ConfigPrivate *d;
102 static QString configFilename(const QString& name, Domain); 103 static QString configFilename(const QString& name, Domain);
103 104
104private: // Sharp ROM compatibility 105private: // Sharp ROM compatibility
105 Config( const QString &name, bool what ); 106 Config( const QString &name, bool what );
107 void read( QTextStream &s);
106}; 108};
107 109
108#endif 110#endif