tools/assistant/compat/docuparser.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/assistant/compat/docuparser.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,433 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Assistant of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "docuparser.h"
+#include "profile.h"
+
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QRegExp>
+#include <QString>
+#include <QDataStream>
+
+QT_BEGIN_NAMESPACE
+
+QDataStream &operator>>(QDataStream &s, ContentItem &ci)
+{
+    s >> ci.title;
+    s >> ci.reference;
+    s >> ci.depth;
+    return s;
+}
+
+QDataStream &operator<<(QDataStream &s, const ContentItem &ci)
+{
+    s << ci.title;
+    s << ci.reference;
+    s << ci.depth;
+    return s;
+}
+
+const QString DocuParser::DocumentKey = QLatin1String("/Qt Assistant/") + QLatin1String(QT_VERSION_STR) + QLatin1String("/");
+
+DocuParser *DocuParser::createParser(const QString &fileName)
+{
+    QFile file(fileName);
+    if(!file.open(QFile::ReadOnly)) {
+        return 0;
+    }
+
+    QString str;
+    int maxlen = 1024;
+    int majVer = 0, minVer = 0, serVer = 0;
+    static QRegExp re(QLatin1String("assistantconfig +version=\"(\\d)\\.(\\d)\\.(\\d)\""), Qt::CaseInsensitive);
+    Q_ASSERT(re.isValid());
+    while(!(str = QLatin1String(file.readLine(maxlen))).isEmpty()) {
+        if(re.indexIn(str) >= 0) {
+            majVer = re.cap(1).toInt();
+            minVer = re.cap(2).toInt();
+            serVer = re.cap(3).toInt();
+            break;
+        }
+    }
+
+    if (majVer < 3 || (majVer == 3 && minVer < 2)) {
+        return new DocuParser310;
+    }
+
+    return new DocuParser320;
+}
+
+
+bool DocuParser::parse(QFile *file)
+{
+    QXmlInputSource source(file);
+    QXmlSimpleReader reader;
+    reader.setContentHandler(this);
+    reader.setErrorHandler(this);
+    setFileName(QFileInfo(*file).absoluteFilePath());
+    return reader.parse(source);
+}
+
+
+QString DocuParser::errorProtocol() const
+{
+    return errorProt;
+}
+
+
+QList<ContentItem> DocuParser::getContentItems()
+{
+    return contentList;
+}
+
+
+QList<IndexItem*> DocuParser::getIndexItems()
+{
+    return indexList;
+}
+
+QString DocuParser::absolutify(const QString &name, bool makeUrl) const
+{
+    if (!name.isEmpty()) {
+        QString s = name;
+        s.replace(QLatin1String("\\"), QLatin1String("/"));
+        QFileInfo orgPath(name);
+        if(orgPath.isRelative())
+            s = QFileInfo(fname).path() + QLatin1Char('/') + name;
+        if (makeUrl)
+            s.prepend(QLatin1String("file:"));
+        return s;
+    }
+    return name;
+}
+
+
+void DocuParser310::addTo(Profile *p)
+{
+    p->addDCFTitle(fname, docTitle);
+    p->addDCFIcon(docTitle, iconName);
+    p->addDCFIndexPage(docTitle, conURL);
+}
+
+
+bool DocuParser310::startDocument()
+{
+    state = StateInit;
+    errorProt = QLatin1String("");
+
+    contentRef = QLatin1String("");
+    indexRef = QLatin1String("");
+    depth = 0;
+
+    contentList.clear();
+    qDeleteAll(indexList);
+    indexList.clear();
+
+    return true;
+}
+
+
+bool DocuParser310::startElement(const QString &, const QString &,
+                               const QString &qname,
+                               const QXmlAttributes &attr)
+{
+    if (qname == QLatin1String("DCF") && state == StateInit) {
+        state = StateContent;
+        contentRef = absolutify(attr.value(QLatin1String("ref")), false);
+        conURL = contentRef;
+        docTitle = attr.value(QLatin1String("title"));
+        iconName = absolutify(attr.value(QLatin1String("icon")), false);
+        contentList.append(ContentItem(docTitle, absolutify(contentRef), depth));
+    } else if (qname == QLatin1String("section") && (state == StateContent || state == StateSect)) {
+        state = StateSect;
+        contentRef = absolutify(attr.value(QLatin1String("ref")));
+        title = attr.value(QLatin1String("title"));
+        depth++;
+        contentList.append(ContentItem(title, contentRef, depth));
+    } else if (qname == QLatin1String("keyword") && state == StateSect) {
+        state = StateKeyword;
+        indexRef = absolutify(attr.value(QLatin1String("ref")));
+    } else
+        return false;
+    return true;
+}
+
+bool DocuParser310::endElement(const QString &nameSpace, const QString &localName,
+                             const QString &qName)
+{
+    Q_UNUSED(nameSpace);
+    Q_UNUSED(localName);
+    Q_UNUSED(qName);
+
+    switch(state) {
+    case StateInit:
+        break;
+    case StateContent:
+        state = StateInit;
+        break;
+    case StateSect:
+        state = --depth ? StateSect : StateContent;
+        break;
+    case StateKeyword:
+        state = StateSect;
+        break;
+    default:
+        break;
+    }
+    return true;
+}
+
+
+bool DocuParser310::characters(const QString& ch)
+{
+    QString str = ch.simplified();
+    if (str.isEmpty())
+        return true;
+
+    switch (state) {
+        case StateInit:
+        case StateContent:
+        case StateSect:
+            return false;
+            break;
+        case StateKeyword:
+            indexList.append(new IndexItem(str, indexRef));
+            break;
+        default:
+            return false;
+    }
+    return true;
+}
+
+
+bool DocuParser310::fatalError(const QXmlParseException& exception)
+{
+    errorProt += QString::fromLatin1("fatal parsing error: %1 in line %2, column %3\n")
+        .arg(exception.message())
+        .arg(exception.lineNumber())
+        .arg(exception.columnNumber());
+
+    return QXmlDefaultHandler::fatalError(exception);
+}
+
+
+DocuParser320::DocuParser320()
+    : prof(new Profile)
+{
+}
+
+
+void DocuParser320::addTo(Profile *p)
+{
+    QMap<QString,QString>::ConstIterator it;
+
+    for (it = prof->dcfTitles.constBegin(); it != prof->dcfTitles.constEnd(); ++it)
+        p->dcfTitles[it.key()] = *it;
+
+    for (it = prof->icons.constBegin(); it != prof->icons.constEnd(); ++it)
+        p->icons[it.key()] = *it;
+
+    for (it = prof->indexPages.constBegin(); it != prof->indexPages.constEnd(); ++it)
+        p->indexPages[it.key()] = *it;
+}
+
+
+bool DocuParser320::startDocument()
+{
+    state = StateInit;
+    errorProt = QLatin1String("");
+
+    contentRef = QLatin1String("");
+    indexRef = QLatin1String("");
+    depth = 0;
+    contentList.clear();
+    indexList.clear();
+
+    prof->addDCF(fname);
+
+    return true;
+}
+
+bool DocuParser320::startElement(const QString &, const QString &,
+                               const QString &qname,
+                               const QXmlAttributes &attr)
+{
+    QString lower = qname.toLower();
+
+    switch(state) {
+
+    case StateInit:
+        if(lower == QLatin1String("assistantconfig"))
+            state = StateDocRoot;
+        break;
+
+    case StateDocRoot:
+        if(lower == QLatin1String("dcf")) {
+            state = StateContent;
+            contentRef = absolutify(attr.value(QLatin1String("ref")));
+            conURL = contentRef;
+            docTitle = attr.value(QLatin1String("title"));
+            iconName = absolutify(attr.value(QLatin1String("icon")));
+            contentList.append(ContentItem(docTitle, contentRef, depth));
+        } else if(lower == QLatin1String("profile")) {
+            state = StateProfile;
+        }
+        break;
+
+    case StateSect:
+        if (lower == QLatin1String("keyword") && state == StateSect) {
+            state = StateKeyword;
+            indexRef = absolutify(attr.value(QLatin1String("ref")));
+            break;
+        } // else if (lower == "section")
+    case StateContent:
+        if(lower == QLatin1String("section")) {
+            state = StateSect;
+            contentRef = absolutify(attr.value(QLatin1String("ref")));
+            title = attr.value(QLatin1String("title"));
+            depth++;
+            contentList.append(ContentItem(title, contentRef, depth));
+        }
+        break;
+
+    case StateProfile:
+        if(lower == QLatin1String("property")) {
+            state = StateProperty;
+            propertyName = attr.value(QLatin1String("name"));
+        }
+        break;
+
+    case StateProperty:
+        break;
+
+    default:
+        break;
+    }
+
+    return true;
+}
+
+bool DocuParser320::endElement(const QString &nameSpace,
+                                const QString &localName,
+                                const QString &qName)
+{
+    Q_UNUSED(nameSpace);
+    Q_UNUSED(localName);
+    Q_UNUSED(qName);
+
+    switch(state) {
+    case StateInit:
+        break;
+    case StateDocRoot:
+        state = StateInit;
+        break;
+    case StateProfile:
+        state = StateDocRoot;
+        break;
+    case StateProperty:
+        state = StateProfile;
+        if(propertyName.isEmpty() || propertyValue.isEmpty())
+            return false;
+        {
+            static const QStringList lst = QStringList()
+                << QLatin1String("startpage") << QLatin1String("abouturl")
+                << QLatin1String("applicationicon") << QLatin1String("assistantdocs");
+
+            if (lst.contains(propertyName))
+                propertyValue = absolutify(propertyValue);
+        }
+        prof->addProperty(propertyName, propertyValue);
+        break;
+    case StateContent:
+        if(!iconName.isEmpty())
+            prof->addDCFIcon(docTitle, iconName);
+        if(contentRef.isEmpty())
+            return false;
+        prof->addDCFIndexPage(docTitle, conURL);
+        prof->addDCFTitle(fname, docTitle);
+        state = StateDocRoot;
+        break;
+    case StateSect:
+        state = --depth ? StateSect : StateContent;
+        break;
+    case StateKeyword:
+        state = StateSect;
+        break;
+    }
+    return true;
+}
+
+bool DocuParser320::characters(const QString& ch)
+{
+    QString str = ch.simplified();
+    if (str.isEmpty())
+        return true;
+
+    switch (state) {
+    case StateInit:
+    case StateContent:
+    case StateSect:
+        return false;
+        break;
+    case StateKeyword:
+        indexList.append(new IndexItem(str, indexRef));
+        break;
+    case StateProperty:
+        propertyValue = ch;
+        break;
+    default:
+        return false;
+    }
+    return true;
+}
+
+bool DocuParser320::fatalError(const QXmlParseException& exception)
+{
+    errorProt += QString::fromLatin1("fatal parsing error: %1 in line %2, column %3\n")
+        .arg(exception.message())
+        .arg(exception.lineNumber())
+        .arg(exception.columnNumber());
+    return QXmlDefaultHandler::fatalError(exception);
+}
+
+QT_END_NAMESPACE