26 #define YUILogComponent "qt-styler"
27 #include <yui/YUILog.h>
28 #include <yui/YUIException.h>
29 #include <yui/Libyui_config.h>
30 #include <yui/YSettings.h>
32 #include "QY2Styler.h"
36 #include <QStringList>
37 #include <QApplication>
40 #include <QSvgRenderer>
42 #include <QPixmapCache>
44 #include <QRegularExpression>
46 #define LOGGING_CAUSES_QT4_THREADING_PROBLEMS 1
48 std::ostream & operator<<( std::ostream & stream,
const QString & str );
49 std::ostream & operator<<( std::ostream & stream,
const QStringList & strList );
50 std::ostream & operator<<( std::ostream & stream,
const QWidget * widget );
56 const QString & defaultStyleSheet,
57 const QString & alternateStyleSheet)
60 QPixmapCache::setCacheLimit( 5 * 1024 );
61 yuiDebug() <<
"Styler created" << endl;
65 _currentStyleSheet = QString(
"" );
76 yuiDebug() <<
"Creating QY2Styler singleton" << endl;
78 QString y2style = getenv(
"Y2STYLE");
79 QString y2altstyle = getenv(
"Y2ALTSTYLE");
80 QString y2alttheme = y2altstyle +
".qss";
81 styler =
new QY2Styler( qApp, y2style, y2alttheme );
83 YUI_CHECK_NEW( styler );
95 QFileInfo fileInfo(
themeDir() + styleSheet);
96 return fileInfo.isFile();
103 _defaultStyleSheet = styleSheet;
104 yuiDebug() <<
"Setting high-contrast style sheet to "
105 << _defaultStyleSheet << endl;
112 _alternateStyleSheet = styleSheet;
113 yuiDebug() <<
"Setting default style sheet to "
114 << _alternateStyleSheet << endl;
121 _usingAlternateStyleSheet =
false;
129 _usingAlternateStyleSheet =
true;
136 QFile file(
themeDir() + filename );
138 if ( file.open( QIODevice::ReadOnly ) )
140 yuiMilestone() <<
"Using style sheet \"" << file.fileName() <<
"\"" << endl;
141 QString text = file.readAll();
142 _currentStyleSheet = QString(filename);
148 yuiMilestone() <<
"Couldn't open style sheet \"" << file.fileName() <<
"\"" << endl;
156 QStringList alreadyImportedFilenames;
163 QRegularExpression re(
" *@import +url\\(\"(.+)\"\\);");
165 QRegularExpressionMatchIterator it = re.globalMatch(content);
169 QRegularExpressionMatch match = it.next();
170 QString fullPath =
themeDir() + match.captured(1);
179 QFile file(filename);
181 if ( ! alreadyImportedFilenames.contains(filename) && file.open( QIODevice::ReadOnly ) )
183 alreadyImportedFilenames << filename;
184 return buildStyleSheet(QString(file.readAll()), alreadyImportedFilenames);
197 QList< QWidget* > childlist;
199 foreach( childlist, _children )
200 foreach( child, childlist )
201 child->setStyleSheet( _style );
203 foreach( QWidget *registered_widget, _registered_widgets )
204 registered_widget->setStyleSheet( _style );
220 QStringList lines = text.split(
'\n' );
221 QRegExp urlRegex(
": *url\\((.*)\\)" );
222 QRegExp backgroundRegex(
"^ */\\* *Background: *([^ ]*) *([^ ]*) *\\*/$" );
223 QRegExp richTextRegex(
"^ */\\* *Richtext: *([^ ]*) *\\*/$" );
225 _backgrounds.clear();
227 for ( QStringList::const_iterator it = lines.begin(); it != lines.end(); ++it )
233 if ( urlRegex.indexIn( line ) >= 0 )
235 QString fileName = urlRegex.cap( 1 );
236 QString fullPath =
themeDir() + fileName;
237 yuiDebug() <<
"Expanding " << fileName <<
"\tto " << fullPath << endl;
238 line.replace( urlRegex,
": url(" + fullPath +
")");
241 if ( backgroundRegex.exactMatch( line ) )
243 QStringList name = backgroundRegex.cap( 1 ).split(
'#' );
244 QString fullPath =
themeDir() + backgroundRegex.cap( 2 );
245 yuiDebug() <<
"Expanding background " << name[0] <<
"\tto " << fullPath << endl;
247 _backgrounds[ name[0] ].filename = fullPath;
248 _backgrounds[ name[0] ].full =
false;
250 if ( name.size() > 1 )
251 _backgrounds[ name[0] ].full = ( name[1] ==
"full" );
254 if ( richTextRegex.exactMatch( line ) )
256 QString filename = richTextRegex.cap( 1 );
257 QFile file(
themeDir() +
"/" + filename );
259 if ( file.open( QIODevice::ReadOnly ) )
261 yuiDebug() <<
"Reading " << file.fileName();
262 _textStyle = file.readAll();
266 yuiError() <<
"Can't read " << file.fileName();
280 return QString(YSettings::themeDir().c_str());
286 widget->installEventFilter(
this );
287 widget->setAutoFillBackground(
true );
288 widget->setStyleSheet( _style );
289 _registered_widgets.push_back( widget );
295 _children.remove( widget );
296 _registered_widgets.removeOne( widget );
304 qDebug() <<
"Registering " << widget <<
" for parent " << parent <<
"\n";
305 widget->installEventFilter(
this );
306 _children[parent].push_back( widget );
311 QY2Styler::getScaled(
const QString name,
const QSize & size )
313 QImage image = _backgrounds[name].pix;
315 if ( size != image.size() )
316 image = image.scaled( size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
318 image = image.convertToFormat( QImage::Format_ARGB32 );
320 if ( image.isNull() )
321 yuiError() <<
"Can't load pixmap from " << name << endl;
324 yuiMilestone() <<
"Loaded pixmap from \"" << name
325 <<
"\" size: " << image.size().width() <<
"x" << image.size().height()
333 void QY2Styler::renderParent( QWidget * wid )
336 QString name = wid->objectName();
339 wid->setPalette( QApplication::palette() );
342 if ( _backgrounds[name].pix.isNull() )
345 QRect fillRect = wid->contentsRect();
346 if ( _backgrounds[name].full )
347 fillRect = wid->rect();
351 if ( _backgrounds[name].lastscale != fillRect.size() )
353 _backgrounds[name].scaled = getScaled( name, fillRect.size() );
354 _backgrounds[name].lastscale = fillRect.size();
357 back = _backgrounds[name].scaled;
359 QPainter pain( &back );
363 foreach( child, _children[wid] )
366 QString name = child->objectName();
368 if (! child->isVisible() || _backgrounds[name].pix.isNull() )
371 QRect fillRect = child->contentsRect();
372 if ( _backgrounds[name].full )
373 fillRect = child->rect();
375 QString key = QString(
"style_%1_%2_%3" ).arg( name ).arg( fillRect.width() ).arg( fillRect.height() );
378 if ( QPixmapCache::find( key, &scaled ) )
384 scaled = QPixmap::fromImage( getScaled( name, fillRect.size() ) );
385 QPixmapCache::insert( key, scaled );
387 pain.drawPixmap( wid->mapFromGlobal( child->mapToGlobal( fillRect.topLeft() ) ), scaled );
390 QPixmap result = QPixmap::fromImage( back );
392 QPalette p = wid->palette();
393 p.setBrush(QPalette::Window, result );
394 wid->setPalette( p );
399 QY2Styler::updateRendering( QWidget *wid )
404 QString name = wid->objectName();
406 if (! wid->isVisible() || !wid->updatesEnabled() )
409 if ( _backgrounds[name].pix.isNull() )
411 QString back = _backgrounds[ name ].filename;
413 if ( back.isEmpty() )
415 _backgrounds[ name ].pix = QImage();
419 QImage image ( back );
420 _backgrounds[ name ].pix = image;
422 if ( image.isNull() )
424 yuiError() <<
"Couldn't load background image \"" << back
425 <<
"\" for \"" << name <<
"\""
430 yuiDebug() <<
"Loading background image \"" << back
431 <<
"\" for " << name <<
"\""
440 if ( !_children.contains( wid ) )
442 QWidget *parent = wid->parentWidget();
443 while ( parent && !_children.contains( parent ) )
444 parent = parent->parentWidget();
447 renderParent( parent );
459 QY2Styler::eventFilter( QObject * obj, QEvent * ev )
461 if ( ev->type() == QEvent::Resize ||
462 ev->type() == QEvent::Show ||
463 ev->type() == QEvent::LayoutRequest ||
464 ev->type() == QEvent::UpdateRequest )
465 updateRendering( qobject_cast<QWidget*>( obj ) );
467 return QObject::eventFilter( obj, ev );
473 std::ostream & operator<<( std::ostream & stream,
const QString & str )
475 return stream << qPrintable( str );
479 std::ostream & operator<<( std::ostream & stream,
const QStringList & strList )
483 for ( QStringList::const_iterator it = strList.begin();
487 stream << qPrintable( *it ) <<
" ";
496 std::ostream & operator<<( std::ostream & stream,
const QWidget * widget )
498 #if LOGGING_CAUSES_QT4_THREADING_PROBLEMS
503 stream <<
"QWidget at " << hex << (
void *) widget << dec;
507 if ( widget->metaObject() )
508 stream << widget->metaObject()->className();
510 stream <<
"<QWidget>";
512 if ( ! widget->objectName().isEmpty() )
513 stream <<
" \"" << qPrintable( widget->objectName() ) <<
"\"";
515 stream <<
" at " << hex << widget << dec;
519 stream <<
"<NULL QWidget>";