src/hbservers/hbsplashgenerator/hbsplashgenerator.cpp
changeset 2 06ff229162e9
parent 1 f7ac710697a9
child 3 11d3954df52a
equal deleted inserted replaced
1:f7ac710697a9 2:06ff229162e9
    41 #include "hbframeitem.h"
    41 #include "hbframeitem.h"
    42 #include <QCoreApplication>
    42 #include <QCoreApplication>
    43 #include <QPainter>
    43 #include <QPainter>
    44 #include <QDir>
    44 #include <QDir>
    45 #include <QFile>
    45 #include <QFile>
       
    46 #include <QFileInfo>
    46 #include <QSet>
    47 #include <QSet>
    47 #include <QTranslator>
    48 #include <QTranslator>
    48 #include <QLocale>
    49 #include <QLocale>
    49 #include <QTimer>
    50 #include <QTimer>
    50 
    51 
    52 const char *last_lang_key = "lastlang";
    53 const char *last_lang_key = "lastlang";
    53 const char *last_file_count_key = "lastfilecount";
    54 const char *last_file_count_key = "lastfilecount";
    54 const char *last_output_dir_key = "lastoutdir";
    55 const char *last_output_dir_key = "lastoutdir";
    55 
    56 
    56 HbSplashGenerator::HbSplashGenerator()
    57 HbSplashGenerator::HbSplashGenerator()
    57     : mBusy(false), mMainWindow(0), mFirstRegenerate(true),
    58     : mBusy(false), mForceRegen(false), mMainWindow(0), mFirstRegenerate(true),
    58       mSettings("Nokia", "HbSplash")
    59       mSettings("Nokia", "HbSplash")
    59 {
    60 {
    60     // Effects on decorators (started when they are shown) would ruin
    61     // Effects on decorators (started when they are shown) would ruin
    61     // the screenshot. So disable everything (except the orientation
    62     // the screenshot. So disable everything (except the orientation
    62     // switch effect which is needed for a proper rotated image).
    63     // switch effect which is needed for a proper rotated image).
    71 
    72 
    72 static QString orientationName(Qt::Orientation orientation)
    73 static QString orientationName(Qt::Orientation orientation)
    73 {
    74 {
    74     switch (orientation) {
    75     switch (orientation) {
    75     case Qt::Horizontal:
    76     case Qt::Horizontal:
    76         return QString("lsc");
    77         return QLatin1String("lsc");
    77     case Qt::Vertical:
    78     case Qt::Vertical:
    78         return QString("prt");
    79         return QLatin1String("prt");
    79     default:
    80     default:
    80         return QString();
    81         return QString();
    81     }
    82     }
    82 }
    83 }
    83 
    84 
   100     return entries.count();
   101     return entries.count();
   101 }
   102 }
   102 
   103 
   103 void HbSplashGenerator::start(bool forceRegen)
   104 void HbSplashGenerator::start(bool forceRegen)
   104 {
   105 {
       
   106     mForceRegen = forceRegen;
       
   107     QTimer::singleShot(5000, this, SLOT(doStart()));
       
   108 }
       
   109 
       
   110 void HbSplashGenerator::doStart()
       
   111 {
       
   112     qDebug() << PRE << "accessing theme";
   105     // Start listening to the theme-change-finished signal.
   113     // Start listening to the theme-change-finished signal.
   106     HbTheme *theme = hbInstance->theme();
   114     HbTheme *theme = hbInstance->theme();
   107     connect(theme, SIGNAL(changeFinished()), SLOT(regenerate()));
   115     connect(theme, SIGNAL(changeFinished()), SLOT(regenerate()));
   108 
   116 
   109     // Watch also the directories containing splashml files. Files may
   117     // Watch also the directories containing splashml files. Files may
   129     QString currentLang = QLocale::system().name();
   137     QString currentLang = QLocale::system().name();
   130     QString currentOutputDir = hbsplash_output_dir();
   138     QString currentOutputDir = hbsplash_output_dir();
   131     int currentFileCount = updateOutputDirContents(currentOutputDir);
   139     int currentFileCount = updateOutputDirContents(currentOutputDir);
   132     qDebug() << PRE << "last regen:" << lastTheme << lastLang << lastFileCount << lastOutputDir
   140     qDebug() << PRE << "last regen:" << lastTheme << lastLang << lastFileCount << lastOutputDir
   133              << "current:" << currentTheme << currentLang << currentFileCount << currentOutputDir;
   141              << "current:" << currentTheme << currentLang << currentFileCount << currentOutputDir;
   134     if (forceRegen
   142     if (mForceRegen
   135         || currentTheme != lastTheme
   143         || currentTheme != lastTheme
   136         || currentLang != lastLang
   144         || currentLang != lastLang
   137         || currentFileCount != lastFileCount
   145         || currentFileCount != lastFileCount
   138         || currentOutputDir != lastOutputDir)
   146         || currentOutputDir != lastOutputDir)
   139     {
   147     {
   140         QMetaObject::invokeMethod(this, "regenerate", Qt::QueuedConnection);
   148         QMetaObject::invokeMethod(this, "regenerate", Qt::QueuedConnection);
   141     }
   149     }
       
   150 }
       
   151 
       
   152 void HbSplashGenerator::uncachedRegenerate()
       
   153 {
       
   154     // Same as regenerate() but no caching is used so every file is
       
   155     // parsed again.
       
   156     mParsedSplashmls.clear();
       
   157     regenerate();
   142 }
   158 }
   143 
   159 
   144 void HbSplashGenerator::regenerate()
   160 void HbSplashGenerator::regenerate()
   145 {
   161 {
   146     QString themeName = hbInstance->theme()->name();
   162     QString themeName = hbInstance->theme()->name();
   182             QMetaObject::invokeMethod(this, "processQueue", Qt::QueuedConnection);
   198             QMetaObject::invokeMethod(this, "processQueue", Qt::QueuedConnection);
   183         } catch (const std::bad_alloc &) {
   199         } catch (const std::bad_alloc &) {
   184             cleanup();
   200             cleanup();
   185         }
   201         }
   186     }
   202     }
       
   203 }
       
   204 
       
   205 void HbSplashGenerator::regenerateOne(const QString &splashmlFileName)
       
   206 {
       
   207     mQueue.clear();
       
   208     QueueItem item(hbInstance->theme()->name(), Qt::Vertical);
       
   209     item.mWorkDirForSingleFileRegen = QFileInfo(splashmlFileName).path(); // e.g. for translations
       
   210     parseSplashml(splashmlFileName, item);
       
   211     item.mDocmlFileName = QDir(item.mWorkDirForSingleFileRegen).filePath(item.mDocmlFileName);
       
   212     mQueue.enqueue(item); // generate it regardless of the fixed orientation setting
       
   213     item.mOrientation = Qt::Horizontal;
       
   214     mQueue.enqueue(item);
       
   215     QMetaObject::invokeMethod(this, "processQueue", Qt::QueuedConnection);
   187 }
   216 }
   188 
   217 
   189 QImage HbSplashGenerator::renderView()
   218 QImage HbSplashGenerator::renderView()
   190 {
   219 {
   191     log("renderView()", mItem.mThemeName, mItem.mOrientation);
   220     log("renderView()", mItem.mThemeName, mItem.mOrientation);
   219         mSettings.setValue(last_theme_key, hbInstance->theme()->name());
   248         mSettings.setValue(last_theme_key, hbInstance->theme()->name());
   220         mSettings.setValue(last_lang_key, QLocale::system().name());
   249         mSettings.setValue(last_lang_key, QLocale::system().name());
   221         QString outDir = hbsplash_output_dir();
   250         QString outDir = hbsplash_output_dir();
   222         mSettings.setValue(last_file_count_key, updateOutputDirContents(outDir));
   251         mSettings.setValue(last_file_count_key, updateOutputDirContents(outDir));
   223         mSettings.setValue(last_output_dir_key, outDir);
   252         mSettings.setValue(last_output_dir_key, outDir);
       
   253         emit finished();
   224         qDebug() << PRE << "processQueue() over";
   254         qDebug() << PRE << "processQueue() over";
   225         return;
   255         return;
   226     }
   256     }
   227     // If a previous splash generation is still in progress then do nothing.
   257     // If a previous splash generation is still in progress then do nothing.
   228     if (mBusy) {
   258     if (mBusy) {
   434                 qDebug() << PRE << "splashml already parsed  queuing request" << item;
   464                 qDebug() << PRE << "splashml already parsed  queuing request" << item;
   435                 addSplashmlItemToQueue(item);
   465                 addSplashmlItemToQueue(item);
   436                 continue;
   466                 continue;
   437             }
   467             }
   438             QueueItem item(themeName, orientation);
   468             QueueItem item(themeName, orientation);
   439             QFile f(fullName);
   469             bool ok = parseSplashml(fullName, item);
   440             bool ok = f.open(QIODevice::ReadOnly);
       
   441             if (ok) {
       
   442                 QXmlStreamReader xml(&f);
       
   443                 bool docOk = false;
       
   444                 while (!xml.atEnd()) {
       
   445                     QXmlStreamReader::TokenType token = xml.readNext();
       
   446                     if (token == QXmlStreamReader::Invalid) {
       
   447                         qWarning() << PRE << fullName << xml.errorString();
       
   448                         ok = false;
       
   449                         break;
       
   450                     } else if (token == QXmlStreamReader::StartElement
       
   451                                && xml.name() == QLatin1String("hbsplash"))
       
   452                     {
       
   453                         docOk = true;
       
   454                     } else if (docOk) {
       
   455                         processSplashml(xml, item);
       
   456                     }
       
   457                 }
       
   458                 f.close();
       
   459             }
       
   460             if (ok
   470             if (ok
   461                 && !item.mAppId.isEmpty()
   471                 && !item.mAppId.isEmpty()
   462                 && !item.mDocmlWidgetName.isEmpty()
   472                 && !item.mDocmlWidgetName.isEmpty()
   463                 && !item.mDocmlFileName.isEmpty())
   473                 && !item.mDocmlFileName.isEmpty())
   464             {
   474             {
   467                 item.mDocmlFileName = dir.filePath(item.mDocmlFileName);
   477                 item.mDocmlFileName = dir.filePath(item.mDocmlFileName);
   468                 qDebug() << PRE << "queuing request" << item;
   478                 qDebug() << PRE << "queuing request" << item;
   469                 addSplashmlItemToQueue(item);
   479                 addSplashmlItemToQueue(item);
   470                 mParsedSplashmls.insert(fullName, item);
   480                 mParsedSplashmls.insert(fullName, item);
   471             } else {
   481             } else {
   472                 qWarning() << PRE << "Unable to parse" << fullName;
   482                 qWarning() << PRE << "unable to parse" << fullName;
   473             }
   483             }
   474         }
   484         }
   475     }
   485     }
       
   486 }
       
   487 
       
   488 inline void reportSplashmlError(const QString &fullFileName, int lineNumber, const QString &msg)
       
   489 {
       
   490     qWarning("%s", qPrintable(QString(QLatin1String("%1 \"%2\":%3: %4"))
       
   491                               .arg(PRE).arg(fullFileName).arg(lineNumber).arg(msg)));
       
   492 }
       
   493 
       
   494 bool HbSplashGenerator::parseSplashml(const QString &fullFileName, QueueItem &item)
       
   495 {
       
   496     QFile f(fullFileName);
       
   497     bool ok = f.open(QIODevice::ReadOnly);
       
   498     if (ok) {
       
   499         QXmlStreamReader xml(&f);
       
   500         bool docOk = false;
       
   501         while (!xml.atEnd()) {
       
   502             QXmlStreamReader::TokenType token = xml.readNext();
       
   503             if (token == QXmlStreamReader::Invalid) {
       
   504                 reportSplashmlError(fullFileName, xml.lineNumber(), xml.errorString());
       
   505                 ok = false;
       
   506                 break;
       
   507             } else if (token == QXmlStreamReader::StartElement
       
   508                        && xml.name() == QLatin1String("hbsplash"))
       
   509             {
       
   510                 docOk = true;
       
   511             } else if (docOk) {
       
   512                 parseSplashmlElements(xml, item, fullFileName);
       
   513             }
       
   514         }
       
   515         f.close();
       
   516     }
       
   517     return ok;
   476 }
   518 }
   477 
   519 
   478 inline bool readBool(QXmlStreamReader &xml)
   520 inline bool readBool(QXmlStreamReader &xml)
   479 {
   521 {
   480     QString text = xml.readElementText().trimmed();
   522     QString text = xml.readElementText().trimmed();
   481     return text == QLatin1String("true") || text == QLatin1String("1");
   523     return text == QLatin1String("true") || text == QLatin1String("1");
   482 }
   524 }
   483 
   525 
   484 void HbSplashGenerator::processSplashml(QXmlStreamReader &xml, QueueItem &item)
   526 void HbSplashGenerator::parseSplashmlElements(QXmlStreamReader &xml,
       
   527                                               QueueItem &item,
       
   528                                               const QString &fullFileName)
   485 {
   529 {
   486     if (xml.isStartElement()) {
   530     if (xml.isStartElement()) {
   487         QStringRef name = xml.name();
   531         QStringRef name = xml.name();
   488         if (name == QLatin1String("docml")) {
   532         if (name == QLatin1String("docml")) {
   489             item.mDocmlFileName = xml.readElementText().trimmed();
   533             item.mDocmlFileName = xml.readElementText().trimmed();
   556             req.mFrameGraphicsName = xml.readElementText().trimmed();
   600             req.mFrameGraphicsName = xml.readElementText().trimmed();
   557             if (!req.mTargetWidgetName.isEmpty() && !req.mFrameGraphicsName.isEmpty()) {
   601             if (!req.mTargetWidgetName.isEmpty() && !req.mFrameGraphicsName.isEmpty()) {
   558                 item.mItemBgGraphics.append(req);
   602                 item.mItemBgGraphics.append(req);
   559             }
   603             }
   560         } else {
   604         } else {
   561             qWarning() << PRE << "unknown element" << name;
   605             reportSplashmlError(fullFileName, xml.lineNumber(),
       
   606                                 QLatin1String("unknown element: ") + name.toString());
   562         }
   607         }
   563     }
   608     }
   564 }
   609 }
   565 
   610 
   566 class CustomDocumentLoader : public HbDocumentLoader
   611 class CustomDocumentLoader : public HbDocumentLoader
   643             mMainWindow->addView(widget);
   688             mMainWindow->addView(widget);
   644         } else {
   689         } else {
   645             qWarning() << PRE << "widget creation failed from" << mItem;
   690             qWarning() << PRE << "widget creation failed from" << mItem;
   646         }
   691         }
   647     } else {
   692     } else {
   648         qWarning() << PRE << "Unable to parse" << mItem.mDocmlFileName;
   693         qWarning() << PRE << "unable to parse" << mItem.mDocmlFileName;
   649     }
   694     }
   650 }
   695 }
   651 
   696 
   652 void HbSplashGenerator::setupNameBasedWidgetProps(HbDocumentLoader &loader)
   697 void HbSplashGenerator::setupNameBasedWidgetProps(HbDocumentLoader &loader)
   653 {
   698 {
   767 {
   812 {
   768     QString lang = QLocale::system().name();
   813     QString lang = QLocale::system().name();
   769     QTranslator *translator = new QTranslator;
   814     QTranslator *translator = new QTranslator;
   770     bool ok = false;
   815     bool ok = false;
   771     QStringList dirNames(hbsplash_translation_dirs());
   816     QStringList dirNames(hbsplash_translation_dirs());
       
   817     if (!mItem.mWorkDirForSingleFileRegen.isEmpty()) {
       
   818         dirNames.append(mItem.mWorkDirForSingleFileRegen);
       
   819     }
   772     foreach (const QString &dirName, dirNames) {
   820     foreach (const QString &dirName, dirNames) {
   773         QDir dir(dirName);
   821         QDir dir(dirName);
   774         QString fullName = dir.filePath(name + '_' + lang);
   822         QString fullName = dir.filePath(name + '_' + lang);
   775         // fullName is not necessarily an existing file, however the translator
   823         // fullName is not necessarily an existing file, however the translator
   776         // may still pick up another suitable file based on this name.
   824         // may still pick up another suitable file based on this name.
   777         if (translator->load(fullName)) {
   825         if (translator->load(fullName)) {
   778             QCoreApplication::installTranslator(translator);
   826             QCoreApplication::installTranslator(translator);
   779             qDebug() << PRE << "Translator installed:" << fullName;
   827             qDebug() << PRE << "translator installed:" << fullName;
   780             ok = true;
   828             ok = true;
   781             break;
   829             break;
   782         }
   830         }
   783     }
   831     }
   784     if (ok) {
   832     if (ok) {
   785         mTranslators.append(translator);
   833         mTranslators.append(translator);
   786     } else {
   834     } else {
   787         qWarning() << PRE << "Unable to find translations based on name" << name;
   835         qWarning() << PRE << "unable to find translations based on name" << name;
   788         delete translator;
   836         delete translator;
   789     }
   837     }
   790 }
   838 }
   791 
   839 
   792 void HbSplashGenerator::clearTranslators()
   840 void HbSplashGenerator::clearTranslators()