tests/auto/qabstractxmlnodemodel/LoadingModel.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QFile>
       
    44 #include <QStack>
       
    45 
       
    46 #ifdef QTEST_XMLPATTERNS
       
    47 #include <QXmlNamePool>
       
    48 #include <QXmlStreamReader>
       
    49 #include <QtDebug>
       
    50 #include <QTest>
       
    51 
       
    52 #include "LoadingModel.h"
       
    53 LoadingModel::LoadingModel(const Node::Vector &content,
       
    54                            const QXmlNamePool &np) : QSimpleXmlNodeModel(np)
       
    55                                                    , m_nodes(content)
       
    56 {
       
    57     Q_ASSERT(!content.isEmpty());
       
    58     /*
       
    59     foreach(const Node *n, content)
       
    60         qDebug() << "this:" << n
       
    61                  << "kind:" << n->kind
       
    62                  << "parent: " << n->parent
       
    63                  << "preceding: " << n->precedingSibling
       
    64                  << "following: " << n->followingSibling
       
    65                  << "firstChild: " << n->firstChild
       
    66                  << "value: " << n->value;
       
    67                  */
       
    68 }
       
    69 
       
    70 LoadingModel::~LoadingModel()
       
    71 {
       
    72      qDeleteAll(m_nodes);
       
    73 }
       
    74 
       
    75 const LoadingModel::Node *LoadingModel::toInternal(const QXmlNodeModelIndex &ni) const
       
    76 {
       
    77     return static_cast<const Node *>(ni.internalPointer());
       
    78 }
       
    79 
       
    80 QXmlNodeModelIndex LoadingModel::createIndex(const Node *const internal) const
       
    81 {
       
    82     Q_ASSERT_X(internal, Q_FUNC_INFO,
       
    83                "We shouldn't construct from null pointers.");
       
    84     return QAbstractXmlNodeModel::createIndex(const_cast<Node *>(internal));
       
    85 }
       
    86 
       
    87 QUrl LoadingModel::documentUri(const QXmlNodeModelIndex &) const
       
    88 {
       
    89     Q_ASSERT(false);
       
    90     return QUrl();
       
    91 }
       
    92 
       
    93 QXmlNodeModelIndex::NodeKind LoadingModel::kind(const QXmlNodeModelIndex &ni) const
       
    94 {
       
    95     Q_ASSERT(!ni.isNull());
       
    96     return toInternal(ni)->kind;
       
    97 }
       
    98 
       
    99 QXmlNodeModelIndex::DocumentOrder LoadingModel::compareOrder(const QXmlNodeModelIndex &n1, const QXmlNodeModelIndex &n2) const
       
   100 {
       
   101     const Node *const in1 = toInternal(n1);
       
   102     const Node *const in2 = toInternal(n2);
       
   103     Q_ASSERT(m_nodes.indexOf(in1) != -1);
       
   104     Q_ASSERT(m_nodes.indexOf(in2) != -1);
       
   105 
       
   106     if(in1 == in2)
       
   107         return QXmlNodeModelIndex::Is;
       
   108     else if(m_nodes.indexOf(in1) < m_nodes.indexOf(in2))
       
   109         return QXmlNodeModelIndex::Precedes;
       
   110     else
       
   111         return QXmlNodeModelIndex::Follows;
       
   112 }
       
   113 
       
   114 QXmlNodeModelIndex LoadingModel::root(const QXmlNodeModelIndex &) const
       
   115 {
       
   116     Q_ASSERT(kind(createIndex(m_nodes.first())) == QXmlNodeModelIndex::Document);
       
   117     return createIndex(m_nodes.first());
       
   118 }
       
   119 
       
   120 QXmlName LoadingModel::name(const QXmlNodeModelIndex &ni) const
       
   121 {
       
   122     return toInternal(ni)->name;
       
   123 }
       
   124 
       
   125 QVariant LoadingModel::typedValue(const QXmlNodeModelIndex &ni) const
       
   126 {
       
   127     const Node *const internal = toInternal(ni);
       
   128 
       
   129     Q_ASSERT(internal->kind == QXmlNodeModelIndex::Attribute
       
   130              || internal->kind == QXmlNodeModelIndex::Element);
       
   131 
       
   132     return internal->value;
       
   133 }
       
   134 
       
   135 QString LoadingModel::stringValue(const QXmlNodeModelIndex &ni) const
       
   136 {
       
   137     const Node *const internal = toInternal(ni);
       
   138 
       
   139     switch(internal->kind)
       
   140     {
       
   141         case QXmlNodeModelIndex::Text:
       
   142         /* Fallthrough. */
       
   143         case QXmlNodeModelIndex::ProcessingInstruction:
       
   144         /* Fallthrough. */
       
   145         case QXmlNodeModelIndex::Comment:
       
   146         /* Fallthrough. */
       
   147         case QXmlNodeModelIndex::Attribute:
       
   148             return internal->value;
       
   149         default:
       
   150             return QString();
       
   151     }
       
   152 }
       
   153 
       
   154 QXmlNodeModelIndex LoadingModel::nextFromSimpleAxis(QAbstractXmlNodeModel::SimpleAxis axis,
       
   155                                                     const QXmlNodeModelIndex &ni) const
       
   156 {
       
   157     const Node *const internal = toInternal(ni);
       
   158 
       
   159     /* Note that a QXmlNodeModelIndex containing a null pointer is not a null node. */
       
   160     switch(axis)
       
   161     {
       
   162         case Parent:
       
   163             return internal->parent ? createIndex(internal->parent) : QXmlNodeModelIndex();
       
   164         case FirstChild:
       
   165             return internal->firstChild ? createIndex(internal->firstChild) : QXmlNodeModelIndex();
       
   166         case PreviousSibling:
       
   167             return internal->precedingSibling ? createIndex(internal->precedingSibling) : QXmlNodeModelIndex();
       
   168         case NextSibling:
       
   169             return internal->followingSibling ? createIndex(internal->followingSibling) : QXmlNodeModelIndex();
       
   170     }
       
   171 
       
   172     Q_ASSERT(false);
       
   173     return QXmlNodeModelIndex();
       
   174 }
       
   175 
       
   176 QVector<QXmlNodeModelIndex> LoadingModel::attributes(const QXmlNodeModelIndex &ni) const
       
   177 {
       
   178     QVector<QXmlNodeModelIndex> retval;
       
   179     foreach(const Node *n, toInternal(ni)->attributes)
       
   180         retval.append(createIndex(n));
       
   181 
       
   182     return retval;
       
   183 }
       
   184 
       
   185 class Loader
       
   186 {
       
   187 public:
       
   188     inline Loader(const QXmlNamePool &namePool) : m_namePool(namePool)
       
   189                                                 , m_currentNode(0)
       
   190     {
       
   191         m_parentStack.push(0);
       
   192     }
       
   193 
       
   194 private:
       
   195     inline void adjustSiblings(LoadingModel::Node *const justBorn);
       
   196     friend class LoadingModel;
       
   197     Q_DISABLE_COPY(Loader);
       
   198 
       
   199     void load();
       
   200 
       
   201     QXmlNamePool                        m_namePool;
       
   202     QXmlStreamReader                    m_reader;
       
   203     LoadingModel::Node::Vector          m_result;
       
   204     LoadingModel::Node *                m_currentNode;
       
   205     QStack<LoadingModel::Node *>        m_parentStack;
       
   206 };
       
   207 
       
   208 inline void Loader::adjustSiblings(LoadingModel::Node *const justBorn)
       
   209 {
       
   210     if(m_currentNode)
       
   211     {
       
   212         if(m_currentNode->parent == justBorn->parent)
       
   213             justBorn->precedingSibling = m_currentNode;
       
   214 
       
   215         m_currentNode->followingSibling = justBorn;
       
   216     }
       
   217 
       
   218     m_currentNode = justBorn;
       
   219 
       
   220     /* Otherwise we're the first child, and our precedingSibling should remain null. */
       
   221 
       
   222     if(m_parentStack.top() && !m_parentStack.top()->firstChild)
       
   223         m_parentStack.top()->firstChild = justBorn;
       
   224 }
       
   225 
       
   226 void Loader::load()
       
   227 {
       
   228     QFile in(QLatin1String("tree.xml"));
       
   229 
       
   230     /* LoadingModel::m_result will be null, signalling failure. */
       
   231     if(!in.open(QIODevice::ReadOnly))
       
   232         return;
       
   233 
       
   234     QXmlStreamReader reader(&in);
       
   235     while(!reader.atEnd())
       
   236     {
       
   237         reader.readNext();
       
   238 
       
   239         switch(reader.tokenType())
       
   240         {
       
   241             case QXmlStreamReader::StartDocument:
       
   242             /* Fallthrough. */
       
   243             case QXmlStreamReader::StartElement:
       
   244             {
       
   245                 QXmlName name;
       
   246                 if(reader.tokenType() == QXmlStreamReader::StartElement)
       
   247                 {
       
   248                     name = QXmlName(m_namePool,
       
   249                                     reader.name().toString(),
       
   250                                     reader.namespaceUri().toString(),
       
   251                                     reader.prefix().toString());
       
   252                 }
       
   253                 /* Else, the name is null. */
       
   254 
       
   255                 LoadingModel::Node *const tmp = new LoadingModel::Node(reader.tokenType() == QXmlStreamReader::StartElement
       
   256                                                                        ? QXmlNodeModelIndex::Element
       
   257                                                                        : QXmlNodeModelIndex::Document,
       
   258                                                                        m_parentStack.top(),
       
   259                                                                        QString(),
       
   260                                                                        name);
       
   261                 m_result.append(tmp);
       
   262 
       
   263                 if(m_currentNode)
       
   264                 {
       
   265                     if(m_currentNode->parent == m_parentStack.top())
       
   266                         m_currentNode->followingSibling = tmp;
       
   267                 }
       
   268 
       
   269                 const QXmlStreamAttributes attributes(reader.attributes());
       
   270                 const int len = attributes.count();
       
   271 
       
   272                 for(int i = 0; i < len; ++i)
       
   273                 {
       
   274                     const QXmlStreamAttribute &attr = attributes.at(i);
       
   275                     const LoadingModel::Node *const a = new LoadingModel::Node(QXmlNodeModelIndex::Attribute,
       
   276                                                                                m_parentStack.top(),
       
   277                                                                                attr.value().toString(),
       
   278                                                                                QXmlName(m_namePool,
       
   279                                                                                        attr.name().toString(),
       
   280                                                                                        attr.namespaceUri().toString(),
       
   281                                                                                        attr.prefix().toString()));
       
   282                     /* We add it also to m_result such that compareOrder() is correct
       
   283                      * for attributes. m_result owns a. */
       
   284                     tmp->attributes.append(a);
       
   285                     m_result.append(a);
       
   286                 }
       
   287 
       
   288                 adjustSiblings(tmp);
       
   289                 m_parentStack.push(m_currentNode);
       
   290                 break;
       
   291             }
       
   292             case QXmlStreamReader::EndDocument:
       
   293             /* Fallthrough. */
       
   294             case QXmlStreamReader::EndElement:
       
   295             {
       
   296                 m_currentNode->followingSibling = 0;
       
   297                 m_currentNode = m_parentStack.pop();
       
   298 
       
   299                 if(reader.tokenType() == QXmlStreamReader::EndDocument)
       
   300                     const_cast<LoadingModel::Node *>(m_result.first())->followingSibling = 0;
       
   301 
       
   302                 break;
       
   303             }
       
   304             case QXmlStreamReader::Characters:
       
   305             {
       
   306                 LoadingModel::Node *const tmp = new LoadingModel::Node(QXmlNodeModelIndex::Text, m_parentStack.top(), reader.text().toString());
       
   307                 m_result.append(tmp);
       
   308                 adjustSiblings(tmp);
       
   309                 break;
       
   310             }
       
   311             case QXmlStreamReader::ProcessingInstruction:
       
   312             {
       
   313                 LoadingModel::Node *const tmp = new LoadingModel::Node(QXmlNodeModelIndex::ProcessingInstruction,
       
   314                                                                        m_parentStack.top(),
       
   315                                                                        reader.processingInstructionData().toString(),
       
   316                                                                        QXmlName(m_namePool, reader.processingInstructionTarget().toString()));
       
   317                 m_result.append(tmp);
       
   318                 adjustSiblings(tmp);
       
   319                 break;
       
   320             }
       
   321             case QXmlStreamReader::Comment:
       
   322             {
       
   323                 LoadingModel::Node *const tmp = new LoadingModel::Node(QXmlNodeModelIndex::Comment, m_parentStack.top(), reader.text().toString());
       
   324                 m_result.append(tmp);
       
   325                 adjustSiblings(tmp);
       
   326                 break;
       
   327             }
       
   328             case QXmlStreamReader::DTD:
       
   329             /* Fallthrough. */
       
   330             case QXmlStreamReader::EntityReference:
       
   331             {
       
   332                 Q_ASSERT_X(false, Q_FUNC_INFO,
       
   333                            "We don't support this.");
       
   334                 /* Fallthrough. */
       
   335             }
       
   336             case QXmlStreamReader::NoToken:
       
   337             /* Fallthrough. */
       
   338             case QXmlStreamReader::Invalid:
       
   339             {
       
   340                 qWarning(qPrintable(reader.errorString()));
       
   341                 m_result.clear();
       
   342                 return;
       
   343             }
       
   344         }
       
   345     }
       
   346 
       
   347     if(reader.hasError())
       
   348     {
       
   349         qWarning(qPrintable(reader.errorString()));
       
   350         m_result.clear();
       
   351     }
       
   352 }
       
   353 
       
   354 QAbstractXmlNodeModel::Ptr LoadingModel::create(const QXmlNamePool &np)
       
   355 {
       
   356     Loader loader(np);
       
   357     loader.load();
       
   358     return Ptr(new LoadingModel(loader.m_result, np));
       
   359 }
       
   360 #endif //QTEST_XMLPATTERNS