Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/tools/qdoc3/generator.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the tools applications of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     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.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4343  generator.cpp
    4444*/
    45 
     45#include <QtCore>
    4646#include <qdir.h>
    47 
     47#include <qdebug.h>
    4848#include "codemarker.h"
    4949#include "config.h"
     
    6666QStringList Generator::imageFiles;
    6767QStringList Generator::imageDirs;
     68QStringList Generator::exampleDirs;
     69QStringList Generator::exampleImgExts;
    6870QString Generator::outDir;
    6971QString Generator::project;
    7072
    71 static Text stockLink(const QString &target)
    72 {
    73     return Text() << Atom(Atom::Link, target) << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
    74                   << target << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
     73static void singularPlural(Text& text, const NodeList& nodes)
     74{
     75    if (nodes.count() == 1)
     76        text << " is";
     77    else
     78        text << " are";
    7579}
    7680
    7781Generator::Generator()
    78     : amp("&amp;"), lt("&lt;"), gt("&gt;"), quot("&quot;"), tag("</?@[^>]*>")
     82    : amp("&amp;"),
     83      lt("&lt;"),
     84      gt("&gt;"),
     85      quot("&quot;"),
     86      tag("</?@[^>]*>")
    7987{
    8088    generators.prepend(this);
     
    115123            config.lastLocation().fatal(tr("Cannot create output directory '%1'")
    116124                                        .arg(outDir + "/images"));
     125        if (!dirInfo.mkdir(outDir + "/images/used-in-examples"))
     126            config.lastLocation().fatal(tr("Cannot create output directory '%1'")
     127                                        .arg(outDir + "/images/used-in-examples"));
    117128    }
    118129
    119130    imageFiles = config.getStringList(CONFIG_IMAGES);
    120131    imageDirs = config.getStringList(CONFIG_IMAGEDIRS);
    121 
    122     QString imagesDotFileExtensions = CONFIG_IMAGES + Config::dot + CONFIG_FILEEXTENSIONS;
     132    exampleDirs = config.getStringList(CONFIG_EXAMPLEDIRS);
     133    exampleImgExts = config.getStringList(CONFIG_EXAMPLES + Config::dot +
     134                                          CONFIG_IMAGEEXTENSIONS);
     135
     136    QString imagesDotFileExtensions =
     137        CONFIG_IMAGES + Config::dot + CONFIG_FILEEXTENSIONS;
    123138    QSet<QString> formats = config.subVars(imagesDotFileExtensions);
    124139    QSet<QString>::ConstIterator f = formats.begin();
    125140    while (f != formats.end()) {
    126         imgFileExts[*f] = config.getStringList(imagesDotFileExtensions + Config::dot + *f);
     141        imgFileExts[*f] = config.getStringList(imagesDotFileExtensions +
     142                                               Config::dot + *f);
    127143        ++f;
    128144    }
     
    132148        if (outputFormats.contains((*g)->format())) {
    133149            (*g)->initializeGenerator(config);
    134             QStringList extraImages = config.getStringList(CONFIG_EXTRAIMAGES + Config::dot
    135                                                            + (*g)->format());
     150            QStringList extraImages =
     151                config.getStringList(CONFIG_EXTRAIMAGES+Config::dot+(*g)->format());
    136152            QStringList::ConstIterator e = extraImages.begin();
    137153            while (e != extraImages.end()) {
    138154                QString userFriendlyFilePath;
    139                 QString filePath = Config::findFile(config.lastLocation(), imageFiles, imageDirs, *e,
    140                                                     imgFileExts[(*g)->format()], userFriendlyFilePath);
     155                QString filePath = Config::findFile(config.lastLocation(),
     156                                                    imageFiles,
     157                                                    imageDirs,
     158                                                    *e,
     159                                                    imgFileExts[(*g)->format()],
     160                                                    userFriendlyFilePath);
    141161                if (!filePath.isEmpty())
    142                     Config::copyFile(config.lastLocation(), filePath, userFriendlyFilePath,
    143                                          (*g)->outputDir() + "/images");
     162                    Config::copyFile(config.lastLocation(),
     163                                     filePath,
     164                                     userFriendlyFilePath,
     165                                     (*g)->outputDir() +
     166                                     "/images");
    144167                ++e;
    145168            }
     
    157180        QSet<QString>::ConstIterator f = formats.begin();
    158181        while (f != formats.end()) {
    159             QString def = config.getString(formattingDotName + Config::dot +
    160                                             *f);
     182            QString def = config.getString(formattingDotName +
     183                                           Config::dot + *f);
    161184            if (!def.isEmpty()) {
    162185                int numParams = Config::numParams(def);
     
    164187
    165188                if (numParams != 1) {
    166                     config.lastLocation().warning(tr("Formatting '%1' must have exactly one"
    167                                                      " parameter (found %2)")
    168                                                  .arg(*n).arg(numParams));
     189                    config.lastLocation().warning(tr("Formatting '%1' must "
     190                                                     "have exactly one "
     191                                                     "parameter (found %2)")
     192                                                  .arg(*n).arg(numParams));
    169193                }
    170194                else if (numOccs > 1) {
    171                     config.lastLocation().fatal(tr("Formatting '%1' must contain exactly one"
    172                                                     " occurrence of '\\1' (found %2)")
     195                    config.lastLocation().fatal(tr("Formatting '%1' must "
     196                                                   "contain exactly one "
     197                                                   "occurrence of '\\1' "
     198                                                   "(found %2)")
    173199                                                .arg(*n).arg(numOccs));
    174200                }
     
    242268}
    243269
    244 void Generator::generateText(const Text& text,
     270bool Generator::generateText(const Text& text,
    245271                             const Node *relative,
    246272                             CodeMarker *marker)
     
    255281                         numAtoms);
    256282        endText(relative, marker);
    257     }
     283        return true;
     284    }
     285    return false;
    258286}
    259287
    260288#ifdef QDOC_QML
    261 void Generator::generateQmlText(const Text& text,
     289/*!
     290  Extract sections of markup text surrounded by \e qmltext
     291  and \e endqmltext and output them.
     292 */
     293bool Generator::generateQmlText(const Text& text,
    262294                                const Node *relative,
    263                                 CodeMarker *marker)
    264 {
    265     if (text.firstAtom() != 0) {
    266         startText(relative, marker);
    267         const Atom *atom = text.firstAtom();
    268         while (atom) {
    269             if (atom->type() != Atom::QmlText)
    270                 atom = atom->next();
    271             else {
    272                 atom = atom->next();
    273                 while (atom && (atom->type() != Atom::EndQmlText)) {
    274                     int n = 1 + generateAtom(atom, relative, marker);
    275                     while (n-- > 0)
    276                         atom = atom->next();
    277                 }
    278             }
    279         }
    280         endText(relative, marker);
    281     }
     295                                CodeMarker *marker,
     296                                const QString& /* qmlName */ )
     297{
     298    const Atom* atom = text.firstAtom();
     299    if (atom == 0)
     300        return false;
     301
     302    startText(relative, marker);
     303    while (atom) {
     304        if (atom->type() != Atom::QmlText)
     305            atom = atom->next();
     306        else {
     307            atom = atom->next();
     308            while (atom && (atom->type() != Atom::EndQmlText)) {
     309                int n = 1 + generateAtom(atom, relative, marker);
     310                while (n-- > 0)
     311                    atom = atom->next();
     312            }
     313        }
     314    }
     315    endText(relative, marker);
     316    return true;
    282317}
    283318#endif
     
    296331    else if (node->type() == Node::Fake) {
    297332        const FakeNode *fake = static_cast<const FakeNode *>(node);
    298         if (fake->subType() == FakeNode::Example)
     333        if (fake->subType() == Node::Example)
    299334            generateExampleFiles(fake, marker);
    300         else if (fake->subType() == FakeNode::File)
     335        else if ((fake->subType() == Node::File) || (fake->subType() == Node::Image))
    301336            quiet = true;
    302337    }
    303338
    304339    if (node->doc().isEmpty()) {
    305         if (!quiet) // ### might be unnecessary
     340        if (!quiet && !node->isReimp()) // ### might be unnecessary
    306341            node->location().warning(tr("No documentation for '%1'")
    307342                            .arg(marker->plainFullName(node)));
    308343    }
    309344    else {
    310         generateText(node->doc().body(), node, marker);
     345        if (node->type() == Node::Function) {
     346            const FunctionNode *func = static_cast<const FunctionNode *>(node);
     347            if (func->reimplementedFrom() != 0)
     348                generateReimplementedFrom(func, marker);
     349        }
     350       
     351        if (!generateText(node->doc().body(), node, marker))
     352            if (node->isReimp())
     353                return;
    311354
    312355        if (node->type() == Node::Enum) {
     
    346389        else if (node->type() == Node::Function) {
    347390            const FunctionNode *func = static_cast<const FunctionNode *>(node);
    348 
    349391            QSet<QString> definedParams;
    350392            QList<Parameter>::ConstIterator p = func->parameters().begin();
     
    383425                                    func->parent()->findFunctionNode(func->name());
    384426                            if (primaryFunc) {
    385                                 foreach (const Parameter &param, primaryFunc->parameters()) {
     427                                foreach (const Parameter &param,
     428                                         primaryFunc->parameters()) {
    386429                                    if (param.name() == *a) {
    387430                                        needWarning = false;
     
    391434                            }
    392435                        }
    393                         if (needWarning)
     436                        if (needWarning && !func->isReimp())
    394437                            node->doc().location().warning(
    395                                 tr("Undocumented parameter '%1' in %2").arg(*a).arg(marker->plainFullName(node)));
     438                                tr("Undocumented parameter '%1' in %2")
     439                                .arg(*a).arg(marker->plainFullName(node)));
    396440                    }
    397441                    ++a;
     
    405449                    node->doc().location().warning(tr("Undocumented return value"));
    406450            }
    407 
     451#if 0
     452            // Now we put this at the top, before the other text.
    408453            if (func->reimplementedFrom() != 0)
    409454                generateReimplementedFrom(func, marker);
     455#endif           
    410456        }
    411457    }
     
    413459    if (node->type() == Node::Fake) {
    414460        const FakeNode *fake = static_cast<const FakeNode *>(node);
    415         if (fake->subType() == FakeNode::File) {
     461        if (fake->subType() == Node::File) {
    416462            Text text;
    417463            Quoter quoter;
     
    460506            if ((*r).access == Node::Protected) {
    461507                text << " (protected)";
    462             } else if ((*r).access == Node::Private) {
     508            }
     509            else if ((*r).access == Node::Private) {
    463510                text << " (private)";
    464511            }
     
    470517    }
    471518}
     519
     520#ifdef QDOC_QML
     521/*!
     522 */
     523void Generator::generateQmlInherits(const QmlClassNode* , CodeMarker* )
     524{
     525    // stub.
     526}
     527#endif
    472528
    473529void Generator::generateInheritedBy(const ClassNode *classe,
     
    484540}
    485541
     542/*!
     543  This function is called when the documentation for an
     544  example is being formatted. It outputs the list of source
     545  files comprising the example, and the list of images used
     546  by the example. The images are copied into a subtree of
     547  \c{...doc/html/images/used-in-examples/...}
     548 */
     549void Generator::generateFileList(const FakeNode* fake,
     550                                 CodeMarker* marker,
     551                                 Node::SubType subtype,
     552                                 const QString& tag)
     553{
     554    int count = 0;
     555    Text text;
     556    OpenedList openedList(OpenedList::Bullet);
     557
     558    text << Atom::ParaLeft << tag << Atom::ParaRight
     559         << Atom(Atom::ListLeft, openedList.styleString());
     560
     561    foreach (const Node* child, fake->childNodes()) {
     562        if (child->subType() == subtype) {
     563            ++count;
     564            QString file = child->name();
     565            if (subtype == Node::Image) {
     566                if (!file.isEmpty()) {
     567                    QDir dirInfo;
     568                    QString userFriendlyFilePath;
     569                    QString srcPath = Config::findFile(fake->location(),
     570                                                       QStringList(),
     571                                                       exampleDirs,
     572                                                       file,
     573                                                       exampleImgExts,
     574                                                       userFriendlyFilePath);
     575                    userFriendlyFilePath.truncate(userFriendlyFilePath.lastIndexOf('/'));
     576
     577                    QString imgOutDir = outDir + "/images/used-in-examples/" + userFriendlyFilePath;
     578                    if (!dirInfo.mkpath(imgOutDir))
     579                        fake->location().fatal(tr("Cannot create output directory '%1'")
     580                                               .arg(imgOutDir));
     581
     582                    QString imgOutName = Config::copyFile(fake->location(),
     583                                                          srcPath,
     584                                                          file,
     585                                                          imgOutDir);
     586                }
     587
     588            }
     589
     590            openedList.next();
     591            text << Atom(Atom::ListItemNumber, openedList.numberString())
     592                 << Atom(Atom::ListItemLeft, openedList.styleString())
     593                 << Atom::ParaLeft
     594                 << Atom(Atom::Link, file)
     595                 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
     596                 << file
     597                 << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
     598                 << Atom::ParaRight
     599                 << Atom(Atom::ListItemRight, openedList.styleString());
     600        }
     601    }
     602    text << Atom(Atom::ListRight, openedList.styleString());
     603    if (count > 0)
     604        generateText(text, fake, marker);
     605}
     606
    486607void Generator::generateExampleFiles(const FakeNode *fake, CodeMarker *marker)
    487608{
    488609    if (fake->childNodes().isEmpty())
    489610        return;
    490 
    491     OpenedList openedList(OpenedList::Bullet);
    492 
    493     Text text;
    494     text << Atom::ParaLeft << "Files:" << Atom::ParaRight
    495          << Atom(Atom::ListLeft, openedList.styleString());
    496     foreach (const Node *child, fake->childNodes()) {
    497         QString exampleFile = child->name();
    498         openedList.next();
    499         text << Atom(Atom::ListItemNumber, openedList.numberString())
    500              << Atom(Atom::ListItemLeft, openedList.styleString()) << Atom::ParaLeft
    501              << Atom(Atom::Link, exampleFile)
    502              << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
    503              << exampleFile
    504              << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK)
    505              << Atom::ParaRight << Atom(Atom::ListItemRight, openedList.styleString());
    506     }
    507     text << Atom(Atom::ListRight, openedList.styleString());
    508     generateText(text, fake, marker);
    509 }
    510 
    511 void Generator::generateModuleWarning(const ClassNode *classe, CodeMarker *marker)
     611    generateFileList(fake, marker, Node::File, QString("Files:"));
     612    generateFileList(fake, marker, Node::Image, QString("Images:"));
     613}
     614
     615#if 0
     616    QList<Generator *>::ConstIterator g = generators.begin();
     617    while (g != generators.end()) {
     618        if (outputFormats.contains((*g)->format())) {
     619            (*g)->initializeGenerator(config);
     620            QStringList extraImages =
     621                config.getStringList(CONFIG_EXTRAIMAGES+Config::dot+(*g)->format());
     622            QStringList::ConstIterator e = extraImages.begin();
     623            while (e != extraImages.end()) {
     624                QString userFriendlyFilePath;
     625                QString filePath = Config::findFile(config.lastLocation(),
     626                                                    imageFiles,
     627                                                    imageDirs,
     628                                                    *e,
     629                                                    imgFileExts[(*g)->format()],
     630                                                    userFriendlyFilePath);
     631                if (!filePath.isEmpty())
     632                    Config::copyFile(config.lastLocation(),
     633                                     filePath,
     634                                     userFriendlyFilePath,
     635                                     (*g)->outputDir() +
     636                                     "/images");
     637                ++e;
     638            }
     639        }
     640        ++g;
     641    }
     642#endif
     643
     644void Generator::generateModuleWarning(const ClassNode *classe,
     645                                      CodeMarker *marker)
    512646{
    513647    QString module = classe->moduleName();
    514648    if (!module.isEmpty()) {
    515649        Text text;
    516         if (Tokenizer::isTrue("defined(consoleedition)")
    517                 && !editionModuleMap["Console"].contains(module)) {
     650        if (!editionModuleMap["DesktopLight"].contains(module)) {
    518651            text << Atom::ParaLeft
    519652                 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
    520                  << "This class is not part of the Qt Console Edition."
     653                 << "This class is not part of the Qt GUI Framework Edition."
    521654                 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
    522655                 << Atom::ParaRight;
    523656        }
    524         else if (Tokenizer::isTrue("defined(desktoplightedition)")
    525                 && !editionModuleMap["DesktopLight"].contains(module)) {
     657        else if (module == "Qt3Support") {
    526658            text << Atom::ParaLeft
    527659                 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
    528                  << "This class is not part of the Qt Desktop Light Edition."
    529                  << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
    530                  << Atom::ParaRight;
    531         }
    532         else if (module == "Qt3Support" && Tokenizer::isTrue("defined(opensourceedition)")) {
    533             text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
    534                  << "Note to Qt Desktop Light Edition users:"
     660                 << "Note to Qt GUI Framework Edition users:"
    535661                 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
    536662                 << " This class is only available in the "
    537                  << Atom(Atom::AutoLink, "Qt Desktop Edition")
     663                 << Atom(Atom::AutoLink, "Qt Full Framework Edition")
    538664                 << "." << Atom::ParaRight;
    539665        }
     
    559685                    break;
    560686            }
    561         } else {
     687        }
     688        else {
    562689            if (markedCode.at(i) == QLatin1Char('\n')) {
    563690                column = 0;
    564             } else {
     691            }
     692            else {
    565693                if (column == 0) {
    566694                    for (int j = 0; j < level; j++)
     
    631759{
    632760    Location::internalError(tr("unknown atom type '%1' in %2 generator")
    633                              .arg(atom->typeString()).arg(format()));
     761                            .arg(atom->typeString()).arg(format()));
    634762}
    635763
     
    660788                    }
    661789                }
    662             } else if (!func->name().isEmpty()) {
     790            }
     791            else if (!func->name().isEmpty()) {
    663792                alternateName = "set";
    664793                alternateName += func->name()[0].toUpper();
     
    716845        break;
    717846    case Node::Preliminary:
    718         text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This "
    719              << typeString(node) << " is under development and is subject to change."
    720              << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << Atom::ParaRight;
     847        text << Atom::ParaLeft
     848             << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
     849             << "This "
     850             << typeString(node)
     851             << " is under development and is subject to change."
     852             << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
     853             << Atom::ParaRight;
    721854        break;
    722855    case Node::Deprecated:
     
    736869        if (node->isInnerNode())
    737870            text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD);
    738         text << " It is provided to keep old source code working. We strongly advise against "
     871        text << " It is provided to keep old source code working. "
     872             << "We strongly advise against "
    739873             << "using it in new code." << Atom::ParaRight;
    740874        break;
     
    742876        // reimplemented in HtmlGenerator subclass
    743877        if (node->isInnerNode()) {
    744             text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "This "
    745                  << typeString(node) << " is part of the Qt 3 compatibility layer."
     878            text << Atom::ParaLeft
     879                 << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD)
     880                 << "This "
     881                 << typeString(node)
     882                 << " is part of the Qt 3 compatibility layer."
    746883                 << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD)
    747                  << " It is provided to keep old source code working. We strongly advise against "
     884                 << " It is provided to keep old source code working. "
     885                 << "We strongly advise against "
    748886                 << "using it in new code. See "
    749887                 << Atom(Atom::AutoLink, "Porting to Qt 4")
     
    763901    Text text;
    764902    Text theStockLink;
    765     Node::ThreadSafeness parent = node->parent()->inheritedThreadSafeness();
    766 
    767     switch (node->threadSafeness()) {
     903    Node::ThreadSafeness threadSafeness = node->threadSafeness();
     904
     905    Text rlink;
     906    rlink << Atom(Atom::Link,"reentrant")
     907          << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
     908          << "reentrant"
     909          << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
     910
     911    Text tlink;
     912    tlink << Atom(Atom::Link,"thread-safe")
     913          << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
     914          << "thread-safe"
     915          << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
     916
     917    switch (threadSafeness) {
    768918    case Node::UnspecifiedSafeness:
    769919        break;
    770920    case Node::NonReentrant:
    771         text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD) << "Warning:"
    772              << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " This "
    773              << typeString(node) << " is not " << stockLink("reentrant") << "." << Atom::ParaRight;
     921        text << Atom::ParaLeft
     922             << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
     923             << "Warning:"
     924             << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD)
     925             << " This "
     926             << typeString(node)
     927             << " is not "
     928             << rlink
     929             << "."
     930             << Atom::ParaRight;
    774931        break;
    775932    case Node::Reentrant:
    776933    case Node::ThreadSafe:
    777         text << Atom::ParaLeft << Atom(Atom::FormattingLeft, ATOM_FORMATTING_BOLD);
    778         if (parent == Node::ThreadSafe) {
    779             text << "Warning:";
    780         } else {
    781             text << "Note:";
    782         }
    783         text << Atom(Atom::FormattingRight, ATOM_FORMATTING_BOLD) << " ";
    784 
    785         if (node->threadSafeness() == Node::ThreadSafe)
    786             theStockLink = stockLink("thread-safe");
    787         else
    788             theStockLink = stockLink("reentrant");
     934        text << Atom::ParaLeft
     935             << Atom(Atom::FormattingLeft,ATOM_FORMATTING_BOLD)
     936             << "Note:"
     937             << Atom(Atom::FormattingRight,ATOM_FORMATTING_BOLD)
     938             << " ";
    789939
    790940        if (node->isInnerNode()) {
    791             const InnerNode *innerNode = static_cast<const InnerNode *>(node);
    792             text << "All the functions in this " << typeString(node) << " are "
    793                  << theStockLink;
    794 
    795             NodeList except;
     941            const InnerNode* innerNode = static_cast<const InnerNode*>(node);
     942            text << "All functions in this "
     943                 << typeString(node)
     944                 << " are ";
     945            if (threadSafeness == Node::ThreadSafe)
     946                text << tlink;
     947            else
     948                text << rlink;
     949
     950            bool exceptions = false;
     951            NodeList reentrant;
     952            NodeList threadsafe;
     953            NodeList nonreentrant;
    796954            NodeList::ConstIterator c = innerNode->childNodes().begin();
    797955            while (c != innerNode->childNodes().end()) {
    798                 if ((*c)->threadSafeness() != Node::UnspecifiedSafeness)
    799                     except.append(*c);
     956                switch ((*c)->threadSafeness()) {
     957                case Node::Reentrant:
     958                    reentrant.append(*c);
     959                    if (threadSafeness == Node::ThreadSafe)
     960                        exceptions = true;
     961                    break;
     962                case Node::ThreadSafe:
     963                    threadsafe.append(*c);
     964                    if (threadSafeness == Node::Reentrant)
     965                        exceptions = true;
     966                    break;
     967                case Node::NonReentrant:
     968                    nonreentrant.append(*c);
     969                    exceptions = true;
     970                    break;
     971                default:
     972                    break;
     973                }
    800974                ++c;
    801975            }
    802             if (except.isEmpty()) {
     976            if (!exceptions)
    803977                text << ".";
    804             }
    805             else {
    806                 text << ", except ";
    807 
    808                 NodeList::ConstIterator e = except.begin();
    809                 int index = 0;
    810                 while (e != except.end()) {
    811                     appendFullName(text, *e, innerNode, marker);
    812                     text << separator(index++, except.count());
    813                     ++e;
     978            else if (threadSafeness == Node::Reentrant) {
     979                if (nonreentrant.isEmpty()) {
     980                    if (!threadsafe.isEmpty()) {
     981                        text << ", but ";
     982                        appendFullNames(text,threadsafe,innerNode,marker);
     983                        singularPlural(text,threadsafe);
     984                        text << " also " << tlink << ".";
     985                    }
     986                    else
     987                        text << ".";
     988                }
     989                else {
     990                    text << ", except for ";
     991                    appendFullNames(text,nonreentrant,innerNode,marker);
     992                    text << ", which";
     993                    singularPlural(text,nonreentrant);
     994                    text << " nonreentrant.";
     995                    if (!threadsafe.isEmpty()) {
     996                        text << " ";
     997                        appendFullNames(text,threadsafe,innerNode,marker);
     998                        singularPlural(text,threadsafe);
     999                        text << " " << tlink << ".";
     1000                    }
     1001                }
     1002            }
     1003            else { // thread-safe
     1004                if (!nonreentrant.isEmpty() || !reentrant.isEmpty()) {
     1005                    text << ", except for ";
     1006                    if (!reentrant.isEmpty()) {
     1007                        appendFullNames(text,reentrant,innerNode,marker);
     1008                        text << ", which";
     1009                        singularPlural(text,reentrant);
     1010                        text << " only " << rlink;
     1011                        if (!nonreentrant.isEmpty())
     1012                            text << ", and ";
     1013                    }
     1014                    if (!nonreentrant.isEmpty()) {
     1015                        appendFullNames(text,nonreentrant,innerNode,marker);
     1016                        text << ", which";
     1017                        singularPlural(text,nonreentrant);
     1018                        text << " nonreentrant.";
     1019                    }
     1020                    text << ".";
    8141021                }
    8151022            }
    8161023        }
    8171024        else {
    818             text << "This " << typeString(node) << " is " << theStockLink << ".";
     1025            text << "This " << typeString(node) << " is ";
     1026            if (threadSafeness == Node::ThreadSafe)
     1027                text << tlink;
     1028            else
     1029                text << rlink;
     1030            text << ".";
    8191031        }
    8201032        text << Atom::ParaRight;
    8211033    }
    822     generateText(text, node, marker);
     1034    generateText(text,node,marker);
    8231035}
    8241036
     
    8271039    if (!node->since().isEmpty()) {
    8281040        Text text;
    829         text << Atom::ParaLeft << "This " << typeString(node)
     1041        text << Atom::ParaLeft
     1042             << "This "
     1043             << typeString(node)
    8301044             << " was introduced in ";
    8311045        if (project.isEmpty())
     
    8571071    if (func->reimplementedFrom() != 0) {
    8581072        const FunctionNode *from = func->reimplementedFrom();
    859         if (from->access() != Node::Private && from->parent()->access() != Node::Private) {
     1073        if (from->access() != Node::Private &&
     1074            from->parent()->access() != Node::Private) {
    8601075            Text text;
    8611076            text << Atom::ParaLeft << "Reimplemented from ";
    862             appendFullName(text, from->parent(), func, marker, from);
     1077            QString fullName =  from->parent()->name() + "::" + from->name() + "()";
     1078            appendFullName(text, from->parent(), fullName, from);
    8631079            text << "." << Atom::ParaRight;
    8641080            generateText(text, func, marker);
     
    8981114            if (atom->type() == Atom::FormatEndif) {
    8991115                if (generate && numAtoms0 == numAtoms) {
    900                     relative->location().warning(tr("Output format %1 not handled").
    901                                                  arg(format()));
     1116                    relative->location().warning(tr("Output format %1 not handled")
     1117                                                 .arg(format()));
    9021118                    Atom unhandledFormatAtom(Atom::UnhandledFormat, format());
    9031119                    generateAtomList(&unhandledFormatAtom,
     
    9101126            }
    9111127        }
    912         else if (atom->type() == Atom::FormatElse || atom->type() == Atom::FormatEndif) {
     1128        else if (atom->type() == Atom::FormatElse ||
     1129                 atom->type() == Atom::FormatEndif) {
    9131130            return atom;
    9141131        }
     
    9401157}
    9411158
     1159void Generator::appendFullName(Text& text,
     1160                               const Node *apparentNode,
     1161                               const QString& fullName,
     1162                               const Node *actualNode)
     1163{
     1164    if (actualNode == 0)
     1165        actualNode = apparentNode;
     1166    text << Atom(Atom::LinkNode, CodeMarker::stringForNode(actualNode))
     1167         << Atom(Atom::FormattingLeft, ATOM_FORMATTING_LINK)
     1168         << Atom(Atom::String, fullName)
     1169         << Atom(Atom::FormattingRight, ATOM_FORMATTING_LINK);
     1170}
     1171
     1172void Generator::appendFullNames(Text& text,
     1173                                const NodeList& nodes,
     1174                                const Node* relative,
     1175                                CodeMarker* marker)
     1176{
     1177    NodeList::ConstIterator n = nodes.begin();
     1178    int index = 0;
     1179    while (n != nodes.end()) {
     1180        appendFullName(text,*n,relative,marker);
     1181        text << comma(index++,nodes.count());
     1182        ++n;
     1183    }
     1184}
     1185
    9421186void Generator::appendSortedNames(Text& text,
    9431187                                  const ClassNode *classe,
     
    9511195    r = classes.begin();
    9521196    while (r != classes.end()) {
    953         if ((*r).node->access() == Node::Public && (*r).node->status() != Node::Internal
     1197        if ((*r).node->access() == Node::Public &&
     1198            (*r).node->status() != Node::Internal
    9541199            && !(*r).node->doc().isEmpty()) {
    9551200            Text className;
Note: See TracChangeset for help on using the changeset viewer.