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 |
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); |
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 |