tools/assistant/lib/qhelpgenerator.cpp
changeset 30 5dc02b23752f
parent 18 2f34d5167611
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    45 #include <math.h>
    45 #include <math.h>
    46 #include <QtCore/QFile>
    46 #include <QtCore/QFile>
    47 #include <QtCore/QFileInfo>
    47 #include <QtCore/QFileInfo>
    48 #include <QtCore/QDir>
    48 #include <QtCore/QDir>
    49 #include <QtCore/QDebug>
    49 #include <QtCore/QDebug>
       
    50 #include <QtCore/QSet>
    50 #include <QtCore/QVariant>
    51 #include <QtCore/QVariant>
    51 #include <QtCore/QDateTime>
    52 #include <QtCore/QDateTime>
    52 #include <QtCore/QTextCodec>
    53 #include <QtCore/QTextCodec>
    53 #include <QtSql/QSqlQuery>
    54 #include <QtSql/QSqlQuery>
    54 
    55 
   187     if (!openingOk) {
   188     if (!openingOk) {
   188         d->error = tr("Cannot open data base file %1!").arg(outFileName);
   189         d->error = tr("Cannot open data base file %1!").arg(outFileName);
   189         cleanupDB();
   190         cleanupDB();
   190         return false;
   191         return false;
   191     }
   192     }
       
   193 
       
   194     d->query->exec(QLatin1String("PRAGMA synchronous=OFF"));
       
   195     d->query->exec(QLatin1String("PRAGMA cache_size=3000"));
   192 
   196 
   193     addProgress(1.0);
   197     addProgress(1.0);
   194     createTables();
   198     createTables();
   195     insertFileNotFoundFile();
   199     insertFileNotFoundFile();
   196     insertMetaData(helpData->metaData());
   200     insertMetaData(helpData->metaData());
   535         } else {
   539         } else {
   536             title = fileName.mid(fileName.lastIndexOf(QLatin1Char('/')) + 1);
   540             title = fileName.mid(fileName.lastIndexOf(QLatin1Char('/')) + 1);
   537         }
   541         }
   538 
   542 
   539         int fileId = -1;
   543         int fileId = -1;
   540         if (!d->fileMap.contains(fileName)) {
   544         QMap<QString, int>::Iterator fileMapIt = d->fileMap.find(fileName);
       
   545         if (fileMapIt == d->fileMap.end()) {
   541             fileDataList.append(qCompress(data));
   546             fileDataList.append(qCompress(data));
   542 
   547 
   543             fileNameData.name = fileName;
   548             fileNameData.name = fileName;
   544             fileNameData.fileId = tableFileId;
   549             fileNameData.fileId = tableFileId;
   545             fileNameData.title = title;
   550             fileNameData.title = title;
   549             d->fileFilterMap.insert(tableFileId, filterAtts.toSet());
   554             d->fileFilterMap.insert(tableFileId, filterAtts.toSet());
   550             tmpFileFilterMap.insert(tableFileId, filterAtts.toSet());
   555             tmpFileFilterMap.insert(tableFileId, filterAtts.toSet());
   551 
   556 
   552             ++tableFileId;
   557             ++tableFileId;
   553         } else {
   558         } else {
   554             fileId = d->fileMap.value(fileName);
   559             fileId = fileMapIt.value();
       
   560             QSet<int> &fileFilterSet = d->fileFilterMap[fileId];
       
   561             QSet<int> &tmpFileFilterSet = tmpFileFilterMap[fileId];
   555             foreach (const int &filter, filterAtts) {
   562             foreach (const int &filter, filterAtts) {
   556                 if (!d->fileFilterMap.value(fileId).contains(filter)
   563                 if (!fileFilterSet.contains(filter)
   557                     && !tmpFileFilterMap.value(fileId).contains(filter)) {
   564                     && !tmpFileFilterSet.contains(filter)) {
   558                         d->fileFilterMap[fileId].insert(filter);
   565                     fileFilterSet.insert(filter);
   559                         tmpFileFilterMap[fileId].insert(filter);
   566                     tmpFileFilterSet.insert(filter);
   560                 }
   567                 }
   561             }
   568             }
   562         }
   569         }
   563     }
   570     }
   564 
   571 
   565     if (tmpFileFilterMap.count()) {
   572     if (!tmpFileFilterMap.isEmpty()) {
   566         d->query->exec(QLatin1String("BEGIN"));
   573         d->query->exec(QLatin1String("BEGIN"));
   567         QMap<int, QSet<int> >::const_iterator it = tmpFileFilterMap.constBegin();
   574         QMap<int, QSet<int> >::const_iterator it = tmpFileFilterMap.constBegin();
   568         while (it != tmpFileFilterMap.constEnd()) {
   575         while (it != tmpFileFilterMap.constEnd()) {
   569             QSet<int>::const_iterator si = it.value().constBegin();
   576             QSet<int>::const_iterator si = it.value().constBegin();
   570             while (si != it.value().constEnd()) {
   577             while (si != it.value().constEnd()) {
   623     QStringList idsToInsert = filterAttribs;
   630     QStringList idsToInsert = filterAttribs;
   624     QMap<QString, int> attributeMap;
   631     QMap<QString, int> attributeMap;
   625     while (d->query->next()) {
   632     while (d->query->next()) {
   626         attributeMap.insert(d->query->value(1).toString(),
   633         attributeMap.insert(d->query->value(1).toString(),
   627             d->query->value(0).toInt());
   634             d->query->value(0).toInt());
   628         if (idsToInsert.contains(d->query->value(1).toString()))
   635         idsToInsert.removeAll(d->query->value(1).toString());
   629             idsToInsert.removeAll(d->query->value(1).toString());
       
   630     }
   636     }
   631 
   637 
   632     foreach (const QString &id, idsToInsert) {
   638     foreach (const QString &id, idsToInsert) {
   633         d->query->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)"));
   639         d->query->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)"));
   634         d->query->bindValue(0, id);
   640         d->query->bindValue(0, id);
   672             return false;
   678             return false;
   673     }
   679     }
   674     return true;
   680     return true;
   675 }
   681 }
   676 
   682 
   677 bool QHelpGenerator::insertKeywords(const QList<QHelpDataIndexItem> keywords,
   683 bool QHelpGenerator::insertKeywords(const QList<QHelpDataIndexItem> &keywords,
   678                                     const QStringList &filterAttributes)
   684                                     const QStringList &filterAttributes)
   679 {
   685 {
   680     if (!d->query)
   686     if (!d->query)
   681         return false;
   687         return false;
   682 
   688 
   702     int fileId = 1;
   708     int fileId = 1;
   703     QList<int> indexFilterTable;
   709     QList<int> indexFilterTable;
   704 
   710 
   705     int i = 0;
   711     int i = 0;
   706     d->query->exec(QLatin1String("BEGIN"));
   712     d->query->exec(QLatin1String("BEGIN"));
       
   713     QSet<QString> indices;
   707     foreach (const QHelpDataIndexItem &itm, keywords) {
   714     foreach (const QHelpDataIndexItem &itm, keywords) {
       
   715 
       
   716         /*
       
   717          * Identical ids make no sense and just confuse the Assistant user,
       
   718          * so we ignore all repetitions.
       
   719          */
       
   720         if (indices.contains(itm.identifier))
       
   721             continue;
       
   722         indices.insert(itm.identifier);
       
   723 
   708         pos = itm.reference.indexOf(QLatin1Char('#'));
   724         pos = itm.reference.indexOf(QLatin1Char('#'));
   709         fileName = itm.reference.left(pos);
   725         fileName = itm.reference.left(pos);
   710         if (pos > -1)
   726         if (pos > -1)
   711             anchor = itm.reference.mid(pos+1);
   727             anchor = itm.reference.mid(pos+1);
   712         else
   728         else
   714 
   730 
   715         fName = QDir::cleanPath(fileName);
   731         fName = QDir::cleanPath(fileName);
   716         if (fName.startsWith(QLatin1String("./")))
   732         if (fName.startsWith(QLatin1String("./")))
   717             fName = fName.mid(2);
   733             fName = fName.mid(2);
   718 
   734 
   719         if (d->fileMap.contains(fName))
   735         QMap<QString, int>::ConstIterator it = d->fileMap.find(fName);
   720             fileId = d->fileMap.value(fName);
   736         if (it != d->fileMap.end())
       
   737             fileId = it.value();
   721         else
   738         else
   722             fileId = 1;
   739             fileId = 1;
   723 
   740 
   724         d->query->prepare(QLatin1String("INSERT INTO IndexTable (Name, Identifier, NamespaceId, FileId, Anchor) "
   741         d->query->prepare(QLatin1String("INSERT INTO IndexTable (Name, Identifier, NamespaceId, FileId, Anchor) "
   725             "VALUES(?, ?, ?, ?, ?)"));
   742             "VALUES(?, ?, ?, ?, ?)"));
   747         }
   764         }
   748     }
   765     }
   749     d->query->exec(QLatin1String("COMMIT"));
   766     d->query->exec(QLatin1String("COMMIT"));
   750 
   767 
   751     d->query->exec(QLatin1String("SELECT COUNT(Id) FROM IndexTable"));
   768     d->query->exec(QLatin1String("SELECT COUNT(Id) FROM IndexTable"));
   752     if (d->query->next() && d->query->value(0).toInt() >= keywords.count())
   769     if (d->query->next() && d->query->value(0).toInt() >= indices.count())
   753         return true;
   770         return true;
   754     return false;
   771     return false;
   755 }
   772 }
   756 
   773 
   757 bool QHelpGenerator::insertContents(const QByteArray &ba,
   774 bool QHelpGenerator::insertContents(const QByteArray &ba,
   822         ++it;
   839         ++it;
   823     }
   840     }
   824     return true;
   841     return true;
   825 }
   842 }
   826 
   843 
       
   844 bool QHelpGenerator::checkLinks(const QHelpDataInterface &helpData)
       
   845 {
       
   846     /*
       
   847      * Step 1: Gather the canoncal file paths of all files in the project.
       
   848      *         We use a set, because there will be a lot of look-ups.
       
   849      */
       
   850     QSet<QString> files;
       
   851     foreach (const QHelpDataFilterSection &filterSection, helpData.filterSections()) {
       
   852         foreach (const QString &file, filterSection.files()) {
       
   853             QFileInfo fileInfo(helpData.rootPath() + QDir::separator() + file);
       
   854             const QString &canonicalFileName = fileInfo.canonicalFilePath();
       
   855             if (!fileInfo.exists())
       
   856                 emit warning(tr("File '%1' does not exist.").arg(file));
       
   857             else
       
   858                 files.insert(canonicalFileName);
       
   859         }
       
   860     }
       
   861 
       
   862     /*
       
   863      * Step 2: Check the hypertext and image references of all HTML files.
       
   864      *         Note that we don't parse the files, but simply grep for the
       
   865      *         respective HTML elements. Therefore. contents that are e.g.
       
   866      *         commented out can cause false warning.
       
   867      */
       
   868     bool allLinksOk = true;
       
   869     foreach (const QString &fileName, files) {
       
   870         if (!fileName.endsWith(QLatin1String("html"))
       
   871             && !fileName.endsWith(QLatin1String("htm")))
       
   872             continue;
       
   873         QFile htmlFile(fileName);
       
   874         if (!htmlFile.open(QIODevice::ReadOnly)) {
       
   875             emit warning(tr("File '%1' cannot be opened.").arg(fileName));
       
   876             continue;
       
   877         }
       
   878         const QRegExp linkPattern(QLatin1String("<(?:a href|img src)=\"?([^#\">]+)[#\">]"));
       
   879         QTextStream stream(&htmlFile);
       
   880         const QString codec = QHelpGlobal::codecFromData(htmlFile.read(1000));
       
   881         stream.setCodec(QTextCodec::codecForName(codec.toLatin1().constData()));
       
   882         const QString &content = stream.readAll();
       
   883         QStringList invalidLinks;
       
   884         for (int pos = linkPattern.indexIn(content); pos != -1;
       
   885              pos = linkPattern.indexIn(content, pos + 1)) {
       
   886             const QString& linkedFileName = linkPattern.cap(1);
       
   887             if (linkedFileName.contains(QLatin1String("://")))
       
   888                 continue;
       
   889             const QString curDir = QFileInfo(fileName).dir().path();
       
   890             const QString &canonicalLinkedFileName =
       
   891                 QFileInfo(curDir + QDir::separator() + linkedFileName).canonicalFilePath();
       
   892             if (!files.contains(canonicalLinkedFileName)
       
   893                 && !invalidLinks.contains(canonicalLinkedFileName)) {
       
   894                 emit warning(tr("File '%1' contains an invalid link to file '%2'").
       
   895                          arg(fileName).arg(linkedFileName));
       
   896                 allLinksOk = false;
       
   897                 invalidLinks.append(canonicalLinkedFileName);
       
   898             }
       
   899         }
       
   900     }
       
   901 
       
   902     if (!allLinksOk)
       
   903         d->error = tr("Invalid links in HTML files.");
       
   904     return allLinksOk;
       
   905 }
       
   906 
   827 QT_END_NAMESPACE
   907 QT_END_NAMESPACE
       
   908