libyui-qt  2.43.5
/usr/src/RPM/BUILD/libyui-qt-2.43.5/src/QY2Styler.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019   File:         QY2Styler.cc
00020 
00021   Author:       Stefan Kulow <coolo@suse.de>
00022 
00023 /-*/
00024 
00025 
00026 #define YUILogComponent "qt-styler"
00027 #include <yui/YUILog.h>
00028 #include <yui/YUIException.h>
00029 #include <yui/Libyui_config.h>
00030 #include <YSettings.h>
00031 
00032 #include "QY2Styler.h"
00033 #include <QDebug>
00034 #include <QFile>
00035 #include <QString>
00036 #include <QStringList>
00037 #include <QApplication>
00038 #include <QWidget>
00039 #include <QPainter>
00040 #include <QSvgRenderer>
00041 #include <iostream>
00042 #include <QPixmapCache>
00043 
00044 #define LOGGING_CAUSES_QT4_THREADING_PROBLEMS   1
00045 
00046 std::ostream & operator<<( std::ostream & stream, const QString     & str     );
00047 std::ostream & operator<<( std::ostream & stream, const QStringList & strList );
00048 std::ostream & operator<<( std::ostream & stream, const QWidget     * widget  );
00049 
00050 using namespace std;
00051 
00052 
00053 QY2Styler::QY2Styler( QObject * parent )
00054     : QObject( parent )
00055 {
00056     QPixmapCache::setCacheLimit( 5 * 1024 );
00057     yuiDebug() << "Styler created" << std::endl;
00058 }
00059 
00060 
00061 QY2Styler *
00062 QY2Styler::styler()
00063 {
00064     static QY2Styler * styler = 0;
00065 
00066     if ( ! styler )
00067     {
00068         yuiDebug() << "Creating QY2Styler singleton" << std::endl;
00069 
00070         styler = new QY2Styler( qApp );
00071         YUI_CHECK_NEW( styler );
00072 
00073         QString style = getenv("Y2STYLE");
00074 
00075         if ( ! style.isEmpty() )
00076             styler->loadStyleSheet( style );
00077         else
00078             styler->loadStyleSheet( "style.qss" );
00079     }
00080 
00081     return styler;
00082 }
00083 
00084 
00085 void QY2Styler::loadStyleSheet( const QString & filename )
00086 {
00087     QFile file( themeDir() + filename );
00088 
00089     if ( file.open( QIODevice::ReadOnly ) )
00090     {
00091         yuiMilestone() << "Using style sheet \"" << file.fileName() << "\"" << std::endl;
00092         QString text = file.readAll();
00093         setStyleSheet( text );
00094     }
00095     else
00096     {
00097         yuiMilestone() << "Couldn't open style sheet \"" << file.fileName() << "\"" << std::endl;
00098     }
00099 
00100 }
00101 
00102 void QY2Styler::setStyleSheet( const QString & text )
00103 {
00104     _style = text;
00105     processUrls( _style );
00106 
00107     QWidget *child;
00108     QList< QWidget* > childlist;
00109 
00110     foreach( childlist, _children )
00111         foreach( child, childlist )
00112             child->setStyleSheet( _style );
00113 }
00114 
00115 
00116 void QY2Styler::processUrls( QString & text )
00117 {
00118     QString result;
00119     QStringList lines = text.split( '\n' );
00120     QRegExp urlRegex( ": *url\\((.*)\\)" );
00121     QRegExp backgroundRegex( "^ */\\* *Background: *([^ ]*) *([^ ]*) *\\*/$" );
00122     QRegExp richTextRegex( "^ */\\* *Richtext: *([^ ]*) *\\*/$" );
00123 
00124     _backgrounds.clear();
00125 
00126     for ( QStringList::const_iterator it = lines.begin(); it != lines.end(); ++it )
00127     {
00128         QString line = *it;
00129 
00130         // Replace file name inside url() with full path (from themeDir() )
00131 
00132         if ( urlRegex.indexIn( line ) >= 0 )
00133         {
00134             QString fileName = urlRegex.cap( 1 );
00135             QString fullPath = themeDir() + fileName;
00136             yuiDebug() << "Expanding " << fileName << "\tto " << fullPath << std::endl;
00137             line.replace( urlRegex, ": url(" + fullPath + ")");
00138         }
00139 
00140         if ( backgroundRegex.exactMatch( line ) )
00141         {
00142             QStringList name = backgroundRegex.cap( 1 ).split( '#' );
00143             QString fullPath =  themeDir() + backgroundRegex.cap( 2 );
00144             yuiDebug() << "Expanding background " << name[0] << "\tto " << fullPath << std::endl;
00145 
00146             _backgrounds[ name[0] ].filename = fullPath;
00147             _backgrounds[ name[0] ].full = false;
00148 
00149             if ( name.size() > 1 )
00150                 _backgrounds[ name[0] ].full = ( name[1] == "full" );
00151         }
00152 
00153         if ( richTextRegex.exactMatch( line ) )
00154         {
00155             QString filename = richTextRegex.cap( 1 );
00156             QFile file( themeDir() + "/" + filename );
00157 
00158             if ( file.open(  QIODevice::ReadOnly ) )
00159             {
00160                 yuiDebug() << "Reading " << file.fileName();
00161                 _textStyle = file.readAll();
00162             }
00163             else
00164             {
00165                 yuiError() << "Can't read " << file.fileName();
00166             }
00167         }
00168 
00169         result += line;
00170     }
00171 
00172     text = result;
00173 }
00174 
00175 
00176 QString
00177 QY2Styler::themeDir() const
00178 {   
00179   return QString(YSettings::themeDir().c_str());
00180 }
00181 
00182 
00183 void QY2Styler::registerWidget( QWidget * widget )
00184 {
00185     widget->installEventFilter( this );
00186     widget->setAutoFillBackground( true );
00187     widget->setStyleSheet( _style );
00188 }
00189 
00190 
00191 void QY2Styler::unregisterWidget( QWidget  *widget )
00192 {
00193     _children.remove( widget );
00194 }
00195 
00196 
00197 void QY2Styler::registerChildWidget( QWidget * parent, QWidget * widget )
00198 {
00199     // Don't use yuiDebug() here - deadlock (reason unknown so far) in thread handling!
00200 
00201     qDebug() << "Registering " << widget << " for parent " << parent << endl;
00202     widget->installEventFilter( this );
00203     _children[parent].push_back( widget );
00204 }
00205 
00206 
00207 QImage
00208 QY2Styler::getScaled( const QString name, const QSize & size )
00209 {
00210     QImage image = _backgrounds[name].pix;
00211 
00212     if ( size != image.size() )
00213         image = image.scaled( size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation );
00214     else
00215         image = image.convertToFormat( QImage::Format_ARGB32 );
00216 
00217     if ( image.isNull() )
00218         yuiError() << "Can't load pixmap from " <<  name << std::endl;
00219 #if 1
00220     else
00221         yuiMilestone() << "Loaded pixmap from \"" << name
00222                        << "\"  size: " << image.size().width() << "x" << image.size().height()
00223                        << std::endl;
00224 #endif
00225 
00226     return image;
00227 }
00228 
00229 
00230 void QY2Styler::renderParent( QWidget * wid )
00231 {
00232     // yuiDebug() << "Rendering " << wid << std::endl;
00233     QString name = wid->objectName();
00234 
00235     // TODO
00236     wid->setPalette( QApplication::palette() );
00237 
00238     // if the parent does not have a background, this does not make sense
00239     if ( _backgrounds[name].pix.isNull() )
00240         return;
00241 
00242     QRect fillRect = wid->contentsRect();
00243     if ( _backgrounds[name].full )
00244         fillRect = wid->rect();
00245 
00246     QImage back;
00247 
00248     if ( _backgrounds[name].lastscale != fillRect.size() )
00249     {
00250         _backgrounds[name].scaled = getScaled( name, fillRect.size() );
00251         _backgrounds[name].lastscale = fillRect.size();
00252     }
00253 
00254     back = _backgrounds[name].scaled;
00255 
00256     QPainter pain( &back );
00257     QWidget *child;
00258 
00259 
00260     foreach( child, _children[wid] )
00261     {
00262         // yuiDebug() << "foreach " << child << " " << wid << std::endl;
00263         QString name = child->objectName();
00264 
00265         if (! child->isVisible() || _backgrounds[name].pix.isNull() )
00266              continue;
00267 
00268         QRect fillRect = child->contentsRect();
00269         if ( _backgrounds[name].full )
00270             fillRect = child->rect();
00271 
00272         QString key = QString( "style_%1_%2_%3" ).arg( name ).arg( fillRect.width() ).arg( fillRect.height() );
00273         QPixmap scaled;
00274 
00275         if ( QPixmapCache::find( key, scaled ) )
00276         {
00277             // yuiDebug() << "found " << key << std::endl;
00278         }
00279         else
00280         {
00281             scaled = QPixmap::fromImage( getScaled( name, fillRect.size() ) );
00282             QPixmapCache::insert( key, scaled );
00283         }
00284         pain.drawPixmap( wid->mapFromGlobal( child->mapToGlobal( fillRect.topLeft() ) ), scaled );
00285     }
00286 
00287     QPixmap result = QPixmap::fromImage( back );
00288 
00289     QPalette p = wid->palette();
00290     p.setBrush(QPalette::Window, result );
00291     wid->setPalette( p );
00292 }
00293 
00294 
00295 bool
00296 QY2Styler::updateRendering( QWidget *wid )
00297 {
00298     if (!wid)
00299        return false;
00300 
00301     QString name = wid->objectName();
00302 
00303     if (! wid->isVisible() || !wid->updatesEnabled() )
00304         return false;
00305 
00306     if ( _backgrounds[name].pix.isNull() )
00307     {
00308         QString back = _backgrounds[ name ].filename;
00309 
00310         QImage image( back );
00311         _backgrounds[ name ].pix = image;
00312 
00313         if ( ! back.isEmpty() ) // Prevent misleading error messages
00314         {
00315             if ( image.isNull() )
00316             {
00317                 yuiError() << "Couldn't load background image \"" << back
00318                            << "\" for \"" << name << "\""
00319                            << std::endl;
00320             }
00321             else
00322             {
00323                 yuiDebug() << "Loading background image \"" << back
00324                            << "\" for " << name << "\""
00325                            << std::endl;
00326             }
00327         }
00328     }
00329 
00330 
00331     // if it's a child itself, we have to do the full blow action
00332 
00333     if ( !_children.contains( wid ) )
00334     {
00335         QWidget *parent = wid->parentWidget();
00336         while ( parent && !_children.contains( parent ) )
00337             parent = parent->parentWidget();
00338         if (!parent)
00339            return false;
00340         renderParent( parent );
00341     }
00342     else
00343     {
00344         renderParent( wid );
00345     }
00346 
00347     return true;
00348 }
00349 
00350 
00351 bool
00352 QY2Styler::eventFilter( QObject * obj, QEvent * ev )
00353 {
00354     if ( ev->type() == QEvent::Resize ||
00355          ev->type() == QEvent::Show   ||
00356          ev->type() == QEvent::LayoutRequest ||
00357          ev->type() == QEvent::UpdateRequest )
00358         updateRendering( qobject_cast<QWidget*>( obj ) );
00359 
00360     return QObject::eventFilter( obj, ev );
00361 }
00362 
00363 
00364 
00365 
00366 std::ostream & operator<<( std::ostream & stream, const QString & str )
00367 {
00368     return stream << qPrintable( str );
00369 }
00370 
00371 
00372 std::ostream & operator<<( std::ostream & stream, const QStringList & strList )
00373 {
00374     stream << "[ ";
00375 
00376     for ( QStringList::const_iterator it = strList.begin();
00377           it != strList.end();
00378           ++it )
00379     {
00380         stream << qPrintable( *it ) << " ";
00381     }
00382 
00383     stream << " ]";
00384 
00385     return stream;
00386 }
00387 
00388 
00389 std::ostream & operator<<( std::ostream & stream, const QWidget * widget )
00390 {
00391 #if LOGGING_CAUSES_QT4_THREADING_PROBLEMS
00392 
00393     // QObject::metaObject()->className() and QObject::objectName() can cause
00394     // YQUI to hang, probably due to threading problems.
00395 
00396     stream << "QWidget at " << hex << (void *) widget << dec;
00397 #else
00398     if ( widget )
00399     {
00400         if ( widget->metaObject() )
00401             stream << widget->metaObject()->className();
00402         else
00403             stream << "<QWidget>";
00404 
00405         if ( ! widget->objectName().isEmpty() )
00406             stream << " \"" << qPrintable( widget->objectName() ) << "\"";
00407 
00408         stream << " at " << hex << widget << dec;
00409     }
00410     else // ! widget
00411     {
00412         stream << "<NULL QWidget>";
00413     }
00414 #endif
00415 
00416 
00417     return stream;
00418 }
00419 
00420 
00421 #include "QY2Styler.moc"
 All Classes Functions Variables