krop's commit fixes my problem in a better way, reverting
[kdepim.git] / korganizer / themeimporter.cpp
blobbdf8d756fd131608b928b7f9215f3d08d7e37efd
1 /*
2 This file is part of KOrganizer.
4 Copyright (c) 2007 Loïc Corbasson <loic.corbasson@gmail.com>
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
22 #include "themeimporter.h"
23 #include "theme.h"
25 #include <KLocale>
27 using namespace KOrg;
29 ThemeImporter::ThemeImporter() : QXmlStreamReader()
33 ThemeImporter::ThemeImporter( QIODevice *device ) : QXmlStreamReader( device )
35 ThemeImporter();
36 read( device );
39 ThemeImporter::~ThemeImporter()
41 qDeleteAll( mPerViewConfigGroups );
42 mPerViewConfigGroups.clear();
45 ///////////////////////////////////////////////////////////////////////////////
47 bool ThemeImporter::read( QIODevice *device )
49 setDevice( device );
51 while ( !atEnd() ) {
52 readNext();
54 if ( isStartElement() ) {
55 if ( name( ) == "korganizer-theme" && attributes().value("version") == "1.0" ) {
56 readThemeXml();
57 } else {
58 raiseError( i18n( "This file is not a KOrganizer theme file." ) );
63 return !error();
66 void ThemeImporter::readThemeXml()
68 Q_ASSERT( isStartElement() && name() == "korganizer-theme" );
70 while ( !atEnd() ) {
71 readNext();
73 if ( isEndElement() ) {
74 break;
77 if ( isStartElement() ) {
78 readElement();
83 ///////////////////////////////////////////////////////////////////////////////
85 void ThemeImporter::readElement( const QString &viewType, const int year,
86 const int month, const int day )
88 if ( name() == "view" ) {
89 readView( viewType, year, month, day );
90 /***** TODO: Date-dependent themes disabled for now ******
91 else if ( name() == "year" || name() == "month" || name() == "day" )
92 readDate( viewType, year, month, day );
95 } else if ( name() == "grid" ) {
96 readGrid( viewType, year, month, day );
97 } else if ( name() == "time-labels" ) {
98 readTimeLabels( viewType, year, month, day );
99 } else if ( name() == "calendar-items" ) {
100 readCalendarItems( viewType, year, month, day );
101 } else if ( name() == "marcus-bains-line" ) {
102 readMarcusBainsLine( viewType, year, month, day );
103 } else if ( name() == "holidays" ) {
104 readHolidays( viewType, year, month, day );
105 } else {
106 readUnknownElement();
110 void ThemeImporter::readDate( const QString &viewType, const int year,
111 const int month, const int day )
113 Q_ASSERT( isStartElement() && ( name() == "year" || name() == "month" || name() == "day" ) );
115 int y = year;
116 int m = month;
117 int d = day;
119 if ( name() == "year" ) {
120 y = attributes().value( "value" ).toString().toInt();
121 } else if ( name() == "month" ) {
122 m = attributes().value( "value" ).toString().toInt();
123 } else if ( name() == "day" ) {
124 d = attributes().value( "value" ).toString().toInt();
127 while ( !atEnd() ) {
128 readNext();
130 if ( isEndElement() ) {
131 break;
134 if ( isStartElement() ) {
135 if ( name() == "year" || name() == "month" || name() == "day" ) {
136 readDate( viewType, y, m, d );
137 } else {
138 readElement( viewType, y, m, d );
144 void ThemeImporter::readView( const QString &viewType, const int year,
145 const int month, const int day )
147 Q_ASSERT( isStartElement() && name() == "view" );
149 QString v = viewType;
150 v = attributes().value( "type" ).toString();
152 while ( !atEnd() ) {
153 readNext();
155 if ( isEndElement() ) {
156 break;
159 if ( isStartElement() ) {
160 readElement( v, year, month, day );
165 void ThemeImporter::readUnknownElement()
167 Q_ASSERT( isStartElement() );
169 kWarning() << "Unknown element found at line" << lineNumber()
170 << ", ending at column" << columnNumber()
171 << ":" << name().toString();
173 while ( !atEnd() ) {
174 readNext();
176 if ( isEndElement() ) {
177 break;
180 if ( isStartElement() ) {
181 readUnknownElement();
186 ///////////////////////////////////////////////////////////////////////////////
188 void ThemeImporter::readCalendarItems( const QString &viewType, const int year,
189 const int month, const int day )
191 Q_ASSERT( isStartElement() && name() == "calendar-items" );
193 // As the available settings are the same for the various calendar items
194 // types, we use a "stack" to keep in mind where we are in the hierarchy
195 // while having the possibility of using the same methods to read the
196 // settings' tags.
197 QList< QPair<QString, QString> > stack;
198 stack.append( qMakePair( QString(), QString( "CalendarItems" ) ) );
200 while ( !atEnd() ) {
201 readNext();
203 if ( isEndElement() ) {
204 if ( stack.count() > 1 ) {
205 stack.removeLast(); // We are going down one level
206 } else {
207 break;
211 if ( isStartElement() ) {
212 /* Item type tags: first level */
213 if ( stack.count() == 1 && name() == "events" ) {
214 stack.append( qMakePair( QString( "events" ),
215 QString( "CalendarItems Events" ) ) );
216 } else if ( stack.count() == 1 && name() == "to-dos" ) {
217 stack.append( qMakePair( QString( "to-dos" ),
218 QString( "CalendarItems ToDos" ) ) );
219 /* Sub-elements of to-dos (second level) */
220 } else if ( stack.count() == 2 && stack.last().first == "to-dos" &&
221 name() == "overdue" ) {
222 stack.append( qMakePair( QString( "to-dos/overdue" ),
223 QString( "CalendarItems ToDos Overdue" ) ) );
224 } else if ( stack.count() == 2 && stack.last().first == "to-dos" &&
225 name() == "due-today" ) {
226 stack.append( qMakePair( QString( "to-dos/due-today" ),
227 QString( "CalendarItems ToDos DueToday" ) ) );
228 /* The sub-elements of these tags allow free text */
229 } else if ( stack.count() == 1 && name() == "categories" ) {
230 stack.append( qMakePair( QString( "categories" ),
231 // When a setting applies to all categories,
232 // it applies to all items.
233 QString( "CalendarItems" ) ) );
234 } else if ( stack.count() == 1 && name() == "resources" ) {
235 stack.append( qMakePair( QString( "resources" ),
236 // When a setting applies to all resources,
237 // it applies to all items.
238 QString( "CalendarItems" ) ) );
240 /* The said sub-elements */
241 else if ( stack.count() == 2 && stack.last().first == "categories" &&
242 name() == "category" ) {
243 QString n = attributes().value( "name" ).toString();
244 stack.append( qMakePair( QString( "categories/" + n ),
245 QString( "CalendarItems Categories " + n ) ) );
246 } else if ( stack.count() == 2 && stack.last().first == "resources" &&
247 name() == "resource" ) {
248 QString n = attributes().value( "name" ).toString();
249 stack.append( qMakePair( QString( "resources/" + n ),
250 QString( "CalendarItems Resources " + n ) ) );
252 /* Settings' tags */
253 else if ( name() == "background" ) {
254 setColor( viewType, year, month, day,
255 stack.last().second + " Background Color",
256 attributes().value( "color" ).toString() );
257 setPath( viewType, year, month, day,
258 stack.last().second + " Background Image",
259 attributes().value( "src" ).toString() );
260 readNext();
261 } else if ( name() == "font" ) {
262 setFont( viewType, year, month, day,
263 stack.last().second + " Font",
264 attributes().value( "family" ).toString(),
265 attributes().value( "style-hint" ).toString(),
266 attributes().value( "point-size" ).toString().toInt(),
267 attributes().value( "weight" ).toString().toInt(),
268 attributes().value( "style" ).toString(),
269 attributes().value( "stretch-factor" ).toString().toInt() );
270 readNext();
271 } else if ( name() == "frame" ) {
272 setColor( viewType, year, month, day,
273 stack.last().second + " Frame Color",
274 attributes().value( "color" ).toString() );
275 readNext();
276 } else if ( name() == "icon" ) {
277 setString( viewType, year, month, day,
278 stack.last().second + " Icon",
279 attributes().value( "name" ).toString() );
280 setPath( viewType, year, month, day,
281 stack.last().second + " IconFile",
282 attributes().value( "src" ).toString() );
283 readNext();
284 } else {
285 readUnknownElement();
291 void ThemeImporter::readGrid( const QString &viewType, const int year,
292 const int month, const int day )
294 Q_ASSERT( isStartElement() && name() == "grid" );
296 QString cfg = "Grid";
298 while ( !atEnd() ) {
299 readNext();
301 if ( isEndElement() ) {
302 break;
305 if ( isStartElement() ) {
306 if ( name() == "background" ) {
307 setColor( viewType, year, month, day,
308 cfg + " Background Color",
309 attributes().value( "color" ).toString() );
310 setPath( viewType, year, month, day,
311 cfg + " Background Image",
312 attributes().value( "src" ).toString() );
313 readNext();
314 } else if ( name() == "highlight" ) {
315 setColor( viewType, year, month, day,
316 cfg + " Highlight Color",
317 attributes().value( "color" ).toString() );
318 readNext();
319 } else if ( name() == "work-hours" ) {
320 while ( !atEnd() ) {
321 readNext();
323 if ( isEndElement() ) {
324 break;
327 if ( isStartElement() ) {
328 if ( name() == "background" ) {
329 setColor( viewType, year, month, day,
330 cfg + " WorkHours Background Color",
331 attributes().value( "color" ).toString() );
332 setPath( viewType, year, month, day,
333 cfg + " WorkHours Background Image",
334 attributes().value( "src" ).toString() );
335 readNext();
336 } else {
337 readUnknownElement();
341 } else {
342 readUnknownElement();
348 void ThemeImporter::readHolidays( const QString &viewType, const int year,
349 const int month, const int day )
351 Q_ASSERT( isStartElement() && name() == "holidays" );
353 QString cfg = "Holidays";
355 while ( !atEnd() ) {
356 readNext();
358 if ( isEndElement() ) {
359 break;
362 if ( isStartElement() ) {
363 if ( name() == "background" ) {
364 setColor( viewType, year, month, day,
365 cfg + " Background Color",
366 attributes().value( "color" ).toString() );
367 setPath( viewType, year, month, day,
368 cfg + " Background Image",
369 attributes().value( "src" ).toString() );
370 readNext();
371 } else {
372 readUnknownElement();
378 void ThemeImporter::readMarcusBainsLine( const QString &viewType, const int year,
379 const int month, const int day )
381 Q_ASSERT( isStartElement() && name() == "marcus-bains-line" );
383 QString cfg = "MarcusBainsLine";
385 while ( !atEnd() ) {
386 readNext();
388 if ( isEndElement() ) {
389 break;
392 if ( isStartElement() ) {
393 if ( name() == "font" ) {
394 setFont( viewType, year, month, day,
395 cfg + " Font",
396 attributes().value( "family" ).toString(),
397 attributes().value( "style-hint" ).toString(),
398 attributes().value( "point-size" ).toString().toInt(),
399 attributes().value( "weight" ).toString().toInt(),
400 attributes().value( "style" ).toString(),
401 attributes().value( "stretch-factor" ).toString().toInt() );
402 readNext();
403 } else if ( name() == "line" ) {
404 setColor( viewType, year, month, day,
405 cfg + " Line Color",
406 attributes().value( "color" ).toString() );
407 readNext();
408 } else {
409 readUnknownElement();
415 void ThemeImporter::readTimeLabels( const QString &viewType, const int year,
416 const int month, const int day )
418 Q_ASSERT( isStartElement() && name() == "time-labels" );
420 QString cfg = "TimeLabels";
422 while ( !atEnd() ) {
423 readNext();
425 if ( isEndElement() ) {
426 break;
429 if ( isStartElement() ) {
430 if ( name() == "font" ) {
431 setFont( viewType, year, month, day,
432 cfg + " Font",
433 attributes().value( "family" ).toString(),
434 attributes().value( "style-hint" ).toString(),
435 attributes().value( "point-size" ).toString().toInt(),
436 attributes().value( "weight" ).toString().toInt(),
437 attributes().value( "style" ).toString(),
438 attributes().value( "stretch-factor" ).toString().toInt() );
439 readNext();
440 } else {
441 readUnknownElement();
447 ///////////////////////////////////////////////////////////////////////////////
449 void ThemeImporter::setColor( const QString &viewType, const int year,
450 const int month, const int day,
451 const QString &key, const QString &value )
453 QString htmlColor = value.toUpper();
454 if ( ( htmlColor.count( QRegExp( "^#[0-9A-F]{6}$" ) ) == 1 ) ||
455 ( htmlColor.count( QRegExp( "^#[0-9A-F]{8}$" ) ) == 1 ) ) {
456 // #RRGGBB or #AARRGGBB, for consistency with Qt
457 int r = htmlColor.mid( 1, 2 ).toInt( 0, 16 );
458 int g = htmlColor.mid( 3, 2 ).toInt( 0, 16 );
459 int b = htmlColor.mid( 5, 2 ).toInt( 0, 16 );
460 int a = 255;
461 if ( htmlColor.length() == 1+8 ) {
462 a = r;
463 r = g;
464 g = b;
465 b = htmlColor.mid( 7, 2 ).toInt( 0, 16 );
467 QColor color( r, g, b, a );
469 foreach ( const QString &v, Theme::themableViews( viewType ) ) {
470 if ( year == 0 && month == 0 && day == 0 ) {
471 configGroup( v )->writeEntry( v + key, color );
472 } else {
473 // TODO: implement this when date-dependent themes will be enabled
474 kWarning() << "feature not yet implemented";
475 kWarning() << "THEORICAL setting:" << year << "-" << month << "-" << day
476 << ":" << v << ":" << key << ":" << value;
482 void ThemeImporter::setFont( const QString &viewType, const int year,
483 const int month, const int day,
484 const QString &key, const QString &family,
485 const QString &styleHint, const int pointSize,
486 const int weight, const QString &style,
487 const int stretchFactor )
489 QFont f( family, pointSize, weight );
491 QFont::StyleHint sh = QFont::AnyStyle;
492 if ( styleHint == "AnyStyle" ) {
493 sh = QFont::AnyStyle;
494 } else if ( styleHint == "SansSerif" ) {
495 sh = QFont::SansSerif;
496 } else if ( styleHint == "Helvetica" ) {
497 sh = QFont::Helvetica;
498 } else if ( styleHint == "Serif" ) {
499 sh = QFont::Serif;
500 } else if ( styleHint == "Times" ) {
501 sh = QFont::Times;
502 } else if ( styleHint == "TypeWriter" ) {
503 sh = QFont::TypeWriter;
504 } else if ( styleHint == "Courier" ) {
505 sh = QFont::Courier;
506 } else if ( styleHint == "OldEnglish" ) {
507 sh = QFont::OldEnglish;
508 } else if ( styleHint == "Decorative" ) {
509 sh = QFont::Decorative;
510 } else if ( styleHint == "System" ) {
511 sh = QFont::System;
513 f.setStyleHint( sh );
514 QFont::Style s = QFont::StyleNormal;
515 if ( style == "Normal" ) {
516 s = QFont::StyleNormal;
517 } else if ( style == "Italic" ) {
518 s = QFont::StyleItalic;
519 } else if ( style == "Oblique" ) {
520 s = QFont::StyleOblique;
522 f.setStyle( s );
523 int sf = ( stretchFactor < 1 ? 100 : stretchFactor );
524 f.setStretch( sf );
526 foreach ( const QString &v, Theme::themableViews( viewType ) ) {
527 if ( year == 0 && month == 0 && day == 0 ) {
528 configGroup( v )->writeEntry( v + key, f );
529 } else {
530 // TODO: implement this when date-dependent themes will be enabled
531 kWarning() << "feature not yet implemented";
532 kWarning() << "THEORICAL setting:" << year << "-" << month << "-" << day
533 << ":" << v << ":" << key << ":" << family << "\t"
534 << styleHint << "\t" << pointSize << "\t" << weight << "\t"
535 << style << "\t" << sf;
540 void ThemeImporter::setPath( const QString &viewType, const int year,
541 const int month, const int day,
542 const QString &key, const QString &value )
544 if ( ! value.isEmpty() ) {
545 foreach ( const QString &v, Theme::themableViews( viewType ) ) {
546 if ( year == 0 && month == 0 && day == 0 ) {
547 configGroup( v )->writePathEntry( v + key, value );
548 } else {
549 // TODO: implement this when date-dependent themes will be enabled
550 kWarning() << "feature not yet implemented";
551 kWarning() << "THEORICAL setting:" << year << "-" << month << "-" << day
552 << ":" << v << ":" << key << ":" << value;
558 void ThemeImporter::setString( const QString &viewType, const int year,
559 const int month, const int day,
560 const QString &key, const QString &value )
562 if ( ! value.isEmpty() ) {
563 foreach ( const QString &v, Theme::themableViews( viewType ) ) {
564 if ( year == 0 && month == 0 && day == 0 ) {
565 configGroup( v )->writeEntry( v + key, value );
566 } else {
567 // TODO: implement this when date-dependent themes will be enabled
568 kWarning() << "feature not yet implemented";
569 kWarning() << "THEORICAL setting:" << year << "-" << month << "-" << day
570 << ":" << v << ":" << key << ":" << value;
576 ///////////////////////////////////////////////////////////////////////////////
578 KConfigGroup *ThemeImporter::configGroup( const QString &viewType )
580 QMap<QString, KConfigGroup*>::ConstIterator it;
581 KConfigGroup *g;
582 it = mPerViewConfigGroups.constFind( viewType );
583 if ( it == mPerViewConfigGroups.constEnd() ) {
584 g = registerPerViewConfigGroup( createPerViewConfigGroup( viewType ), viewType );
585 } else {
586 g = *it;
588 return g;
591 QList<KConfigGroup*> ThemeImporter::perViewConfigGroups()
593 QList<KConfigGroup*> l;
594 foreach ( const QString &v, Theme::themableViews() ) {
595 l.append( configGroup( v ) );
597 return l;
600 KConfigGroup *ThemeImporter::registerPerViewConfigGroup( KConfigGroup *g, const QString &viewType )
602 mPerViewConfigGroups.insert( viewType, g );
603 return g;
606 KConfigGroup *ThemeImporter::createPerViewConfigGroup( const QString &viewType ) const
608 return new KConfigGroup( KSharedConfig::openConfig(), "Theme/" + viewType + " view" );