26 #define YUILogComponent "qt-styler" 27 #include <yui/YUILog.h> 28 #include <yui/YUIException.h> 29 #include <yui/Libyui_config.h> 30 #include <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" << std::endl;
64 _currentStyleSheet = QString(
"" );
75 yuiDebug() <<
"Creating QY2Styler singleton" << std::endl;
77 QString y2style = getenv(
"Y2STYLE");
78 QString y2altstyle = getenv(
"Y2ALTSTYLE");
79 QString y2alttheme = y2altstyle +
".qss";
80 styler =
new QY2Styler( qApp, y2style, y2alttheme );
82 YUI_CHECK_NEW( styler );
93 QFileInfo fileInfo(
themeDir() + styleSheet);
94 return fileInfo.isFile();
100 _defaultStyleSheet = styleSheet;
101 yuiDebug() <<
"Setting high-contrast style sheet to " 102 << _defaultStyleSheet << std::endl;
108 _alternateStyleSheet = styleSheet;
109 yuiDebug() <<
"Setting default style sheet to " 110 << _alternateStyleSheet << std::endl;
116 _usingAlternateStyleSheet =
false;
123 _usingAlternateStyleSheet =
true;
129 QFile file(
themeDir() + filename );
131 if ( file.open( QIODevice::ReadOnly ) )
133 yuiMilestone() <<
"Using style sheet \"" << file.fileName() <<
"\"" << std::endl;
134 QString text = file.readAll();
135 _currentStyleSheet = QString(filename);
141 yuiMilestone() <<
"Couldn't open style sheet \"" << file.fileName() <<
"\"" << std::endl;
148 QStringList alreadyImportedFilenames;
154 QRegularExpression re(
" *@import +url\\(\"(.+)\"\\);");
156 QRegularExpressionMatchIterator it = re.globalMatch(content);
157 while (it.hasNext()) {
158 QRegularExpressionMatch match = it.next();
159 QString fullPath =
themeDir() + match.captured(1);
167 QFile file(filename);
169 if ( !alreadyImportedFilenames.contains(filename) && file.open( QIODevice::ReadOnly ) ) {
170 alreadyImportedFilenames << filename;
171 return buildStyleSheet(QString(file.readAll()), alreadyImportedFilenames);
183 QList< QWidget* > childlist;
185 foreach( childlist, _children )
186 foreach( child, childlist )
187 child->setStyleSheet( _style );
189 foreach( QWidget *registered_widget, _registered_widgets )
190 registered_widget->setStyleSheet( _style );
204 QStringList lines = text.split(
'\n' );
205 QRegExp urlRegex(
": *url\\((.*)\\)" );
206 QRegExp backgroundRegex(
"^ */\\* *Background: *([^ ]*) *([^ ]*) *\\*/$" );
207 QRegExp richTextRegex(
"^ */\\* *Richtext: *([^ ]*) *\\*/$" );
209 _backgrounds.clear();
211 for ( QStringList::const_iterator it = lines.begin(); it != lines.end(); ++it )
217 if ( urlRegex.indexIn( line ) >= 0 )
219 QString fileName = urlRegex.cap( 1 );
220 QString fullPath =
themeDir() + fileName;
221 yuiDebug() <<
"Expanding " << fileName <<
"\tto " << fullPath << std::endl;
222 line.replace( urlRegex,
": url(" + fullPath +
")");
225 if ( backgroundRegex.exactMatch( line ) )
227 QStringList name = backgroundRegex.cap( 1 ).split(
'#' );
228 QString fullPath =
themeDir() + backgroundRegex.cap( 2 );
229 yuiDebug() <<
"Expanding background " << name[0] <<
"\tto " << fullPath << std::endl;
231 _backgrounds[ name[0] ].filename = fullPath;
232 _backgrounds[ name[0] ].full =
false;
234 if ( name.size() > 1 )
235 _backgrounds[ name[0] ].full = ( name[1] ==
"full" );
238 if ( richTextRegex.exactMatch( line ) )
240 QString filename = richTextRegex.cap( 1 );
241 QFile file(
themeDir() +
"/" + filename );
243 if ( file.open( QIODevice::ReadOnly ) )
245 yuiDebug() <<
"Reading " << file.fileName();
246 _textStyle = file.readAll();
250 yuiError() <<
"Can't read " << file.fileName();
264 return QString(YSettings::themeDir().c_str());
270 widget->installEventFilter(
this );
271 widget->setAutoFillBackground(
true );
272 widget->setStyleSheet( _style );
273 _registered_widgets.push_back( widget );
279 _children.remove( widget );
280 _registered_widgets.removeOne( widget );
288 qDebug() <<
"Registering " << widget <<
" for parent " << parent << endl;
289 widget->installEventFilter(
this );
290 _children[parent].push_back( widget );
295 QY2Styler::getScaled(
const QString name,
const QSize & size )
297 QImage image = _backgrounds[name].pix;
299 if ( size != image.size() )
300 image = image.scaled( size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
302 image = image.convertToFormat( QImage::Format_ARGB32 );
304 if ( image.isNull() )
305 yuiError() <<
"Can't load pixmap from " << name << std::endl;
308 yuiMilestone() <<
"Loaded pixmap from \"" << name
309 <<
"\" size: " << image.size().width() <<
"x" << image.size().height()
317 void QY2Styler::renderParent( QWidget * wid )
320 QString name = wid->objectName();
323 wid->setPalette( QApplication::palette() );
326 if ( _backgrounds[name].pix.isNull() )
329 QRect fillRect = wid->contentsRect();
330 if ( _backgrounds[name].full )
331 fillRect = wid->rect();
335 if ( _backgrounds[name].lastscale != fillRect.size() )
337 _backgrounds[name].scaled = getScaled( name, fillRect.size() );
338 _backgrounds[name].lastscale = fillRect.size();
341 back = _backgrounds[name].scaled;
343 QPainter pain( &back );
347 foreach( child, _children[wid] )
350 QString name = child->objectName();
352 if (! child->isVisible() || _backgrounds[name].pix.isNull() )
355 QRect fillRect = child->contentsRect();
356 if ( _backgrounds[name].full )
357 fillRect = child->rect();
359 QString key = QString(
"style_%1_%2_%3" ).arg( name ).arg( fillRect.width() ).arg( fillRect.height() );
362 if ( QPixmapCache::find( key, scaled ) )
368 scaled = QPixmap::fromImage( getScaled( name, fillRect.size() ) );
369 QPixmapCache::insert( key, scaled );
371 pain.drawPixmap( wid->mapFromGlobal( child->mapToGlobal( fillRect.topLeft() ) ), scaled );
374 QPixmap result = QPixmap::fromImage( back );
376 QPalette p = wid->palette();
377 p.setBrush(QPalette::Window, result );
378 wid->setPalette( p );
383 QY2Styler::updateRendering( QWidget *wid )
388 QString name = wid->objectName();
390 if (! wid->isVisible() || !wid->updatesEnabled() )
393 if ( _backgrounds[name].pix.isNull() )
395 QString back = _backgrounds[ name ].filename;
397 if ( back.isEmpty() )
399 _backgrounds[ name ].pix = QImage();
403 QImage image ( back );
404 _backgrounds[ name ].pix = image;
406 if ( image.isNull() )
408 yuiError() <<
"Couldn't load background image \"" << back
409 <<
"\" for \"" << name <<
"\"" 414 yuiDebug() <<
"Loading background image \"" << back
415 <<
"\" for " << name <<
"\"" 424 if ( !_children.contains( wid ) )
426 QWidget *parent = wid->parentWidget();
427 while ( parent && !_children.contains( parent ) )
428 parent = parent->parentWidget();
431 renderParent( parent );
443 QY2Styler::eventFilter( QObject * obj, QEvent * ev )
445 if ( ev->type() == QEvent::Resize ||
446 ev->type() == QEvent::Show ||
447 ev->type() == QEvent::LayoutRequest ||
448 ev->type() == QEvent::UpdateRequest )
449 updateRendering( qobject_cast<QWidget*>( obj ) );
451 return QObject::eventFilter( obj, ev );
457 std::ostream & operator<<( std::ostream & stream,
const QString & str )
459 return stream << qPrintable( str );
463 std::ostream & operator<<( std::ostream & stream,
const QStringList & strList )
467 for ( QStringList::const_iterator it = strList.begin();
471 stream << qPrintable( *it ) <<
" ";
480 std::ostream & operator<<( std::ostream & stream,
const QWidget * widget )
482 #if LOGGING_CAUSES_QT4_THREADING_PROBLEMS 487 stream <<
"QWidget at " << hex << (
void *) widget << dec;
491 if ( widget->metaObject() )
492 stream << widget->metaObject()->className();
494 stream <<
"<QWidget>";
496 if ( ! widget->objectName().isEmpty() )
497 stream <<
" \"" << qPrintable( widget->objectName() ) <<
"\"";
499 stream <<
" at " << hex << widget << dec;
503 stream <<
"<NULL QWidget>";
512 #include "QY2Styler.moc" bool styleSheetExists(const QString &file)
Determines if an style sheet exists.
QY2Styler(QObject *parent, const QString &defaultStyleSheet="", const QString &alternateStyleSheet="")
Constructor.
const QString buildStyleSheet(QString content)
Build a stylesheet from a string.
void toggleAlternateStyleSheet()
Toggle between default/alternate style sheets.
const QString buildStyleSheetFromFile(const QString &filename, QStringList &alreadyImportedFilenames)
Build a stylesheet from a file.
void setStyleSheet(const QString &text)
Applies a style sheet from a string.
void registerWidget(QWidget *widget)
Registers a widget and applies the style sheet.
bool loadStyleSheet(const QString &file)
Loads and apply a style sheet from a file.
bool usingAlternateStyleSheet()
Determines if the alternate style is being used.
void processUrls(QString &text)
Search and replace some self-defined macros in the style sheet.
bool loadDefaultStyleSheet()
Loads the default stylesheet.
void setDefaultStyleSheet(const QString &styleSheet)
Set style sheet for the default theme.
void setAlternateStyleSheet(const QString &styleSheet)
Set style sheet for the alternate theme.
bool loadAlternateStyleSheet()
Loads the alternate stylesheet.
void registerChildWidget(QWidget *parent, QWidget *widget)
Registers a child widget.
QString themeDir() const
Returns the path to the style sheets directory.
void unregisterWidget(QWidget *widget)
Unregisters a widget.