src/hbtools/hbthemeindexer/main.cpp
changeset 34 ed14f46c0e55
parent 6 c3690ec91ef8
equal deleted inserted replaced
31:7516d6d86cf5 34:ed14f46c0e55
    23 **
    23 **
    24 ****************************************************************************/
    24 ****************************************************************************/
    25 
    25 
    26 #include <hbiconsource_p.h>
    26 #include <hbiconsource_p.h>
    27 #include <hbthemeindex_p.h>
    27 #include <hbthemeindex_p.h>
       
    28 #include <hbhash_p.h>
       
    29 
    28 #include <assert.h>
    30 #include <assert.h>
    29 #include <iostream>
    31 #include <iostream>
    30 #include <QApplication>
    32 #include <QApplication>
    31 #include <QStringList>
    33 #include <QStringList>
    32 #include <QTextStream>
    34 #include <QTextStream>
    35 #include <QString>
    37 #include <QString>
    36 #include <QFile>
    38 #include <QFile>
    37 #include <QMap>
    39 #include <QMap>
    38 #include <QDir>
    40 #include <QDir>
    39 
    41 
       
    42 #if !defined(QT_DLL) && !defined(QT_SHARED)
       
    43 #include <QtPlugin>
       
    44 Q_IMPORT_PLUGIN(qsvg)
       
    45 #endif
       
    46 
    40 #define RESOURCE_LIB_NAME "HbCore"
    47 #define RESOURCE_LIB_NAME "HbCore"
    41 #define WIN32_DEBUG_SUFFIX "d"
    48 #define WIN32_DEBUG_SUFFIX "d"
    42 #define MAC_DEBUG_SUFFIX "_debug"
    49 #define MAC_DEBUG_SUFFIX "_debug"
    43 
    50 
    44 
    51 
   101                 continue; 
   108                 continue; 
   102             }
   109             }
   103             LockedList.append(line);
   110             LockedList.append(line);
   104         }
   111         }
   105     }
   112     }
   106 }
       
   107 
       
   108 QSize getDefaultSize(const QString &filename)
       
   109 {
       
   110     HbIconSource source(filename);
       
   111     return source.defaultSize().toSize();
       
   112 }
   113 }
   113 
   114 
   114 void appendItem(HbThemeIndexItemData &itemData, const QString &itemName)
   115 void appendItem(HbThemeIndexItemData &itemData, const QString &itemName)
   115 {
   116 {
   116     bool alreadyExists = false;
   117     bool alreadyExists = false;
   229             // Define fileName (remove file extension)
   230             // Define fileName (remove file extension)
   230             QString iconname;
   231             QString iconname;
   231             // If we come here, the filename must end with .* (e.g. .svg)
   232             // If we come here, the filename must end with .* (e.g. .svg)
   232             iconname = filename.left(filename.lastIndexOf('.'));
   233             iconname = filename.left(filename.lastIndexOf('.'));
   233 
   234 
   234             itemData.itemNameHash = HbThemeIndex::hash(iconname);
   235             itemData.itemNameHash = hbHash(iconname);
   235 
   236 
   236             // Define default size
   237             // Define default size
   237             QSize defaultSize = getDefaultSize(fullFilename);
   238             HbIconSource source(fullFilename);
       
   239             if (itemData.itemType != HbThemeIndexItemData::NvgItem) {
       
   240                 if (!source.imageReader()) {
       
   241                     std::cout << "ERROR: could not read file " << fullFilename.toStdString() << "\n";
       
   242                     return; // Don't add invalid file to the index
       
   243                 }
       
   244             }
       
   245             QSize defaultSize = source.defaultSize().toSize();
   238             itemData.defaultWidth = static_cast<quint32>(defaultSize.width());
   246             itemData.defaultWidth = static_cast<quint32>(defaultSize.width());
   239             itemData.defaultHeight = static_cast<quint32>(defaultSize.height());
   247             itemData.defaultHeight = static_cast<quint32>(defaultSize.height());
   240 
   248 
   241             QString mirroredFilepath = fullFilename;
   249             QString mirroredFilepath = fullFilename;
   242 
   250 
   257 
   265 
   258                 foreach(QString ext, extList) {
   266                 foreach(QString ext, extList) {
   259                     QString mirroredFilenameCandidate = mirroredFilepath + iconname + ext;
   267                     QString mirroredFilenameCandidate = mirroredFilepath + iconname + ext;
   260 
   268 
   261                     if (QFile::exists(mirroredFilenameCandidate)) {
   269                     if (QFile::exists(mirroredFilenameCandidate)) {
       
   270                         HbIconSource mirroredSource(fullFilename);
       
   271                         if ((ext != ".nvg") && !mirroredSource.imageReader()) {
       
   272                             std::cout << "ERROR: could not read file " << fullFilename.toStdString() << "\n";
       
   273                             continue; // Don't register invalid mirrored icon
       
   274                         }
   262                         itemData.mirroredItemType = getItemType(mirroredFilenameCandidate);
   275                         itemData.mirroredItemType = getItemType(mirroredFilenameCandidate);
   263                         // Define mirrored icon size
   276                         // Define mirrored icon size
   264                         QSize mirroredSize = getDefaultSize(mirroredFilenameCandidate);
   277                         QSize mirroredSize = mirroredSource.defaultSize().toSize();
   265                         itemData.mirroredWidth = static_cast<quint32>(mirroredSize.width());
   278                         itemData.mirroredWidth = static_cast<quint32>(mirroredSize.width());
   266                         itemData.mirroredHeight = static_cast<quint32>(mirroredSize.height());
   279                         itemData.mirroredHeight = static_cast<quint32>(mirroredSize.height());
   267                         break;
   280                         break;
   268                     }
   281                     }
   269                 }
   282                 }
   286 
   299 
   287         case HbThemeIndexItemData::AxmlItem: // fallback, these are handled same way
   300         case HbThemeIndexItemData::AxmlItem: // fallback, these are handled same way
   288         case HbThemeIndexItemData::FxmlItem:
   301         case HbThemeIndexItemData::FxmlItem:
   289             {
   302             {
   290             // Define fileName (file extension not removed)
   303             // Define fileName (file extension not removed)
   291             itemData.itemNameHash = HbThemeIndex::hash(filename);
   304             itemData.itemNameHash = hbHash(filename);
   292 
   305 
   293             if (LockedList.contains(filename)) {
   306             if (LockedList.contains(filename)) {
   294                 itemData.flags |= HbThemeIndexItemData::Locked;
   307                 itemData.flags |= HbThemeIndexItemData::Locked;
   295                 // Remove all found items from the list so that in the end we can handle with missing items.
   308                 // Remove all found items from the list so that in the end we can handle with missing items.
   296                 LockedList.removeOne(filename);
   309                 LockedList.removeOne(filename);
   340                     int startIndex = line.indexOf("var(") + 4;
   353                     int startIndex = line.indexOf("var(") + 4;
   341                     int endIndex = line.indexOf(')');
   354                     int endIndex = line.indexOf(')');
   342                     value = line.mid(startIndex, endIndex - startIndex).trimmed();
   355                     value = line.mid(startIndex, endIndex - startIndex).trimmed();
   343                 }
   356                 }
   344 
   357 
   345                 itemData.itemNameHash = HbThemeIndex::hash(name);
   358                 itemData.itemNameHash = hbHash(name);
   346                 itemData.itemType = HbThemeIndexItemData::ColorItem;
   359                 itemData.itemType = HbThemeIndexItemData::ColorItem;
   347                 bool ok = false;
   360                 bool ok = false;
   348                 itemData.colorValue = (quint32)value.toUInt(&ok, 16);   // Might cause compiler warning in 64 bit systems
   361                 itemData.colorValue = (quint32)value.toUInt(&ok, 16);   // Might cause compiler warning in 64 bit systems
   349                 appendItem(itemData, name);
   362                 appendItem(itemData, name);
   350             }
   363             }
   354         std::cout << "No " << filename.toStdString() << " in theme!\n";
   367         std::cout << "No " << filename.toStdString() << " in theme!\n";
   355     }
   368     }
   356     return;
   369     return;
   357 }
   370 }
   358 
   371 
   359 void processDir(const QDir &dir, const QString &themename, const QString targetName, bool subDir = false)
   372 void processDir(const QDir &dir, const QString &themename, const QString targetName)
   360 {
   373 {
   361     if (!subDir) {
   374     QString iconPath(dir.absolutePath()+"/icons/"+themename);
   362         IndexItems.clear();
   375     QString animationPath(dir.absolutePath()+"/animations/"+themename);
   363         AddedItems.clear();
   376     QString effectPath(dir.absolutePath()+"/effects/"+themename);
   364         MirroredList.clear();
   377 
   365         LockedList.clear();
   378     // Do the initialization
   366         createMirroredList(dir.absolutePath()+"/icons/"+themename);
   379     IndexItems.clear();
   367         createLockedList(dir.absolutePath()+"/icons/"+themename);
   380     AddedItems.clear();
   368     }
   381     MirroredList.clear();
   369 
   382     LockedList.clear();
   370     QFileInfoList entries = dir.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot);
   383     createMirroredList(iconPath);
   371     for (int i=0; i<entries.count(); i++) {
   384     createLockedList(iconPath);
   372         QFileInfo info = entries.at(i);
   385 
   373         QString file = info.absoluteFilePath();
   386     // Only check icons under scalable and pixmap folders
   374         if (info.isDir()) {
   387     QDir scalableDir(iconPath+"/scalable");
   375             // Process subdirs recursively
   388     if (scalableDir.exists()) {
   376             QDir subDir(file);
   389         QFileInfoList entries = scalableDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
   377             processDir(subDir, themename, targetName, true);
   390         for (int i=0; i<entries.count(); i++) {
   378         }
   391             QFileInfo info = entries.at(i);
   379         // Process file
       
   380         if (file.contains("/" + themename + "/", Qt::CaseInsensitive)) {
       
   381             processFile(info);
   392             processFile(info);
   382         }
   393         }
   383     }
   394     }
   384 
   395  
   385     if (!subDir) {
   396     QDir pixmapDir(iconPath+"/pixmap");
   386         // There might still be items in mirrored list (e.g. frames are not actual items, but they are still mirrored)
   397     if (pixmapDir.exists()) {
   387         // So just create empty items for the rest of mirrored items in list
   398         QFileInfoList entries = pixmapDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
   388         foreach (QString mirrored, MirroredList) {
   399         for (int i=0; i<entries.count(); i++) {
   389             HbThemeIndexItemData itemData;
   400             QFileInfo info = entries.at(i);
   390             itemData.itemNameHash = HbThemeIndex::hash(mirrored);
   401             processFile(info);
   391             itemData.flags |= HbThemeIndexItemData::Mirrorable;
   402         }
   392             appendItem(itemData, mirrored);
   403     }
   393         }
   404 
   394 
   405     QDir animationDir(animationPath);
   395         // Read application and widget color group CSS files and index their content
   406     if (animationDir.exists()) {
   396         // Temporary check
   407         QFileInfoList entries = animationDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
   397         if (QFile::exists(dir.absolutePath() + "/style/" + themename + "/variables/color/hbapplicationcolorgroup.css") &&
   408         for (int i=0; i<entries.count(); i++) {
   398             QFile::exists(dir.absolutePath() + "/style/" + themename + "/variables/color/hbwidgetcolorgroup.css")) {
   409             QFileInfo info = entries.at(i);
   399             if (verboseOn) {
   410             processFile(info);
   400                 std::cout << "Processing hbapplicationcolorgroup.css and hbwidgetcolorgroup.css";
   411         }
   401             }
   412     }
   402             indexColorVariables(dir.absolutePath() + "/style/" + themename + "/variables/color/hbapplicationcolorgroup.css");
   413 
   403             indexColorVariables(dir.absolutePath() + "/style/" + themename + "/variables/color/hbwidgetcolorgroup.css");
   414     QDir effectDir(effectPath);
   404         } else {
   415     if (effectDir.exists()) {
   405             if (verboseOn) {
   416         QFileInfoList entries = effectDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
   406                 std::cout << "Processing hbcolorgroup.css";
   417         for (int i=0; i<entries.count(); i++) {
   407             }
   418             QFileInfo info = entries.at(i);
   408             indexColorVariables(dir.absolutePath() + "/style/" + themename + "/variables/color/hbcolorgroup.css");
   419             processFile(info);
   409         }
   420         }
   410 
   421     }
   411         QDir targetDir;
   422 
   412         if (!targetDir.exists(targetName)) {
   423     // There might still be items in mirrored list (e.g. frames are not actual items, but they are still mirrored)
   413             targetDir.mkpath(targetName);
   424     // So just create empty items for the rest of mirrored items in list
   414         }
   425     foreach (QString mirrored, MirroredList) {
   415         QString filename = targetName + themename + ".themeindex";
   426         HbThemeIndexItemData itemData;
   416 
   427         itemData.itemNameHash = hbHash(mirrored);
   417         QFile::remove(filename);
   428         itemData.flags |= HbThemeIndexItemData::Mirrorable;
   418         QFile indexFile(filename);
   429         appendItem(itemData, mirrored);
   419         if (!indexFile.open(QIODevice::ReadWrite)) {
   430     }
   420             std::cout << "ERROR: could not open index file!\n";
   431 
   421             return;
   432     // Read application and widget color group CSS files and index their content
   422         }
   433     // Temporary check
   423         
   434     if (QFile::exists(dir.absolutePath() + "/style/" + themename + "/variables/color/hbapplicationcolorgroup.css") &&
   424         // Write the header in the beginning of the file
   435         QFile::exists(dir.absolutePath() + "/style/" + themename + "/variables/color/hbwidgetcolorgroup.css")) {
   425         HbThemeIndexHeaderV1 header;
       
   426         header.version = version;
       
   427         header.itemCount = IndexItems.count();
       
   428 
       
   429         if (verboseOn) {
   436         if (verboseOn) {
   430             std::cout << "============================TOTALS==============================\n";
   437             std::cout << "Processing hbapplicationcolorgroup.css and hbwidgetcolorgroup.css";
   431             std::cout << "Added " << header.itemCount << " items.\n";
   438         }
   432             std::cout << "================================================================\n";
   439         indexColorVariables(dir.absolutePath() + "/style/" + themename + "/variables/color/hbapplicationcolorgroup.css");
   433         }
   440         indexColorVariables(dir.absolutePath() + "/style/" + themename + "/variables/color/hbwidgetcolorgroup.css");
   434  
   441     } else {
   435         // Sort the list
   442         if (verboseOn) {
   436         qStableSort(IndexItems.begin(), IndexItems.end(), themeIndexItemDataLessThan);
   443             std::cout << "Processing hbcolorgroup.css";
   437          
   444         }
   438         // Write header info into the file stream
   445         indexColorVariables(dir.absolutePath() + "/style/" + themename + "/variables/color/hbcolorgroup.css");
   439         qint64 ret = indexFile.write(reinterpret_cast<const char *>(&header), sizeof(HbThemeIndexHeaderV1));
   446     }
   440         assert(ret == sizeof(HbThemeIndexHeaderV1));
   447 
   441         
   448     QDir targetDir;
   442         // Write items into the file stream
   449     if (!targetDir.exists(targetName)) {
   443         foreach(const HbThemeIndexItemData &itemData, IndexItems) {
   450         targetDir.mkpath(targetName);
   444             ret = indexFile.write(reinterpret_cast<const char *>(&itemData), sizeof(HbThemeIndexItemData));
   451     }
   445             assert(ret == sizeof(HbThemeIndexItemData));
   452     QString filename = targetName + themename + ".themeindex";
   446         }
   453 
   447         
   454     QFile::remove(filename);
   448         indexFile.close();
   455     QFile indexFile(filename);
   449     }
   456     if (!indexFile.open(QIODevice::ReadWrite)) {
       
   457         std::cout << "ERROR: could not open index file!\n";
       
   458         return;
       
   459     }
       
   460     
       
   461     // Write the header in the beginning of the file
       
   462     HbThemeIndexHeaderV1 header;
       
   463     header.version = version;
       
   464     header.itemCount = IndexItems.count();
       
   465 
       
   466     if (verboseOn) {
       
   467         std::cout << "============================TOTALS==============================\n";
       
   468         std::cout << "Added " << header.itemCount << " items.\n";
       
   469         std::cout << "================================================================\n";
       
   470     }
       
   471 
       
   472     // Sort the list
       
   473     qStableSort(IndexItems.begin(), IndexItems.end(), themeIndexItemDataLessThan);
       
   474      
       
   475     // Write header info into the file stream
       
   476     qint64 ret = indexFile.write(reinterpret_cast<const char *>(&header), sizeof(HbThemeIndexHeaderV1));
       
   477     assert(ret == sizeof(HbThemeIndexHeaderV1));
       
   478     
       
   479     // Write items into the file stream
       
   480     foreach(const HbThemeIndexItemData &itemData, IndexItems) {
       
   481         ret = indexFile.write(reinterpret_cast<const char *>(&itemData), sizeof(HbThemeIndexItemData));
       
   482         assert(ret == sizeof(HbThemeIndexItemData));
       
   483     }
       
   484     
       
   485     indexFile.close();
   450 }
   486 }
   451 
   487 
   452 void showHelp() {
   488 void showHelp() {
   453     std::cout << "Themeindexer.exe usage:\n\n";
   489     std::cout << "Themeindexer.exe usage:\n\n";
   454     std::cout << "hbthemeindexer [-v] -f filename OR (-n themename) -s themes source directory -t theme index file target directory\n\n";
   490     std::cout << "hbthemeindexer [-v] -f filename OR (-n themename) -s themes source directory -t theme index file target directory\n\n";