summaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
authorDaniel Molkentin <daniel.molkentin@nokia.com>2010-11-11 16:49:17 +0100
committerEike Ziller <eike.ziller@nokia.com>2011-06-29 00:31:47 +0200
commit497dd323ea550cfc9987b3ee049700986b5d8859 (patch)
treed602e654adec95d78d4f5e7ce237169641296eb5 /src/tools
parentb23aa108900e32b514e1939494c0d54fa9e75e32 (diff)
downloadqt-creator-497dd323ea550cfc9987b3ee049700986b5d8859.tar.gz
Introduce QML-based welcome screen using desktop components
Implements new XML-based format for examples, demos & tutorials Done-with: Primrose Mbanefo <ext-primrose.mbanefo@nokia.com> Change-Id: I42c0afdb419cffe5637cd4f298e828d09e0fb15a Reviewed-on: http://codereview.qt.nokia.com/840 Reviewed-by: Eike Ziller <eike.ziller@nokia.com>
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/examplesscanner/examplesscanner.pro9
-rw-r--r--src/tools/examplesscanner/helpextractor.cpp372
-rw-r--r--src/tools/examplesscanner/helpextractor.h41
-rw-r--r--src/tools/examplesscanner/main.cpp9
4 files changed, 431 insertions, 0 deletions
diff --git a/src/tools/examplesscanner/examplesscanner.pro b/src/tools/examplesscanner/examplesscanner.pro
new file mode 100644
index 0000000000..531a4aabfb
--- /dev/null
+++ b/src/tools/examplesscanner/examplesscanner.pro
@@ -0,0 +1,9 @@
+QT += declarative xml network
+CONFIG += help
+
+SOURCES += \
+ main.cpp \
+ helpextractor.cpp
+
+HEADERS += \
+ helpextractor.h
diff --git a/src/tools/examplesscanner/helpextractor.cpp b/src/tools/examplesscanner/helpextractor.cpp
new file mode 100644
index 0000000000..7fad855197
--- /dev/null
+++ b/src/tools/examplesscanner/helpextractor.cpp
@@ -0,0 +1,372 @@
+#include "helpextractor.h"
+
+#include <QtGui>
+#include <QDebug>
+
+HelpExtractor::HelpExtractor()
+{
+ initHelpEngine();
+}
+
+void HelpExtractor::initHelpEngine()
+{
+ helpRootUrl = QString("qthelp://com.trolltech.qt/qdoc/");
+ // .arg(QT_VERSION >> 16).arg((QT_VERSION >> 8) & 0xFF)
+ // .arg(QT_VERSION & 0xFF);
+
+ // Store help collection file in cache dir of assistant
+ QString cacheDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation)
+ + QLatin1String("/Trolltech/Assistant/");
+ QString helpDataFile = QString(QLatin1String("qtdemo_%1.qhc")).arg(QLatin1String(QT_VERSION_STR));
+
+ QDir dir;
+ if (!dir.exists(cacheDir))
+ dir.mkpath(cacheDir);
+
+ // Create help engine (and new
+ // helpDataFile if it does not exist):
+ helpEngine = new QHelpEngineCore(cacheDir + helpDataFile);
+ helpEngine->setupData();
+
+ QString qtDocRoot = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + QLatin1String("/qch");
+ qtDocRoot = QDir(qtDocRoot).absolutePath();
+
+ QStringList qchFiles;
+ qchFiles << QLatin1String("/qt.qch")
+ << QLatin1String("/designer.qch")
+ << QLatin1String("/linguist.qch");
+
+ QString oldDir = helpEngine->customValue(QLatin1String("docDir"), QString()).toString();
+ if (oldDir != qtDocRoot) {
+ foreach (const QString &qchFile, qchFiles)
+ helpEngine->unregisterDocumentation(QHelpEngineCore::namespaceName(qtDocRoot + qchFile));
+ }
+
+ // If the data that the engine will work
+ // on is not yet registered, do it now:
+ foreach (const QString &qchFile, qchFiles)
+ helpEngine->registerDocumentation(qtDocRoot + qchFile);
+
+ helpEngine->setCustomValue(QLatin1String("docDir"), qtDocRoot);
+}
+
+void HelpExtractor::readXmlDocument()
+{
+ contentsDoc = new QDomDocument();
+ QString errorStr;
+ int errorLine;
+ int errorColumn;
+
+ QString qtDemoPath = QLibraryInfo::location(QLibraryInfo::DemosPath) + QLatin1String("/qtdemo");
+ QFile file(qtDemoPath + "/xml/examples.xml");
+ bool statusOK = contentsDoc->setContent(&file, true, &errorStr, &errorLine, &errorColumn);
+ if (!statusOK) {
+ qDebug() << QString::fromLatin1("DOM Parser: Could not read or find the contents document. Error at line %1, column %2:\n%3")
+ .arg(errorLine).arg(errorColumn).arg(errorStr);
+ exit(-1);
+ }
+ //convertToSql(contentsDoc->documentElement());
+ convertToAggregatableXml(contentsDoc->documentElement());
+}
+
+
+void HelpExtractor::convertToAggregatableXml(const QDomElement &documentElement)
+{
+ QDomDocument outDocument;
+ QDomElement root = outDocument.createElement("instructionals");
+ QDomElement demos = outDocument.createElement("demos");
+ QDomElement examples = outDocument.createElement("examples");
+ QDomElement tutorials = outDocument.createElement("tutorials");
+ root.setAttribute("module", "Qt");
+ root.appendChild(demos);
+ root.appendChild(examples);
+ root.appendChild(tutorials);
+ outDocument.appendChild(root);
+
+ QDomNode currentNode = documentElement.firstChild();
+ QDomElement step, steps, instructional;
+ int id = 0;
+ while (!currentNode.isNull()){
+ //qDebug() << '\t' << label;
+ QDomNode sub = currentNode.firstChild();
+ while (!sub.isNull()) {
+ QDomElement element = sub.toElement();
+ readInfoAboutExample(element);
+ QString exampleName = element.attribute("name");
+ StringHash exampleInfo = info[exampleName];
+
+ // type = category - last char
+ QString category = exampleInfo["category"];
+ QString categoryName = sub.parentNode().toElement().attribute("name");
+ QString type = category;
+ type.chop(1);
+
+ QString dirName = exampleInfo["dirname"];
+
+ if (category != "tutorial" || (category == "tutorial" && category != lastCategory)) {
+ instructional = outDocument.createElement(type);
+ if (category == "tutorial" && category != lastCategory)
+ instructional.setAttribute("name", categoryName);
+ else
+ instructional.setAttribute("name", exampleName);
+ }
+
+ QString projectPath = dirName + '/' + exampleInfo["filename"] + '/' + exampleInfo["filename"];
+
+ bool qml = (exampleInfo["qml"] == "true");
+ if (qml)
+ projectPath += ".qmlproject";
+ else
+ projectPath += ".pro";
+
+
+ if (category == "tutorials")
+ {
+ if (category != lastCategory) {
+ steps = outDocument.createElement("steps");
+ instructional.appendChild(steps);
+ }
+
+ step = outDocument.createElement("step");
+ step.setAttribute("projectPath", projectPath);
+ step.setAttribute("imageUrl", getImageUrl(exampleName));
+ step.setAttribute("docUrl", resolveDocUrl(exampleName));
+ steps.appendChild(step);
+ }
+
+ instructional.setAttribute("projectPath", projectPath);
+ instructional.setAttribute("imageUrl", getImageUrl(exampleName));
+ instructional.setAttribute("docUrl", resolveDocUrl(exampleName));
+ instructional.setAttribute("difficulty", "?");
+ QDomElement description = outDocument.createElement("description");
+ QString descriptionText = loadDescription(exampleName);
+ description.appendChild(outDocument.createCDATASection(descriptionText));
+ QDomElement tags = outDocument.createElement("tags");
+ // TODO
+ QStringList tagList;
+ tagList << type << exampleInfo["filename"].split('/');
+ if (dirName != ".")
+ tagList << dirName.split('/');
+ if (qml)
+ tagList << "qml" << "qt quick";
+ QRegExp ttText("<tt>(.*)</tt>");
+ ttText.setMinimal(true); // non-greedy
+ int index = 0;
+ QStringList keywords;
+ while ((index = ttText.indexIn(descriptionText, index)) != -1) {
+ keywords << descriptionText.mid(index+4, ttText.matchedLength()-9);
+ index = index + ttText.matchedLength();
+ }
+
+ // Blacklist Checking...
+ QStringList blackList;
+ blackList << "license" << "trafikanten";
+ foreach (const QString& keyword, keywords)
+ if (!keyword.isEmpty()) {
+ bool skip = false;
+ foreach (const QString& blackListItem, blackList)
+ if (keyword.contains(blackListItem, Qt::CaseInsensitive)) {
+ skip = true;
+ break;
+ }
+ if (!skip)
+ tagList << keyword.simplified().toLower();
+ }
+
+ tags.appendChild(outDocument.createTextNode(tagList.join(",")));
+ instructional.appendChild(description);
+ instructional.appendChild(tags);
+
+ if (category != "tutorials") {
+ if (category == "demos")
+ demos.appendChild(instructional);
+ else
+ examples.appendChild(instructional);
+ } else if (lastCategory != "tutorials")
+ tutorials.appendChild(instructional);
+
+ id++;
+ sub = sub.nextSibling();
+ lastCategory = category;
+
+ }
+ currentNode = currentNode.nextSibling();
+ }
+
+
+ QFile outFile("../../../share/qtcreator/welcomescreen/examples_fallback.xml");
+
+ QByteArray xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+ xml += outDocument.toByteArray();
+ if (!outFile.open(QIODevice::WriteOnly))
+ return;
+ outFile.write(xml);
+ //qDebug() << xml;
+ outFile.close();
+
+}
+
+QString HelpExtractor::loadDescription(const QString &name)
+{
+ QByteArray ba = getHtml(name);
+ QString errorMsg;
+ int errorLine, errorColumn;
+
+ QDomDocument exampleDoc;
+ if (ba.isEmpty()) {
+ qDebug() << "No documentation found for" << name << "Is the documentation built?";
+ } else if (!exampleDoc.setContent(ba, false, &errorMsg, &errorLine, &errorColumn)) {
+ qDebug() << "Error loading documentation for " << name << ": " << errorMsg << errorLine << errorColumn;
+ }
+
+ QDomNodeList paragraphs = exampleDoc.elementsByTagName("p");
+ if (paragraphs.length() < 1)
+ qDebug() << "- ExampleContent::loadDescription(): Could not load description:"
+ << info[name]["docfile"];
+ QString description = QLatin1String("");
+ for (int p = 0; p < int(paragraphs.length()); ++p) {
+ description = extractTextFromParagraph(paragraphs.item(p));
+ if (isSummaryOf(description, name)) {
+ break;
+ }
+ }
+ return description;
+}
+
+void HelpExtractor::readInfoAboutExample(const QDomElement &example)
+{
+ QString name = example.attribute("name");
+ if (info.contains(name))
+ qWarning() << "__WARNING: HelpExtractor::readInfoAboutExample: Demo/example with name"
+ << name << "appears twice in the xml-file!__";
+
+ info[name]["filename"] = example.attribute("filename");
+ QString dirName = example.parentNode().toElement().attribute("dirname");
+ info[name]["dirname"] = dirName;
+ QString category;
+ if (dirName.startsWith("tutorials"))
+ category = "tutorials";
+ else
+ category = example.parentNode().toElement().tagName();
+
+ if (category == "category")
+ category = "examples";
+
+ info[name]["category"] = category;
+ info[name]["changedirectory"] = example.attribute("changedirectory");
+ info[name]["image"] = example.attribute("image");
+ info[name]["qml"] = example.attribute("qml");
+}
+
+QString HelpExtractor::resolveDocUrl(const QString &name)
+{
+ QString dirName = info[name]["dirname"];
+ QString category = info[name]["category"];
+ QString fileName = info[name]["filename"];
+
+ if (category == "demos")
+ return helpRootUrl + "demos-" + fileName.replace("/", "-") + ".html";
+ else
+ return helpRootUrl + dirName.replace("/", "-") + "-" + fileName + ".html";
+}
+
+
+QString HelpExtractor::resolveImageUrl(const QString &name)
+{
+ return helpRootUrl + "images/" + name;
+}
+
+QByteArray HelpExtractor::getResource(const QString &name)
+{
+ return helpEngine->fileData(name);
+}
+
+QByteArray HelpExtractor::getHtml(const QString &name)
+{
+ return getResource(resolveDocUrl(name));
+}
+
+QByteArray HelpExtractor::getImage(const QString &name)
+{
+ QString imageName = this->info[name]["image"];
+ QString category = this->info[name]["category"];
+ QString fileName = this->info[name]["filename"];
+ bool qml = (this->info[name]["qml"] == QLatin1String("true"));
+ if (qml)
+ fileName = QLatin1String("qml-") + fileName.split('/').last();
+
+ if (imageName.isEmpty()){
+ if (category == "demos")
+ imageName = fileName + "-demo.png";
+ else
+ imageName = fileName + "-example.png";
+ if ((getResource(resolveImageUrl(imageName))).isEmpty())
+ imageName = fileName + ".png";
+ if ((getResource(resolveImageUrl(imageName))).isEmpty())
+ imageName = fileName + "example.png";
+ }
+ return getResource(resolveImageUrl(imageName));
+}
+
+QString HelpExtractor::getImageUrl(const QString &name)
+{
+ QString imageName = this->info[name]["image"];
+ QString category = this->info[name]["category"];
+ QString fileName = this->info[name]["filename"];
+ bool qml = (this->info[name]["qml"] == QLatin1String("true"));
+ if (qml)
+ fileName = QLatin1String("qml-") + fileName.split('/').last();
+
+ if (imageName.isEmpty()){
+ if (category == "demos")
+ imageName = fileName + "-demo.png";
+ else
+ imageName = fileName + "-example.png";
+ if ((getResource(resolveImageUrl(imageName))).isEmpty())
+ imageName = fileName + ".png";
+ if ((getResource(resolveImageUrl(imageName))).isEmpty())
+ imageName = fileName + "example.png";
+ if ((getResource(resolveImageUrl(imageName))).isEmpty())
+ return "";
+ }
+ return resolveImageUrl(imageName);
+}
+
+QString HelpExtractor::extractTextFromParagraph(const QDomNode &parentNode)
+{
+ QString description;
+ QDomNode node = parentNode.firstChild();
+
+ while (!node.isNull()) {
+ QString beginTag;
+ QString endTag;
+ if (node.isText())
+ description += node.nodeValue();
+ else if (node.hasChildNodes()) {
+ if (node.nodeName() == "b") {
+ beginTag = "<b>";
+ endTag = "</b>";
+ } else if (node.nodeName() == "a") {
+ beginTag = "<tt>";
+ endTag = "</tt>";
+ } else if (node.nodeName() == "i") {
+ beginTag = "<i>";
+ endTag = "</i>";
+ } else if (node.nodeName() == "tt") {
+ beginTag = "<tt>";
+ endTag = "</tt>";
+ }
+ description += beginTag + extractTextFromParagraph(node) + endTag;
+ }
+ node = node.nextSibling();
+ }
+
+ return description;
+}
+
+bool HelpExtractor::isSummaryOf(const QString &text, const QString &example)
+{
+ return (!text.contains("[") &&
+ text.indexOf(QRegExp(QString("(In )?((The|This) )?(%1 )?.*(tutorial|example|demo|application)").arg(example),
+ Qt::CaseInsensitive)) != -1);
+}
diff --git a/src/tools/examplesscanner/helpextractor.h b/src/tools/examplesscanner/helpextractor.h
new file mode 100644
index 0000000000..4210a6635d
--- /dev/null
+++ b/src/tools/examplesscanner/helpextractor.h
@@ -0,0 +1,41 @@
+#ifndef HELPEXTRACTOR_H
+#define HELPEXTRACTOR_H
+
+#include <QtCore>
+#include <QtXml>
+#include <QtHelp>
+
+typedef QHash<QString, QString> StringHash;
+typedef QHash<QString, StringHash> HashHash;
+
+class HelpExtractor
+{
+public:
+ HelpExtractor();
+ void readXmlDocument();
+
+private:
+ void initHelpEngine();
+ void convertToAggregatableXml(const QDomElement &documentElement);
+ QByteArray getResource(const QString &name);
+ QByteArray getHtml(const QString &name);
+ QByteArray getImage(const QString &name);
+ QString getImageUrl(const QString &name);
+ QString resolveDocUrl(const QString &name);
+ QString resolveImageUrl(const QString &name);
+ QString loadDescription(const QString &name);
+ void readInfoAboutExample(const QDomElement &example);
+ QString extractTextFromParagraph(const QDomNode &parentNode);
+ bool isSummaryOf(const QString &text, const QString &example);
+
+ HashHash info;
+ QHelpEngineCore *helpEngine;
+ QDomDocument *contentsDoc;
+ QString helpRootUrl;
+ QDir docDir;
+ QDir imgDir;
+ QString lastCategory;
+
+};
+
+#endif // HELPEXTRACTOR_H
diff --git a/src/tools/examplesscanner/main.cpp b/src/tools/examplesscanner/main.cpp
new file mode 100644
index 0000000000..5c47a9788b
--- /dev/null
+++ b/src/tools/examplesscanner/main.cpp
@@ -0,0 +1,9 @@
+#include <QtCore>
+
+#include "helpextractor.h"
+
+int main(int argc, char *argv[])
+{
+ HelpExtractor extractor;
+ extractor.readXmlDocument();
+}