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/doc.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**
     
    7474
    7575enum {
    76     CMD_A, CMD_ABSTRACT, CMD_BADCODE, CMD_BASENAME, CMD_BOLD,
    77     CMD_BRIEF, CMD_C, CMD_CAPTION, CMD_CHAPTER, CMD_CODE,
    78     CMD_CODELINE, CMD_DOTS, CMD_ELSE, CMD_ENDABSTRACT,
    79     CMD_ENDCHAPTER, CMD_ENDCODE, CMD_ENDFOOTNOTE, CMD_ENDIF,
    80     CMD_ENDLEGALESE, CMD_ENDLINK, CMD_ENDLIST, CMD_ENDOMIT,
    81     CMD_ENDPART, CMD_ENDQUOTATION, CMD_ENDRAW, CMD_ENDSECTION1,
    82     CMD_ENDSECTION2, CMD_ENDSECTION3, CMD_ENDSECTION4,
    83     CMD_ENDSIDEBAR, CMD_ENDTABLE, CMD_EXPIRE, CMD_FOOTNOTE,
    84     CMD_GENERATELIST, CMD_GRANULARITY, CMD_HEADER, CMD_I,
    85     CMD_IF, CMD_IMAGE, CMD_INCLUDE, CMD_INLINEIMAGE, CMD_INDEX,
    86     CMD_KEYWORD, CMD_L, CMD_LEGALESE, CMD_LINK, CMD_LIST,
    87     CMD_META, CMD_NEWCODE, CMD_O, CMD_OLDCODE, CMD_OMIT,
    88     CMD_OMITVALUE, CMD_OVERLOAD,
    89     CMD_PART, CMD_PRINTLINE, CMD_PRINTTO,
     76    CMD_A, CMD_ABSTRACT, CMD_ANNOTATEDLIST, CMD_BADCODE,
     77    CMD_BASENAME, CMD_BOLD, CMD_BRIEF, CMD_C, CMD_CAPTION,
     78    CMD_CHAPTER, CMD_CODE, CMD_CODELINE, CMD_DOTS, CMD_ELSE,
     79    CMD_ENDABSTRACT, CMD_ENDCHAPTER, CMD_ENDCODE,
     80    CMD_ENDFOOTNOTE, CMD_ENDIF, CMD_ENDLEGALESE, CMD_ENDLINK,
     81    CMD_ENDLIST, CMD_ENDOMIT, CMD_ENDPART, CMD_ENDQUOTATION,
     82    CMD_ENDRAW, CMD_ENDSECTION1, CMD_ENDSECTION2,
     83    CMD_ENDSECTION3, CMD_ENDSECTION4, CMD_ENDSIDEBAR,
     84    CMD_ENDTABLE, CMD_EXPIRE, CMD_FOOTNOTE, CMD_GENERATELIST,
     85    CMD_GRANULARITY, CMD_HEADER, CMD_I, CMD_IF, CMD_IMAGE,
     86    CMD_INCLUDE, CMD_INLINEIMAGE, CMD_INDEX, CMD_KEYWORD,
     87    CMD_L, CMD_LEGALESE, CMD_LINK, CMD_LIST, CMD_META,
     88    CMD_NEWCODE, CMD_O, CMD_OLDCODE, CMD_OMIT, CMD_OMITVALUE,
     89    CMD_OVERLOAD, CMD_PART, CMD_PRINTLINE, CMD_PRINTTO,
    9090    CMD_PRINTUNTIL, CMD_QUOTATION, CMD_QUOTEFILE,
    9191    CMD_QUOTEFROMFILE, CMD_QUOTEFUNCTION, CMD_RAW, CMD_ROW,
    9292    CMD_SA, CMD_SECTION1, CMD_SECTION2, CMD_SECTION3,
    93     CMD_SECTION4, CMD_SIDEBAR, CMD_SKIPLINE, CMD_SKIPTO,
    94     CMD_SKIPUNTIL, CMD_SNIPPET, CMD_SUB, CMD_SUP, CMD_TABLE,
    95     CMD_TABLEOFCONTENTS, CMD_TARGET, CMD_TT, CMD_UNDERLINE,
    96     CMD_UNICODE, CMD_VALUE, CMD_WARNING,
     93    CMD_SECTION4, CMD_SIDEBAR, CMD_SINCELIST, CMD_SKIPLINE,
     94    CMD_SKIPTO, CMD_SKIPUNTIL, CMD_SNIPPET, CMD_SUB, CMD_SUP,
     95    CMD_TABLE, CMD_TABLEOFCONTENTS, CMD_TARGET, CMD_TT,
     96    CMD_UNDERLINE, CMD_UNICODE, CMD_VALUE, CMD_WARNING,
    9797#ifdef QDOC_QML   
    9898    CMD_QML, CMD_ENDQML, CMD_CPP, CMD_ENDCPP, CMD_QMLTEXT,
     
    109109    { "a", CMD_A, 0 },
    110110    { "abstract", CMD_ABSTRACT, 0 },
     111    { "annotatedlist", CMD_ANNOTATEDLIST, 0 },
    111112    { "badcode", CMD_BADCODE, 0 },
    112113    { "basename", CMD_BASENAME, 0 }, // ### don't document for now
     
    177178    { "section4", CMD_SECTION4, 0 },
    178179    { "sidebar", CMD_SIDEBAR, 0 }, // ### don't document for now
     180    { "sincelist", CMD_SINCELIST, 0 },
    179181    { "skipline", CMD_SKIPLINE, 0 },
    180182    { "skipto", CMD_SKIPTO, 0 },
     
    516518                    case CMD_BADCODE:
    517519                        leavePara();
    518 #ifdef QDOC2DOX                       
    519                         if (DoxWriter::isDoxPass())
    520                             append(Atom::CodeBad,getUnmarkedCode(CMD_BADCODE));
    521                         else
    522                             append(Atom::CodeBad,getCode(CMD_BADCODE, marker));
    523 #else
    524520                        append(Atom::CodeBad,getCode(CMD_BADCODE, marker));
    525 #endif                       
    526521                        break;
    527522                    case CMD_BASENAME:
     
    539534                        enterPara();
    540535                        x = untabifyEtc(getArgument(true));
    541 #ifdef QDOC2DOX                       
    542                         if (DoxWriter::isDoxPass())
    543                             append(Atom::C, x);
    544                         else {
    545                             marker = CodeMarker::markerForCode(x);
    546                             append(Atom::C, marker->markedUpCode(x, 0, ""));
    547                         }
    548 #else
    549536                        marker = CodeMarker::markerForCode(x);
    550537                        append(Atom::C, marker->markedUpCode(x, 0, ""));
    551 #endif
    552538                        break;
    553539                    case CMD_CAPTION:
     
    560546                    case CMD_CODE:
    561547                        leavePara();
    562 #ifdef QDOC2DOX                       
    563                         if (DoxWriter::isDoxPass())
    564                             append(Atom::Code, getUnmarkedCode(CMD_CODE));
    565                         else
    566                             append(Atom::Code, getCode(CMD_CODE, marker));
    567 #else
    568548                        append(Atom::Code, getCode(CMD_CODE, marker));
    569 #endif
    570549                        break;
    571550#ifdef QDOC_QML       
     
    580559                    case CMD_CODELINE:
    581560                        {
    582 #ifdef QDOC2DOX                       
    583                             if (!quoting && !DoxWriter::isDoxPass()) {
    584                                 if (priv->text.lastAtom()->type() == Atom::Code
    585                                         && priv->text.lastAtom()->string().endsWith("\n\n"))
    586                                     priv->text.lastAtom()->chopString();
    587                                 appendToCode("\n");
    588                             } lse {
    589                                 append(Atom::CodeQuoteCommand, cmdStr);
    590                                 append(Atom::CodeQuoteArgument, " ");
    591                             }
    592 #else
    593561                            if (!quoting) {
    594562                                if (priv->text.lastAtom()->type() == Atom::Code
     
    601569                                append(Atom::CodeQuoteArgument, " ");
    602570                            }
    603 #endif
    604571                        }
    605572                        break;
    606573                    case CMD_DOTS:
    607574                        {
    608 #ifdef QDOC2DOX                       
    609                             if (DoxWriter::isDoxPass()) {
    610                                 append(Atom::CodeQuoteCommand, cmdStr);
    611                                 append(Atom::CodeQuoteArgument, "    ...");
    612                             }
    613                             else if (!quoting) {
     575                            if (!quoting) {
    614576                                if (priv->text.lastAtom()->type() == Atom::Code
    615577                                        && priv->text.lastAtom()->string().endsWith("\n\n"))
     
    631593                                append(Atom::CodeQuoteArgument, arg);
    632594                            }
    633 #else
    634                             if (!quoting) {
    635                                 if (priv->text.lastAtom()->type() == Atom::Code
    636                                         && priv->text.lastAtom()->string().endsWith("\n\n"))
    637                                     priv->text.lastAtom()->chopString();
    638 
    639                                 QString arg = getOptionalArgument();
    640                                 int indent = 4;
    641                                 if (!arg.isEmpty())
    642                                     indent = arg.toInt();
    643                                 for (int i = 0; i < indent; ++i)
    644                                     appendToCode(" ");
    645                                 appendToCode("...\n");
    646                             }
    647                             else {
    648                                 append(Atom::CodeQuoteCommand, cmdStr);
    649                                 QString arg = getOptionalArgument();
    650                                 if (arg.isEmpty())
    651                                     arg = "4";
    652                                 append(Atom::CodeQuoteArgument, arg);
    653                             }
    654 #endif
    655595                        }
    656596                        break;
     
    785725                            paraState = OutsidePara; // ###
    786726                        }
     727                        break;
     728                    case CMD_ANNOTATEDLIST:
     729                        append(Atom::AnnotatedList, getArgument());
     730                        break;
     731                    case CMD_SINCELIST:
     732                        append(Atom::SinceList, getArgument());
    787733                        break;
    788734                    case CMD_GENERATELIST:
     
    954900                    case CMD_OLDCODE:
    955901                        leavePara();
    956 #ifdef QDOC2DOX                       
    957                         if (DoxWriter::isDoxPass()) {
    958                             append(Atom::CodeOld, getUnmarkedCode(CMD_OLDCODE));
    959                             append(Atom::CodeNew, getUnmarkedCode(CMD_NEWCODE));
    960                         }
    961                         else {
    962                             append(Atom::CodeOld, getCode(CMD_OLDCODE, marker));
    963                             append(Atom::CodeNew, getCode(CMD_NEWCODE, marker));
    964                         }
    965 #else
    966902                        append(Atom::CodeOld, getCode(CMD_OLDCODE, marker));
    967903                        append(Atom::CodeNew, getCode(CMD_NEWCODE, marker));
    968 #endif
    969904                        break;
    970905                    case CMD_OMIT:
     
    11481083                            QString snippet = getArgument();
    11491084                            QString identifier = getRestOfLine();
    1150 #ifdef QDOC2DOX                       
    1151                             if (quoting || DoxWriter::isDoxPass()) {
    1152                                 append(Atom::SnippetCommand, cmdStr);
    1153                                 append(Atom::SnippetLocation, snippet);
    1154                                 append(Atom::SnippetIdentifier, identifier);
    1155                             }
    1156                             else {
    1157                                 Doc::quoteFromFile(location(),quoter,snippet);
    1158                                 appendToCode(quoter.quoteSnippet(location(),
    1159                                                                  identifier));
    1160                             }
    1161 #else
    11621085                            if (quoting) {
    11631086                                append(Atom::SnippetCommand, cmdStr);
     
    11701093                                                                 identifier));
    11711094                            }
    1172 #endif
    11731095                        }
    11741096                        break;
     
    12521174                        append(Atom::String, " ");
    12531175                        break;
    1254                     case CMD_OVERLOAD: // qdoc --> doxygen
     1176                    case CMD_OVERLOAD:
    12551177                        priv->metacommandsUsed.insert(cmdStr);
    12561178                        x.clear();
     
    12661188                        else {
    12671189                            append(Atom::ParaLeft);
    1268                             append(Atom::String,
    1269                                    "This is an overloaded member function, "
    1270                                    "provided for convenience.");
     1190                            append(Atom::String,"This is an overloaded function.");
    12711191                            append(Atom::ParaRight);
    12721192                            x = getMetaCommandArgument(cmdStr);
     
    17661686
    17671687    if (currentSectioningUnit == Doc::Book) {
     1688#if 0
     1689        // mws didn't think this was necessary.
    17681690        if (unit > Doc::Section1)
    17691691            location().warning(tr("Unexpected '\\%1' without '\\%2'")
    17701692                                .arg(cmdName(cmd))
    17711693                                .arg(cmdName(CMD_SECTION1)));
     1694#endif       
    17721695        currentSectioningUnit = (Doc::SectioningUnit) (unit - 1);
    17731696        priv->constructExtra();
     
    23462269
    23472270/*!
    2348   Used only for generating doxygen output.
     2271  Was used only for generating doxygen output.
    23492272 */
    23502273QString DocParser::getUnmarkedCode(int cmd)
     
    25822505#endif
    25832506
    2584 #ifdef QDOC2DOX                       
    2585 #define DOXYGEN_INDENT 2
    2586 #define DOXYGEN_TAB_SIZE 4
    2587 #define DOXYGEN_INDENT_STRING "  "
    2588 #define DOXYGEN_TAB_STRING "    "
    2589 
    2590 static QRegExp ws_rx("\\s");
    2591 static QRegExp not_ws_rx("\\S");
    2592 
    2593 int DoxWriter::doxPass = 0;
    2594 QString DoxWriter::currentClass;
    2595 QSet<QString> DoxWriter::anchors;
    2596 QStringMap DoxWriter::exampleTitles;
    2597 QStringMap DoxWriter::headerFileTitles;
    2598 QStringMap DoxWriter::fileTitles;
    2599 QStringMap DoxWriter::groupTitles;
    2600 QStringMap DoxWriter::moduleTitles;
    2601 QStringMap DoxWriter::pageTitles;
    2602 QStringMap DoxWriter::externalPageTitles;
    2603 QStringMap DoxWriter::exampleTitlesInverse;
    2604 QStringMap DoxWriter::headerFileTitlesInverse;
    2605 QStringMap DoxWriter::fileTitlesInverse;
    2606 QStringMap DoxWriter::groupTitlesInverse;
    2607 QStringMap DoxWriter::moduleTitlesInverse;
    2608 QStringMap DoxWriter::pageTitlesInverse;
    2609 QStringMap DoxWriter::externalPageTitlesInverse;
    2610 QStringMultiMap DoxWriter::variables;
    2611 QStringMultiMap DoxWriter::properties;
    2612 QStringMultiMap DoxWriter::enums;
    2613 #endif
    26142507
    26152508Doc::Doc(const Location& start_loc,
     
    26212514    DocParser parser;
    26222515    parser.parse(source,priv,metaCommandSet);
    2623 #ifdef QDOC2DOX                       
    2624     if (DoxWriter::isDoxPass()) {
    2625         DoxWriter doxWriter(source,priv);
    2626         if (DoxWriter::isDoxPass(1))
    2627             doxWriter.pass1();
    2628         else
    2629             doxWriter.pass2();
    2630     }
    2631 #endif
    26322516}
    26332517
     
    27582642
    27592643        /*
    2760             This code is really ugly. The entire \brief business
    2761             should be rethought.
     2644          This code is really ugly. The entire \brief business
     2645          should be rethought.
    27622646        */
    2763         while (atom && (atom->type() == Atom::AutoLink || atom->type() == Atom::String)) {
    2764             briefStr += atom->string();
     2647        while (atom) {
     2648            if (atom->type() == Atom::AutoLink || atom->type() == Atom::String) {
     2649                briefStr += atom->string();
     2650            }
    27652651            atom = atom->next();
    27662652        }
    27672653
    27682654        QStringList w = briefStr.split(" ");
    2769         if (!w.isEmpty() && w.first() == "The")
    2770             w.removeFirst();
     2655        if (!w.isEmpty() && w.first() == "Returns") {
     2656        }
    27712657        else {
    2772             location().warning(
    2773                 tr("Nonstandard wording in '\\%1' text for '%2' (expected 'The')")
    2774                 .arg(COMMAND_BRIEF).arg(className));
    2775             standardWording = false;
     2658            if (!w.isEmpty() && w.first() == "The")
     2659                w.removeFirst();
     2660            else {
     2661                location().warning(
     2662                  tr("Nonstandard wording in '\\%1' text for '%2' (expected 'The')")
     2663                  .arg(COMMAND_BRIEF).arg(className));
     2664                standardWording = false;
     2665            }
     2666
     2667            if (!w.isEmpty() && (w.first() == className || w.first() == classNameOnly))
     2668                w.removeFirst();
     2669            else {
     2670                location().warning(
     2671                  tr("Nonstandard wording in '\\%1' text for '%2' (expected '%3')")
     2672                  .arg(COMMAND_BRIEF).arg(className).arg(className));
     2673                standardWording = false;
     2674            }
     2675
     2676            if (!w.isEmpty() && ((w.first() == "class") ||
     2677                                 (w.first() == "function") ||
     2678                                 (w.first() == "macro") ||
     2679                                 (w.first() == "widget") ||
     2680                                 (w.first() == "namespace") ||
     2681                                 (w.first() == "header")))
     2682                w.removeFirst();
     2683            else {
     2684                location().warning(
     2685                  tr("Nonstandard wording in '\\%1' text for '%2' ("
     2686                     "expected 'class', 'function', 'macro', 'widget', "
     2687                     "'namespace' or 'header')")
     2688                  .arg(COMMAND_BRIEF).arg(className));
     2689                standardWording = false;
     2690            }
     2691
     2692            if (!w.isEmpty() && (w.first() == "is" || w.first() == "provides"))
     2693                w.removeFirst();
     2694
     2695            if (!w.isEmpty() && (w.first() == "a" || w.first() == "an"))
     2696                w.removeFirst();
    27762697        }
    27772698
    2778         if (!w.isEmpty() && (w.first() == className || w.first() == classNameOnly))
    2779             w.removeFirst();
    2780         else {
    2781             location().warning(
    2782                 tr("Nonstandard wording in '\\%1' text for '%2' (expected '%3')")
    2783                 .arg(COMMAND_BRIEF).arg(className).arg(className));
    2784             standardWording = false;
    2785         }
    2786 
    2787         if (!w.isEmpty() && (w.first() == "class" || w.first() == "widget"
    2788                              || w.first() == "namespace" || w.first() == "header"))
    2789             w.removeFirst();
    2790         else {
    2791             location().warning(
    2792                 tr("Nonstandard wording in '\\%1' text for '%2' ("
    2793                    "expected 'class', 'widget', 'namespace' or 'header')")
    2794                 .arg(COMMAND_BRIEF).arg(className));
    2795             standardWording = false;
    2796         }
    2797 
    2798         if (!w.isEmpty() && (w.first() == "is" || w.first() == "provides"))
    2799             w.removeFirst();
    2800 
    2801         if (!w.isEmpty() && (w.first() == "a" || w.first() == "an"))
    2802             w.removeFirst();
    2803 
    28042699        whats = w.join(" ");
     2700       
    28052701        if (whats.endsWith("."))
    28062702            whats.truncate(whats.length() - 1);
     
    29452841    DocParser::sourceDirs = config.getStringList(CONFIG_SOURCEDIRS);
    29462842    DocParser::quoting = config.getBool(CONFIG_QUOTINGINFORMATION);
     2843
     2844#ifdef QDOC_QML
     2845    QmlClassNode::qmlOnly = config.getBool(CONFIG_QMLONLY);
     2846#endif
    29472847
    29482848    QStringMap reverseAliasMap;
     
    31833083}
    31843084
    3185 #ifdef QDOC2DOX                       
    3186 /*!
    3187   Sets the doxygen writer pass to \a pass. You can use
    3188   isDoxPass(), with or without a parameter, to test if
    3189   you are in a doxygen writer run or in a specific pass
    3190   of a doxygen writer run.
    3191 
    3192   This function is only called from main() if either the
    3193   \e doxygen1 or \e doxygen2 flag is passed to qdoc3 on
    3194   the command line.
    3195  */
    3196 void DoxWriter::setDoxPass(int pass)
    3197 {
    3198     qDebug() << "SETTING doxygen pass to " << pass
    3199              << " in DoxWriter::setDoxPass()";
    3200     doxPass = pass;
    3201 }
    3202 
    3203 /*!
    3204   Returns true if the doxygen pass is set to \a pass,
    3205   which means we are in the specified \a pass of a doxygen
    3206   writer run of qdoc3.
    3207  */
    3208 bool DoxWriter::isDoxPass(int pass) { return (doxPass == pass); }
    3209 
    3210 /*!
    3211   Returns true if the doxygen pass is 1 or 2, which
    3212   means this is a doxygen writer run to transform qdoc
    3213   comments into doxygen comments.
    3214  */
    3215 bool DoxWriter::isDoxPass() { return (doxPass > 0); }
    3216 
    3217 bool DoxWriter::conversionRequired() const
    3218 {
    3219     /*
    3220       Loop through all the topic commands searching for
    3221       one that must be transformed to doxygen format. If
    3222       one is found, return true.
    3223      */
    3224     QCommandMap::const_iterator i;
    3225     i = priv->metaCommandMap.constBegin();
    3226     while (i != priv->metaCommandMap.constEnd()) {
    3227         QString s = i.key();
    3228         if (s == "enum")
    3229             return true;
    3230         else if (s == "example")
    3231             return true;
    3232         else if (s == "externalpage")
    3233             return true;
    3234         else if (s == "group")
    3235             return true;
    3236         else if (s == "headerfile")
    3237             return true;
    3238         else if (s == "module")
    3239             return true;
    3240         else if (s == "page")
    3241             return true;
    3242         else if (s == "property")
    3243             return true;
    3244         else if (s == "typedef")
    3245             return true;
    3246         else if (s == "variable")
    3247             return true;
    3248         else if (s == "overload")
    3249             return true;
    3250         else if (s == "reimp")
    3251             return true;
    3252         else if (s == "relates")
    3253             return true;
    3254         else if (s == "macro")
    3255             return true;
    3256         else {
    3257 #if 0           
    3258             if (s == "class")
    3259             else if (s == "namespace")
    3260             else if (s == "service")
    3261             else if (s == "inheaderfile")
    3262             else if (s == "file")
    3263             else if (s == "fn")
    3264             else if (s == "contentspage")
    3265             else if (s == "nextpage")
    3266             else if (s == "previous")
    3267             else if (s == "indexpage")
    3268             else if (s == "startpage")
    3269 #endif           
    3270         }
    3271         ++i;
    3272     }
    3273    
    3274     /*
    3275       Loop through all the qdoc atoms searching for one
    3276       that must be transformed to doxygen format. If one
    3277       is found, return true.
    3278      */
    3279     const Atom* next = priv->text.firstAtom();
    3280     while (next != 0) {
    3281         Atom::Type atomType = next->type();
    3282         switch (atomType) {
    3283             case Atom::C:
    3284             case Atom::CaptionLeft:
    3285             case Atom::Code:
    3286             case Atom::CodeBad:
    3287             case Atom::CodeNew:
    3288             case Atom::CodeOld:
    3289             case Atom::CodeQuoteArgument:
    3290             case Atom::CodeQuoteCommand:
    3291             case Atom::FootnoteLeft:
    3292             case Atom::FormatElse:
    3293             case Atom::FormatEndif:
    3294             case Atom::FormatIf:
    3295             case Atom::GeneratedList:
    3296             case Atom::Image:
    3297             case Atom::ImageText:
    3298             case Atom::InlineImage:
    3299             case Atom::LegaleseLeft:
    3300             case Atom::LineBreak:
    3301             case Atom::Link:
    3302             case Atom::LinkNode:
    3303             case Atom::ListLeft:
    3304             case Atom::ListItemNumber:
    3305             case Atom::ListTagLeft:
    3306             case Atom::ListItemLeft:
    3307             case Atom::QuotationLeft:
    3308             case Atom::RawString:
    3309             case Atom::SectionLeft:
    3310             case Atom::SectionHeadingLeft:
    3311             case Atom::SidebarLeft:
    3312             case Atom::SnippetCommand:
    3313             case Atom::SnippetIdentifier:
    3314             case Atom::SnippetLocation:
    3315             case Atom::TableLeft:
    3316             case Atom::TableHeaderLeft:
    3317             case Atom::TableRowLeft:
    3318             case Atom::TableItemLeft:
    3319             case Atom::TableOfContents:
    3320             case Atom::Target:
    3321                 return true;
    3322             case Atom::AbstractLeft:
    3323             case Atom::AbstractRight:
    3324             case Atom::AutoLink:
    3325             case Atom::BaseName:
    3326             case Atom::BriefLeft:
    3327             case Atom::BriefRight:
    3328             case Atom::CaptionRight:
    3329             case Atom::FormattingLeft:
    3330             case Atom::FormattingRight:
    3331             case Atom::Nop:
    3332             case Atom::ParaLeft:
    3333             case Atom::ParaRight:
    3334             case Atom::FootnoteRight:
    3335             case Atom::LegaleseRight:
    3336             case Atom::ListTagRight:
    3337             case Atom::ListItemRight:
    3338             case Atom::ListRight:
    3339             case Atom::QuotationRight:
    3340             case Atom::SectionRight:
    3341             case Atom::SectionHeadingRight:
    3342             case Atom::SidebarRight:
    3343             case Atom::String:
    3344             case Atom::TableRight:
    3345             case Atom::TableHeaderRight:
    3346             case Atom::TableRowRight:
    3347             case Atom::TableItemRight:
    3348             default:
    3349                 break;
    3350         }
    3351         next = next->next();
    3352     }
    3353     return false;
    3354 }
    3355 
    3356 /*!
    3357   A convenience function to write a qdoc metacommand as a
    3358   doxygen command, without conversion. i.e., some of the
    3359   qdoc metacommands don't require conversion for doxygen.
    3360  */
    3361 void DoxWriter::writeCommand(QCommandMap::const_iterator cmd)
    3362 {
    3363     concatenate("\\" + cmd.key() + " " + cmd.value()[0]);
    3364     newLine();
    3365 }
    3366 
    3367 /*!
    3368   Convert the qdoc commands in the metacommand map to
    3369   doxygen format. This function is called only in pass2().
    3370   The metacommand map contains all the metacommands that
    3371   were found in the qdoc comment that is being converted.
    3372   The metacommands are the ones that begin with the '\'.
    3373   These are not considered part of the text of the comment.
    3374   The text is converted by convertText().
    3375  */
    3376 void DoxWriter::convertMetaCommands()
    3377 {
    3378     QCommandMap& metaCmdMap = priv->metaCommandMap;
    3379     QCommandMap::iterator cmd;
    3380     int c;
    3381 
    3382     currentPage.clear();
    3383     currentFn.clear();
    3384     currentTitle.clear();
    3385     currentEnum.clear();
    3386     currentProperty.clear();
    3387     currentVariable.clear();
    3388     currentClass.clear();
    3389     currentExample.clear();
    3390     currentGroup.clear();
    3391     currentModule.clear();
    3392     currentMacro.clear();
    3393     currentService.clear();
    3394     currentTypedef.clear();
    3395     currentHeaderFile.clear();
    3396     commentType = OtherComment;
    3397 
    3398     if ((cmd = metaCmdMap.find("class")) != metaCmdMap.end()) {
    3399         currentClass = cmd.value()[0];
    3400         if ((c = currentClass.indexOf(' ')) > 0)
    3401             currentClass = currentClass.left(c);
    3402         writeCommand(cmd);
    3403         metaCmdMap.erase(cmd);
    3404         commentType = ClassComment;
    3405     }
    3406     else if ((cmd = metaCmdMap.find("fn")) != metaCmdMap.end()) {
    3407         currentFn = cmd.value()[0];
    3408         writeCommand(cmd);
    3409         metaCmdMap.erase(cmd);
    3410         commentType = FnComment;
    3411     }
    3412     else if ((cmd = metaCmdMap.find("enum")) != metaCmdMap.end()) {
    3413         currentEnum = cmd.value()[0];
    3414         if ((c = currentEnum.lastIndexOf("::")) > 0) {
    3415             currentClass = currentEnum.left(c);
    3416             currentEnum = currentEnum.right(currentEnum.size()-c-2);
    3417             qDebug() << "currentEnum =" << currentEnum;
    3418             qDebug() << "currentClass =" << currentClass;
    3419         }
    3420         writeCommand(cmd);
    3421         metaCmdMap.erase(cmd);
    3422         commentType = EnumComment;
    3423     }
    3424     else if ((cmd = metaCmdMap.find("property")) != metaCmdMap.end()) {
    3425         currentClass = cmd.value()[0];
    3426         if ((c = currentClass.lastIndexOf("::")) > 0) {
    3427             currentProperty = currentClass.right(currentClass.size()-c-2);
    3428             currentClass = currentClass.left(c);
    3429             qDebug() << "currentProperty =" << currentProperty;
    3430             qDebug() << "currentClass =" << currentClass;
    3431         }
    3432         writeCommand(cmd);
    3433         metaCmdMap.erase(cmd);
    3434         commentType = PropertyComment;
    3435     }
    3436     else if ((cmd = metaCmdMap.find("variable")) != metaCmdMap.end()) {
    3437         currentClass = cmd.value()[0];
    3438         if ((c = currentClass.lastIndexOf("::")) > 0) {
    3439             currentVariable = currentClass.right(currentClass.size()-c-2);
    3440             currentClass = currentClass.left(c);
    3441             qDebug() << "currentVariable =" << currentVariable;
    3442             qDebug() << "currentClass =" << currentClass;
    3443         }
    3444         concatenate("\\var " + cmd.value()[0]);
    3445         newLine();
    3446         metaCmdMap.erase(cmd);
    3447         commentType = VariableComment;
    3448     }
    3449 
    3450     if ((cmd = metaCmdMap.find("page")) != metaCmdMap.end()) {
    3451         currentPage = cmd.value()[0];
    3452         QString htmlFile = currentPage;
    3453         const QString* title = getPageTitle(htmlFile);
    3454         QStringList parts = htmlFile.split('.');
    3455         metaCmdMap.erase(cmd);
    3456         if (title) {
    3457             concatenate("\\page " + parts[0] + " " + *title);
    3458             newLine();
    3459         }
    3460         commentType = PageComment;
    3461         qDebug() << "currentPage =" << currentPage;
    3462     }
    3463 
    3464     if ((cmd = metaCmdMap.find("example")) != metaCmdMap.end()) {
    3465         currentExample = cmd.value()[0];
    3466         metaCmdMap.erase(cmd);
    3467         commentType = ExampleComment;
    3468         qDebug() << "currentExample =" << currentExample;
    3469     }
    3470    
    3471     if ((cmd = metaCmdMap.find("macro")) != metaCmdMap.end()) {
    3472         currentMacro = cmd.value()[0];
    3473         metaCmdMap.erase(cmd);
    3474         commentType = MacroComment;
    3475         qDebug() << "currentMacro =" << currentMacro;
    3476     }
    3477    
    3478     if ((cmd = metaCmdMap.find("group")) != metaCmdMap.end()) {
    3479         currentGroup = cmd.value()[0];
    3480         metaCmdMap.erase(cmd);
    3481         commentType = GroupComment;
    3482         qDebug() << "currentGroup =" << currentGroup;
    3483     }
    3484    
    3485     if ((cmd = metaCmdMap.find("module")) != metaCmdMap.end()) {
    3486         currentModule = cmd.value()[0];
    3487         metaCmdMap.erase(cmd);
    3488         commentType = ModuleComment;
    3489         qDebug() << "currentModule =" << currentModule;
    3490     }
    3491    
    3492     if ((cmd = metaCmdMap.find("headerfile")) != metaCmdMap.end()) {
    3493         currentHeaderFile = cmd.value()[0];
    3494         metaCmdMap.erase(cmd);
    3495         commentType = HeaderFileComment;
    3496         qDebug() << "currentHeaderFile =" << currentHeaderFile;
    3497     }
    3498 
    3499     if ((cmd = metaCmdMap.find("typedef")) != metaCmdMap.end()) {
    3500         currentClass = cmd.value()[0];
    3501         if ((c = currentClass.lastIndexOf("::")) > 0) {
    3502             currentTypedef = currentClass.right(currentClass.size()-c-2);
    3503             currentClass = currentClass.left(c);
    3504         }
    3505         metaCmdMap.erase(cmd);
    3506         commentType = TypedefComment;
    3507         qDebug() << "currentTypedef =" << currentTypedef;
    3508         qDebug() << "currentClass =" << currentClass;
    3509     }
    3510    
    3511     cmd = priv->metaCommandMap.begin();
    3512     while (cmd != priv->metaCommandMap.end()) {
    3513         for (int i=0; i<cmd.value().size(); i++) {
    3514             concatenate("\\" + cmd.key() + " " + cmd.value()[i]);
    3515             newLine();
    3516         }
    3517         //qDebug() << "   " << cmd.key() << ": " << cmd.value();
    3518         ++cmd;
    3519     }
    3520 }
    3521 
    3522 /*!
    3523   Convert the qdoc text to doxygen format. The metacommands
    3524   are converted by convertMetaCommands(). This function is
    3525   called in pass2().
    3526  */
    3527 void DoxWriter::convertText()
    3528 {
    3529     const Atom* prev = 0;
    3530     const Atom* next = priv->text.firstAtom();
    3531     while (next != 0) {
    3532         next->dump();
    3533         Atom::Type atomType = next->type();
    3534         switch (atomType) {
    3535             case Atom::AbstractLeft:
    3536                 break;
    3537             case Atom::AbstractRight:
    3538                 break;
    3539             case Atom::AutoLink:
    3540                 concatenate(next->string());
    3541                 break;
    3542             case Atom::BaseName:
    3543                 break;
    3544             case Atom::BriefLeft:
    3545                 concatenate("\\brief ");
    3546                 break;
    3547             case Atom::BriefRight:
    3548                 newLine();
    3549                 break;
    3550             case Atom::C:
    3551                 tt(next);
    3552                 break;
    3553             case Atom::CaptionLeft:
    3554                 unhandled(next);
    3555                 break;
    3556             case Atom::CaptionRight:
    3557                 unhandled(next);
    3558                 break;
    3559             case Atom::Code:
    3560                 code(next);
    3561                 break;
    3562             case Atom::CodeBad:
    3563                 code(next);
    3564                 break;
    3565             case Atom::CodeNew:
    3566                 newLine();
    3567                 concatenate("you can rewrite it as");
    3568                 code(next);
    3569                 break;
    3570             case Atom::CodeOld:
    3571                 newLine();
    3572                 concatenate("For example, if you have code like");
    3573                 code(next);
    3574                 break;
    3575             case Atom::CodeQuoteArgument:
    3576                 unhandled(next);
    3577                 break;
    3578             case Atom::CodeQuoteCommand:
    3579                 next = codeQuoteCommand(next);
    3580                 break;
    3581             case Atom::FootnoteLeft:
    3582                 break;
    3583             case Atom::FootnoteRight:
    3584                 break;
    3585             case Atom::FormatElse:
    3586                 formatElse();
    3587                 break;
    3588             case Atom::FormatEndif:
    3589                 formatEndif();
    3590                 break;
    3591             case Atom::FormatIf:
    3592                 formatIf(next);
    3593                 break;
    3594             case Atom::FormattingLeft:
    3595                 formattingLeft(next,next->next());
    3596                 break;
    3597             case Atom::FormattingRight:
    3598                 formattingRight(next,prev);
    3599                 break;
    3600             case Atom::GeneratedList:
    3601                 break;
    3602             case Atom::Image:
    3603                 break;
    3604             case Atom::ImageText:
    3605                 break;
    3606             case Atom::InlineImage:
    3607                 break;
    3608             case Atom::LegaleseLeft:
    3609                 break;
    3610             case Atom::LegaleseRight:
    3611                 break;
    3612             case Atom::LineBreak:
    3613                 break;
    3614             case Atom::Link:
    3615                 next = link(next);
    3616                 break;
    3617             case Atom::LinkNode:
    3618                 break;
    3619             case Atom::ListLeft:
    3620                 {
    3621                     bool nested = false;
    3622                     if (structs.isEmpty()) {
    3623                         const Atom* i = next->next();
    3624                         while (i->type() != Atom::ListRight) {
    3625                             if ((i->type() == Atom::ListLeft) ||
    3626                                 (i->type() == Atom::TableLeft)) {
    3627                                 nested = true;
    3628                                 break;
    3629                             }
    3630                             i = i->next();
    3631                         }
    3632                     }
    3633                     else
    3634                         nested = true;
    3635                     StructDesc d(BulletList,nested);
    3636                     if (next->string() == "numeric")
    3637                         d.structType = NumericList;
    3638                     else if (next->string() == "value") {
    3639                         d.structType = ValueList;
    3640                     }
    3641                     else if (next->string() != "bullet")
    3642                         qDebug() << "UNKNOWN LIST TYPE" << next->string();
    3643                     structs.push(d);
    3644                     if (nested || (d.structType != BulletList)) {
    3645                         if (d.structType == BulletList)
    3646                             concatenate("<ul>");
    3647                         else if (d.structType == NumericList)
    3648                             concatenate("<ol>");
    3649                         else if (d.structType == ValueList)
    3650                             concatenate("<dl>");
    3651                         newLine();
    3652                     }
    3653                 }
    3654                 break;
    3655             case Atom::ListItemNumber:
    3656                 structs.top().count = next->string().toInt();
    3657                 break;
    3658             case Atom::ListTagLeft:
    3659                 {
    3660                     structs.top().count++;
    3661                     concatenate("<dt>");
    3662                     const Atom* n = next->next();
    3663                     if (n->type() == Atom::String) {
    3664                         qDebug() << "ENUM VALUE" << n->string();
    3665                     }
    3666                     else
    3667                         qDebug() << "NOT EN ENUM";
    3668                 }
    3669                 break;
    3670             case Atom::ListTagRight:
    3671                 concatenate("</dt>");
    3672                 break;
    3673             case Atom::ListItemLeft:
    3674                 {
    3675                     newLine();
    3676                     const StructDesc& d = structs.top();
    3677                     if (d.structType == BulletList) {
    3678                         if (!d.nested)
    3679                             concatenate("\\arg ");
    3680                         else
    3681                             concatenate("<li>");
    3682                     }
    3683                     else if (d.structType == NumericList)
    3684                         concatenate("<li>");
    3685                     else if (d.structType == ValueList)
    3686                         concatenate("<dd>");
    3687                 }
    3688                 break;
    3689             case Atom::ListItemRight:
    3690                 {
    3691                     const StructDesc& d = structs.top();
    3692                     if (d.structType == BulletList) {
    3693                         if (d.nested) {
    3694                             concatenate("</li>");
    3695                             newLine();
    3696                         }
    3697                     }
    3698                     else if (d.structType == NumericList) {
    3699                         concatenate("</li>");
    3700                         newLine();
    3701                     }
    3702                     else if (d.structType == ValueList) {
    3703                         concatenate("</dd>");
    3704                         newLine();
    3705                     }
    3706                 }
    3707                 break;
    3708             case Atom::ListRight:
    3709                 {
    3710                     if (!structs.isEmpty()) {
    3711                         const StructDesc& d = structs.top();
    3712                         if (d.nested || (d.structType != BulletList)) {
    3713                             if (d.structType == BulletList)
    3714                                 concatenate("</ul>");
    3715                             else if (d.structType == NumericList)
    3716                                 concatenate("</ol>");
    3717                             else if (d.structType == ValueList)
    3718                                 concatenate("</dl>");
    3719                             newLine();
    3720                         }
    3721                         structs.pop();
    3722                     }
    3723                 }
    3724                 break;
    3725             case Atom::Nop:
    3726                 // nothing.
    3727                 break;
    3728             case Atom::ParaLeft:
    3729                 if (structs.isEmpty())
    3730                     newLine();
    3731                 break;
    3732             case Atom::ParaRight:
    3733                 {
    3734                     if (structs.isEmpty())
    3735                         newLine();
    3736                     else {
    3737                         const StructDesc& d = structs.top();
    3738                         if (d.nested || (d.structType != BulletList)) {
    3739                             Atom::Type t = next->next()->type();
    3740                             if ((t != Atom::ListItemRight) &&
    3741                                 (t != Atom::TableItemRight))
    3742                                 newLine();
    3743                         }
    3744                         else
    3745                             newLine();
    3746                     }
    3747                 }
    3748                 break;
    3749             case Atom::QuotationLeft:
    3750                 break;
    3751             case Atom::QuotationRight:
    3752                 break;
    3753             case Atom::RawString:
    3754                 concatenate(next->string());
    3755                 break;
    3756             case Atom::SectionLeft:
    3757                 // nothing.
    3758                 break;
    3759             case Atom::SectionRight:
    3760                 // nothing.
    3761                 break;
    3762             case Atom::SectionHeadingLeft:
    3763                 next = sectionHeading(next);
    3764                 break;
    3765             case Atom::SectionHeadingRight:
    3766                 newLine();
    3767                 break;
    3768             case Atom::SidebarLeft:
    3769                 break;
    3770             case Atom::SidebarRight:
    3771                 break;
    3772             case Atom::SnippetCommand:
    3773                 newLine();
    3774                 concatenate("\\snippet ");
    3775                 break;
    3776             case Atom::SnippetIdentifier:
    3777                 newText += next->string();
    3778                 lineLength += next->string().size();
    3779                 newLine();
    3780                 break;
    3781             case Atom::SnippetLocation:
    3782                 newText += next->string() + " ";
    3783                 lineLength += next->string().size() + 1;
    3784                 break;
    3785             case Atom::String:
    3786                 wrap(next->string());
    3787                 break;
    3788             case Atom::TableLeft:
    3789                 {
    3790                     bool nested = false;
    3791                     if (structs.isEmpty()) {
    3792                         const Atom* i = next->next();
    3793                         while (i->type() != Atom::TableRight) {
    3794                             if ((i->type() == Atom::ListLeft) ||
    3795                                 (i->type() == Atom::TableLeft)) {
    3796                                 nested = true;
    3797                                 break;
    3798                             }
    3799                             i = i->next();
    3800                         }
    3801                     }
    3802                     else
    3803                         nested = true;
    3804                     StructDesc d(Table,nested);
    3805                     structs.push(d);
    3806                     if (next->string().isEmpty())
    3807                         concatenate("<table>");
    3808                     else {
    3809                         QString attrs = "width=\"" + next->string() + "\"";
    3810                         attrs += " align=\"center\"";
    3811                         concatenate("<table " + attrs + ">");
    3812                     }
    3813                     newLine();
    3814                 }
    3815                 break;
    3816             case Atom::TableRight:
    3817                 concatenate("</table>");
    3818                 if (!structs.isEmpty())
    3819                     structs.pop();
    3820                 newLine();
    3821                 break;
    3822             case Atom::TableHeaderLeft:
    3823                 concatenate("<tr>");
    3824                 if (!structs.isEmpty())
    3825                     structs.top().inTableHeader = true;
    3826                 newLine();
    3827                 break;
    3828             case Atom::TableHeaderRight:
    3829                 concatenate("</tr>");
    3830                 if (!structs.isEmpty())
    3831                     structs.top().inTableHeader = false;
    3832                 newLine();
    3833                 break;
    3834             case Atom::TableRowLeft:
    3835                 if (!structs.isEmpty()) {
    3836                     structs.top().inTableRow = true;
    3837                     concatenate("<tr valign=\"top\" class=\"");
    3838                     if (structs.top().odd)
    3839                         concatenate("odd\">");
    3840                     else
    3841                         concatenate("even\">");
    3842                     structs.top().odd = !structs.top().odd;
    3843                 }
    3844                 newLine();
    3845                 break;
    3846             case Atom::TableRowRight:
    3847                 concatenate("</tr>");
    3848                 if (!structs.isEmpty())
    3849                     structs.top().inTableRow = false;
    3850                 newLine();
    3851                 break;
    3852             case Atom::TableItemLeft:
    3853                 if (!structs.isEmpty()) {
    3854                     structs.top().inTableItem = true;
    3855                     concatenate("<td>");
    3856                     if (structs.top().inTableHeader)
    3857                         concatenate("<b> ");
    3858                 }
    3859                 break;
    3860             case Atom::TableItemRight:
    3861                 if (!structs.isEmpty()) {
    3862                     structs.top().inTableItem = false;
    3863                     if (structs.top().inTableHeader)
    3864                         concatenate(" </b>");
    3865                     concatenate("</td>");
    3866                 }
    3867                 newLine();
    3868                 break;
    3869             case Atom::TableOfContents:
    3870                 break;
    3871             case Atom::Target:
    3872                 {
    3873                     QString text = next->string();
    3874                     text.remove(ws_rx);
    3875                     newLine();
    3876                     concatenate("\\anchor ");
    3877                     newText += text;
    3878                     lineLength += text.size();
    3879                     newLine();
    3880                 }
    3881                 break;
    3882             case Atom::UnhandledFormat:
    3883                 unhandled(next);
    3884                 break;
    3885             case Atom::UnknownCommand:
    3886                 unhandled(next);
    3887                 break;
    3888             default:
    3889                 //next->dump();
    3890                 break;
    3891         }
    3892         prev = next;
    3893         next = next->next();
    3894     }
    3895 }
    3896 
    3897 /*!
    3898  
    3899   Pass one looks for topic commands and target and section
    3900   commands, and maybe other stuff. These are serialized to
    3901   text files, which are read back in by pass2().
    3902  */
    3903 void DoxWriter::pass1()
    3904 {
    3905     QCommandMap& metaCmdMap = priv->metaCommandMap;
    3906     if (!metaCmdMap.isEmpty()) {
    3907         int c;
    3908         QCommandMap::iterator cmd;
    3909         if ((cmd = metaCmdMap.find("enum")) != metaCmdMap.end()) {
    3910             commentType = EnumComment;
    3911             currentEnum = cmd.value()[0];
    3912             if ((c = currentEnum.lastIndexOf("::")) > 0) {
    3913                 currentClass = currentEnum.left(c);
    3914                 currentEnum = currentEnum.right(currentEnum.size()-c-2);
    3915                 qDebug() << "currentEnum =" << currentEnum;
    3916                 qDebug() << "currentClass =" << currentClass;
    3917                 if (enums.contains(currentEnum,currentClass)) {
    3918                     qWarning() << "DoxWriter::pass1():"
    3919                                << "Duplicate enum:"
    3920                                << currentClass << currentEnum;
    3921                 }
    3922                 else
    3923                     enums.insert(currentEnum,currentClass);
    3924             }
    3925         }
    3926         else if ((cmd = metaCmdMap.find("property")) != metaCmdMap.end()) {
    3927             commentType = PropertyComment;
    3928             currentClass = cmd.value()[0];
    3929             if ((c = currentClass.lastIndexOf("::")) > 0) {
    3930                 currentProperty = currentClass.right(currentClass.size()-c-2);
    3931                 currentClass = currentClass.left(c);
    3932                 qDebug() << "currentProperty =" << currentProperty;
    3933                 qDebug() << "currentClass =" << currentClass;
    3934                 if (properties.contains(currentProperty,currentClass)) {
    3935                     qWarning() << "DoxWriter::pass1():"
    3936                                << "Duplicate property:"
    3937                                << currentClass << currentProperty;
    3938                 }
    3939                 else
    3940                     properties.insert(currentProperty,currentClass);
    3941             }
    3942         }
    3943         else if ((cmd = metaCmdMap.find("variable")) != metaCmdMap.end()) {
    3944             commentType = VariableComment;
    3945             currentClass = cmd.value()[0];
    3946             if ((c = currentClass.lastIndexOf("::")) > 0) {
    3947                 currentVariable = currentClass.right(currentClass.size()-c-2);
    3948                 currentClass = currentClass.left(c);
    3949                 qDebug() << "currentVariable =" << currentVariable;
    3950                 qDebug() << "currentClass =" << currentClass;
    3951                 if (variables.contains(currentVariable,currentClass)) {
    3952                     qWarning() << "DoxWriter::pass1():"
    3953                                << "Duplicate variable:"
    3954                                << currentClass << currentVariable;
    3955                 }
    3956                 else
    3957                     variables.insert(currentVariable,currentClass);
    3958             }
    3959         }
    3960     }
    3961 
    3962     /*
    3963      */
    3964     const Atom* next = priv->text.firstAtom();
    3965     while (next != 0) {
    3966         switch (next->type()) {
    3967             case Atom::SectionHeadingLeft:
    3968                 {
    3969                     QString text;
    3970                     next = next->next();
    3971                     while (next) {
    3972                         if (next->type() == Atom::SectionHeadingRight)
    3973                             break;
    3974                         else
    3975                             text += next->string();
    3976                         next = next->next();
    3977                     }
    3978                     //text.remove(ws_rx);
    3979                     insertAnchor(text);
    3980                 }
    3981                 break;
    3982             case Atom::Target:
    3983                 {
    3984                     QString text = next->string();
    3985                     //text.remove(ws_rx);
    3986                     insertAnchor(text);
    3987                 }
    3988             default:
    3989                 break;
    3990         }
    3991         next = next->next();
    3992     }
    3993 }
    3994 
    3995 /*!
    3996   Output a parsed, tokenized qdoc comment as a doxygen
    3997   comment in diff format for input to the patch command.
    3998  */
    3999 void DoxWriter::pass2()
    4000 {
    4001     if (!conversionRequired()) {
    4002         qDebug() << "NO CONVERSION - FILE:" << priv->start_loc.fileName()
    4003                  << "START:" << priv->start_loc.lineNo()
    4004                  << "END:" << priv->end_loc.lineNo() - 1;
    4005         return;
    4006     }
    4007 
    4008     /*
    4009       Transformation to doxygen required...
    4010      */
    4011     newText = "\n/*! \n";
    4012     convertMetaCommands();
    4013     convertText();
    4014     if (newText[newText.size()-1] == ' ')
    4015         newText.remove(newText.size()-1,1);
    4016     newText += " */\n";
    4017     qDebug() << "CONVERTED COMMENT - FILE:" << priv->start_loc.fileName()
    4018              << "START:" << priv->start_loc.lineNo()
    4019              << "END:" << priv->end_loc.lineNo() - 1;
    4020     qDebug() << newText;
    4021 }
    4022 
    4023 /*!
    4024   Unparse the second parameter of a "\l" command.
    4025  */
    4026 const Atom* DoxWriter::link(const Atom* atom)
    4027 {
    4028     QString first_text = atom->string();
    4029     QString second_text;
    4030     const QString* value = 0;
    4031 
    4032     const Atom* next = atom->next(Atom::FormattingLeft,Atom::LINK_);
    4033     if (next) {
    4034         next->dump();
    4035         while (1) {
    4036             next = next->next();
    4037             next->dump();
    4038             if (next->type() == Atom::FormattingRight) {
    4039                 if (next->string() == Atom::LINK_)
    4040                     break;
    4041                 else {
    4042                     // ignore it.
    4043                 }
    4044             }
    4045             else
    4046                 second_text += next->string();
    4047         }
    4048         int i = first_text.indexOf('#');
    4049         if (i >= 0)
    4050             first_text = first_text.right(first_text.size() - i - 1);
    4051         //newLine();
    4052         if ((value = getExternalPage(first_text))) {
    4053             //qDebug() << "USED AN EXTERNAL PAGE TITLE" << first_text;
    4054             QString href = "<a href=\""+*value+"\">"+first_text+"</a>";
    4055             concatenate(href);
    4056         }
    4057         else if (first_text.startsWith("http:",Qt::CaseInsensitive)) {
    4058             if (first_text == second_text) {
    4059                 concatenate(first_text);
    4060             }
    4061             else {
    4062                 QString href = "<a href=\""+first_text+"\">"+second_text+"</a>";
    4063                 concatenate(href);
    4064             }
    4065         }
    4066         else if ((value = getPageFile(first_text))) {
    4067             //qDebug() << "USED A PAGE TITLE" << first_text;
    4068             QStringList parts = (*value).split('.');
    4069             QString ref = "\\ref " + parts[0] + " \"" + second_text + "\"";
    4070             concatenate(ref);
    4071         }
    4072         else if ((value = getGroup(first_text))) {
    4073             //qDebug() << "USED A GROUP TITLE" << first_text;
    4074             concatenate("\\ref " + *value + " \"" + second_text + "\"");
    4075         }
    4076         else if ((value = getModule(first_text))) {
    4077             //qDebug() << "USED A MODULE TITLE" << first_text;
    4078             concatenate("\\ref " + *value + " \"" + second_text + "\"");
    4079         }
    4080         else if ((value = getExamplePath(first_text))) {
    4081             //qDebug() << "USED AN EXAMPLE TITLE" << first_text;
    4082             first_text.remove(ws_rx);
    4083             QString ref = "\\ref " + first_text + " \"" + second_text + "\"";
    4084             concatenate(ref);
    4085         }
    4086         else if ((value = getFile(first_text))) {
    4087             //qDebug() << "USED A FILE TITLE" << first_text;
    4088             // I think this command is no longer available.
    4089             first_text.remove(ws_rx);
    4090             QString ref = "\\ref " + first_text + " \"" + second_text + "\"";
    4091             concatenate(ref);
    4092         }
    4093         else if ((value = getHeaderFile(first_text))) {
    4094             //qDebug() << "USED A HEADER FILE TITLE" << first_text;
    4095             first_text.remove(ws_rx);
    4096             QString ref = "\\ref " + first_text + " \"" + second_text + "\"";
    4097             concatenate(ref);
    4098         }
    4099         else if (isAnchor(first_text)) {
    4100             //qDebug() << "USED AN ANCHOR" << first_text;
    4101             first_text.remove(ws_rx);
    4102             QString ref = "\\ref " + first_text + " \"" + second_text + "\"";
    4103             concatenate(ref);
    4104         }
    4105         else if ((value = getPageTitle(first_text))) {
    4106             //qDebug() << "USED AN INVERSE PAGE TITLE" << first_text;
    4107             QStringList parts = first_text.split('.');
    4108             QString ref = "\\ref " + parts[0] + " \"" + second_text + "\"";
    4109             concatenate(ref);
    4110         }
    4111         else if ((value = getExampleTitle(first_text))) {
    4112             //qDebug() << "USED AN INVERSE EXAMPLE TITLE" << first_text;
    4113             QString title = *value;
    4114             title.remove(ws_rx);
    4115             QString ref = "\\ref " + title  + " \"" + second_text + "\"";
    4116             concatenate(ref);
    4117         }
    4118         else if ((value = getGroupTitle(first_text))) {
    4119             //qDebug() << "USED AN INVERSE GROUP TITLE" << first_text;
    4120             concatenate("\\ref " + first_text + " \"" + second_text + "\"");
    4121         }
    4122         else if ((value = getModuleTitle(first_text))) {
    4123             //qDebug() << "USED AN INVERSE MODULE TITLE" << first_text;
    4124             concatenate("\\ref " + first_text + " \"" + second_text + "\"");
    4125         }
    4126         else if ((value = getFileTitle(first_text))) {
    4127             qDebug() << "USED AN INVERSE FILE TITLE" << first_text;
    4128         }
    4129         else if ((value = getHeaderFileTitle(first_text))) {
    4130             qDebug() << "USED AN INVERSE HEADER FILE TITLE" << first_text;
    4131         }
    4132         else if ((first_text.indexOf("::") >= 0) ||
    4133                  (first_text.indexOf("()") >= 0) ||
    4134                  (first_text[0] == 'Q')) {
    4135             //qDebug() << "AUTO-LINKABLE" << first_text;
    4136             if (first_text == second_text)
    4137                 concatenate(first_text);
    4138             else {
    4139                 QString link = first_text + " " + second_text;
    4140                 concatenate("\\link " + link + "\\endlink");
    4141             }
    4142         }
    4143         else {
    4144             QString link;
    4145             QStringList propertyClasses;
    4146             QStringList variableClasses;
    4147             QStringList enumClasses;
    4148             bool p = isProperty(first_text,propertyClasses);
    4149             bool v = isVariable(first_text,variableClasses);
    4150             bool e = isEnum(first_text,enumClasses);
    4151             if (e) {
    4152                 if (enumClasses.size() == 1)
    4153                     link = enumClasses[0];
    4154                 else if (enumClasses.contains(currentClass))
    4155                     link = currentClass;
    4156                 else {
    4157                     QString msg = "Unqualified enum name: " + first_text;
    4158                     QString details = "Classes: " + enumClasses.join(", ");
    4159                     priv->start_loc.error(msg,details);
    4160                 }
    4161                 if (!link.isEmpty())
    4162                     qDebug() << "FOUND ENUM" << link << first_text;
    4163             }
    4164             else if (p && v) {
    4165                 if (propertyClasses.size() == 1) {
    4166                     if (variableClasses.size() == 1) {
    4167                         if (propertyClasses[0] == variableClasses[0])
    4168                             link = propertyClasses[0];
    4169                     }
    4170                 }
    4171                 if (link.isEmpty()) {
    4172                     if (propertyClasses.contains(currentClass) ||
    4173                         variableClasses.contains(currentClass))
    4174                         link = currentClass;
    4175                     else {
    4176                         propertyClasses += variableClasses;
    4177                         QString msg = "Unqualified property or variable name: "
    4178                             + first_text;
    4179                         QString details = "Classes: " +
    4180                             propertyClasses.join(", ");
    4181                         priv->start_loc.error(msg,details);
    4182                     }
    4183                 }
    4184             }
    4185             else if (p) {
    4186                 if (propertyClasses.size() == 1)
    4187                     link = propertyClasses[0];
    4188                 else if (propertyClasses.contains(currentClass))
    4189                     link = currentClass;
    4190                 else {
    4191                     QString msg = "Unqualified property name: " + first_text;
    4192                     QString details = "Classes: " + propertyClasses.join(", ");
    4193                     priv->start_loc.error(msg,details);
    4194                 }
    4195             }
    4196             else if (v) {
    4197                 if (variableClasses.size() == 1)
    4198                     link = variableClasses[0];
    4199                 else if (variableClasses.contains(currentClass))
    4200                     link = currentClass;
    4201                 else {
    4202                     QString msg = "Unqualified variable name: " + first_text;
    4203                     QString details = "Classes: " + variableClasses.join(", ");
    4204                     priv->start_loc.error(msg,details);
    4205                 }
    4206             }
    4207             else {
    4208                 qDebug() << "NOT AUTO-LINKABLE" << first_text;
    4209                 QString s = first_text + " " + second_text;
    4210                 concatenate("\\link " + s + "\\endlink");
    4211             }
    4212             if (!link.isEmpty()) {
    4213                 link += "::" + first_text + " " + second_text;
    4214                 concatenate("\\link " + link + "\\endlink");
    4215             }
    4216         }
    4217     }
    4218     else
    4219         qDebug() << "LINK with no second parameter!!!!";
    4220     return next? next : atom;
    4221 }
    4222 
    4223 /*!
    4224   If the current line length is 0, the current line is
    4225   indented according to the context.
    4226  */
    4227 void DoxWriter::indentLine()
    4228 {
    4229     if (lineLength == 0) {
    4230         newText += DOXYGEN_INDENT_STRING;
    4231         lineLength = DOXYGEN_INDENT;
    4232         if (!structs.isEmpty()) {
    4233             for (int i=1; i<structs.size(); ++i) {
    4234                 newText += DOXYGEN_TAB_STRING;
    4235                 lineLength += DOXYGEN_TAB_SIZE;
    4236             }
    4237         }
    4238     }
    4239 }
    4240 
    4241 /*!
    4242   Concatenates a newline to the doxygen text, increments the
    4243   line count, and resets the line length to 0.
    4244  */
    4245 void DoxWriter::newLine()
    4246 {
    4247     newText += "\n";
    4248     ++lineCount;
    4249     lineLength = 0;
    4250 }
    4251 
    4252 static const int maxLineLength = 70;
    4253 
    4254 /*!
    4255   Concatenate the \a text to the doxygen comment currently
    4256   under construction and increment the current line length
    4257   by the size of the \a text.
    4258  
    4259   If incrementing the current line length by the \a text size
    4260   would make the current line length longer than the maximum
    4261   line length, then call newLine() and indentLine() \e before
    4262   concatenating the \a text.
    4263  */
    4264 void DoxWriter::concatenate(QString text)
    4265 {
    4266     if ((lineLength + text.size()) > maxLineLength)
    4267         newLine();
    4268     indentLine();
    4269     newText += text;
    4270     lineLength += text.size();
    4271 }
    4272 
    4273 static bool punctuation(QChar c)
    4274 {
    4275     switch (c.toAscii()) {
    4276     case '.':
    4277     case ',':
    4278     case ':':
    4279     case ';':
    4280     case '/':
    4281     case '+':
    4282     case '-':
    4283     case '?':
    4284     case '!':
    4285     case '\"':
    4286         return true;
    4287     default:
    4288         break;
    4289     }
    4290     return false;
    4291 }
    4292 
    4293 /*!
    4294   Concatenate the \a text string to the doxygen text, doing
    4295   line wrapping where necessary.
    4296  */
    4297 void DoxWriter::wrap(QString text)
    4298 {
    4299     int from = 0;
    4300     int to = -1;
    4301 
    4302     if ((lineLength == 0) || (lineLength >= maxLineLength)) {
    4303         if (!text.isEmpty() && (text[0] == ' '))
    4304             text = text.right(text.size() - 1);
    4305     }
    4306 
    4307     indentLine();
    4308     while (text.size()) {
    4309         int avail = maxLineLength - lineLength;
    4310         from = text.indexOf(' ',from);
    4311         if (from >= 0) {
    4312             if (from < avail)
    4313                 to = from++;
    4314             else if (from == 1 && punctuation(text[0]))
    4315                 to = from++;
    4316             else {
    4317                 if (to >= 0) {
    4318                     newText += text.left(to+1);
    4319                     lineLength += to + 1;
    4320                     text = text.right(text.size() - to - 1);
    4321                 }
    4322                 else {
    4323                     newLine();
    4324                     indentLine();
    4325                     newText += text.left(from+1);
    4326                     lineLength += from + 1;
    4327                     text = text.right(text.size() - from - 1);
    4328                 }
    4329                 from = 0;
    4330                 to = -1;
    4331                 if (text.size() && (lineLength > maxLineLength)) {
    4332                     newLine();
    4333                     indentLine();
    4334                 }
    4335             }
    4336         }
    4337         else
    4338             break;
    4339     }
    4340     if (text.size()) {
    4341         if (lineLength >= maxLineLength) {
    4342             newLine();
    4343             indentLine();
    4344         }
    4345         newText += text;
    4346         lineLength += text.size();
    4347     }
    4348 }
    4349 
    4350 /*!
    4351   This will output something, but it depends on what the
    4352   \a atom string and the \a next atom string are.
    4353  */
    4354 void DoxWriter::formattingLeft(const Atom* atom, const Atom* next)
    4355 {
    4356     if (atom->string() == "parameter") {
    4357         concatenate("\\a ");
    4358         return;
    4359     }
    4360     else if (atom->string() == "underline") {
    4361         concatenate("<u>");
    4362         return;
    4363     }
    4364     else if (atom->string() == "superscript") {
    4365         concatenate("<sup>");
    4366         return;
    4367     }
    4368     else if (atom->string() == "subscript") {
    4369         concatenate("<sub>");
    4370         return;
    4371     }
    4372     int ws = -1;
    4373     if (next)
    4374         ws = next->string().indexOf(ws_rx);
    4375     if (atom->string() == "bold") {
    4376         if (ws < 0)
    4377             concatenate("\\b ");
    4378         else
    4379             concatenate("<b>");
    4380     }
    4381     else if (atom->string() == "italic") {
    4382         if (ws < 0)
    4383             concatenate("\\e ");
    4384         else
    4385             concatenate("<i>");
    4386     }
    4387     else if (atom->string() == "teletype") {
    4388         if (ws < 0)
    4389             concatenate("\\c ");
    4390         else
    4391             concatenate("<tt>");
    4392     }
    4393     else
    4394         qDebug() << "UNHANDLED FormattingLeft: " << atom->string();
    4395 }
    4396 
    4397 /*!
    4398   This will output something, but it depends on what the
    4399   \a atom string and the \a prev atom string are.
    4400  */
    4401 void DoxWriter::formattingRight(const Atom* atom, const Atom* prev)
    4402 {
    4403     if (atom->string() == "parameter")
    4404         return;
    4405     else if (atom->string() == "underline") {
    4406         concatenate("</u>");
    4407         return;
    4408     }
    4409     else if (atom->string() == "superscript") {
    4410         concatenate("</sup>");
    4411         return;
    4412     }
    4413     else if (atom->string() == "subscript") {
    4414         concatenate("</sub>");
    4415         return;
    4416     }
    4417     int ws = -1;
    4418     if (prev)
    4419         ws = prev->string().indexOf(ws_rx);
    4420     if (ws < 0)
    4421         return;
    4422     if (atom->string() == "bold")
    4423         concatenate("</b>");
    4424     else if (atom->string() == "italic")
    4425         concatenate("</i>");
    4426     else if (atom->string() == "teletype")
    4427         concatenate("</tt>");
    4428     else
    4429         qDebug() << "UNHANDLED FormattingRight: " << atom->string();
    4430 }
    4431 
    4432 /*!
    4433   Output a \c or a <tt>...</tt>.
    4434  */
    4435 void DoxWriter::tt(const Atom* atom)
    4436 {
    4437     if (atom->string().indexOf(ws_rx) < 0) {
    4438         concatenate("\\c ");
    4439         concatenate(atom->string());
    4440     }
    4441     else {
    4442         concatenate("<tt>");
    4443         concatenate(atom->string());
    4444         concatenate("</tt>");
    4445     }
    4446 }
    4447 
    4448 /*!
    4449  */
    4450 void DoxWriter::formatIf(const Atom* atom)
    4451 {
    4452     if (atom->string() == "HTML") {
    4453         newLine();
    4454         concatenate("\\htmlonly");
    4455         newLine();
    4456     }
    4457 }
    4458 
    4459 /*!
    4460  */
    4461 void DoxWriter::formatEndif()
    4462 {
    4463     newLine();
    4464     concatenate("\\endhtmlonly");
    4465     newLine();
    4466 }
    4467 
    4468 /*!
    4469  */
    4470 void DoxWriter::formatElse()
    4471 {
    4472     // nothing.
    4473 }
    4474 
    4475 /*!
    4476   Pass 1: Construct a section identifier and insert it into
    4477   the anchor set.
    4478  
    4479   Pass 2: Convert section1, section2, and section3 commands
    4480   to section, subsection, and subsubsection respectively.
    4481   Warn if a section command higher than 3 is seen.
    4482  */
    4483 const Atom* DoxWriter::sectionHeading(const Atom* atom)
    4484 {
    4485     QString heading_level = atom->string();
    4486     QString heading_text;
    4487     const Atom* next = atom->next();
    4488     while (next) {
    4489         next->dump();
    4490         if (next->type() == Atom::SectionHeadingRight) {
    4491             if (next->string() == heading_level)
    4492                 break;
    4493             else {
    4494                 qDebug() << "WRONG SectionHeading number!!!!";
    4495             }
    4496         }
    4497         else
    4498             heading_text += next->string();
    4499         next = next->next();
    4500     }
    4501 
    4502     QString heading_identifier = heading_text;
    4503     heading_identifier.remove(ws_rx);
    4504    
    4505     newLine();
    4506     if (heading_level == "1")
    4507         heading_level = "\\section ";
    4508     else if (heading_level == "2")
    4509         heading_level = "\\subsection ";
    4510     else if (heading_level == "3")
    4511         heading_level = "\\subsubsection ";
    4512     else if (heading_level == "4") {
    4513         heading_level = "\\subsubsection ";
    4514         qDebug() << "WARNING section4 converted to \\subsubsection";
    4515     }
    4516     else {
    4517         heading_level = "\\subsubsection ";
    4518         qDebug() << "WARNING section5 converted to \\subsubsection";
    4519     }
    4520     concatenate(heading_level);
    4521     newText += heading_identifier + " ";
    4522     lineLength += heading_identifier.size() + 1;
    4523     newText += heading_text;
    4524     lineLength += heading_text.size();
    4525     newLine();
    4526     return next? next : atom;
    4527 }
    4528 
    4529 /*!
    4530   Report an unhandled atom.
    4531  */
    4532 void DoxWriter::unhandled(const Atom* atom)
    4533 {
    4534     qDebug() << "UNHANDLED ATOM";
    4535     atom->dump();
    4536 }
    4537 
    4538 /*!
    4539   Output a code/endcode block.
    4540  */
    4541 void DoxWriter::code(const Atom* atom)
    4542 {
    4543     newLine();
    4544     concatenate("\\code");
    4545     writeCode(atom->string());
    4546     concatenate("\\endcode");
    4547     newLine();
    4548 }
    4549 
    4550 /*!
    4551   Output a code/endcode block depending on the
    4552   CodeQuote Command and CodeQuoteArgument parameters.
    4553  */
    4554 const Atom* DoxWriter::codeQuoteCommand(const Atom* atom)
    4555 {
    4556     QString command = atom->string();
    4557     atom = atom->next();
    4558     concatenate("\\code");
    4559     if (command == "codeline") {
    4560         newLine();
    4561         concatenate(atom->string());
    4562         newLine();
    4563     }
    4564     else if (command == "dots") {
    4565         newLine();
    4566         concatenate(atom->string());
    4567         newLine();
    4568     }
    4569     else {
    4570         writeCode(atom->string());
    4571     }
    4572     concatenate("\\endcode");
    4573     return atom;
    4574 }
    4575 
    4576 /*!
    4577   Appends a block of code to the comment.
    4578  */
    4579 void DoxWriter::writeCode(QString text)
    4580 {
    4581     int cr_count = text.count('\n') - 1;
    4582     if (cr_count >= 0) {
    4583         int last_cr = text.lastIndexOf('\n');
    4584         newText += text.left(last_cr);
    4585         lineCount += cr_count;
    4586     }
    4587     else
    4588         newText += text;
    4589     newLine();
    4590 }
    4591 
    4592 /*!
    4593   Inserts \a text into the anchor set. This function is called
    4594   during doxygen pass 1.
    4595  */
    4596 void DoxWriter::insertAnchor(const QString& text)
    4597 {
    4598     anchors.insert(text);
    4599 }
    4600 
    4601 /*!
    4602   Returns true if \a text identifies an anchor, section,
    4603   subsection, subsubsection, or page.
    4604  */
    4605 bool DoxWriter::isAnchor(const QString& text)
    4606 {
    4607     return anchors.contains(text);
    4608 }
    4609 
    4610 /*!
    4611   Write the set of anchors to a file, one per line.
    4612  */
    4613 void DoxWriter::writeAnchors()
    4614 {
    4615     QFile file("anchors.txt");
    4616     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    4617         qWarning("Unable to open anchors.txt for writing.");
    4618         return;
    4619     }
    4620    
    4621     QTextStream out(&file);
    4622     QSet<QString>::const_iterator i = anchors.constBegin();
    4623     while (i != anchors.constEnd()) {
    4624         out << *i << "\n";
    4625         ++i;
    4626     }
    4627     file.close();
    4628 }
    4629 
    4630 /*!
    4631   Read the set of anchors from the anchors file, one per line,
    4632   and insert each one into the anchor set.
    4633  */
    4634 void DoxWriter::readAnchors()
    4635 {
    4636     QFile file("anchors.txt");
    4637     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    4638         qWarning("Unable to open anchors.txt for reading.");
    4639         return;
    4640     }
    4641    
    4642     QTextStream in(&file);
    4643     while (!in.atEnd()) {
    4644         QString line = in.readLine();
    4645         anchors.insert(line);
    4646     }
    4647     file.close();
    4648 #if 0   
    4649     QSet<QString>::const_iterator i = anchors.constBegin();
    4650     while (i != anchors.constEnd()) {
    4651         qDebug() << *i;
    4652         ++i;
    4653     }
    4654 #endif   
    4655 }
    4656 
    4657 /*!
    4658   Inserts \a title into one of the title maps. \a title is
    4659   mapped to the \a node name. This function is called during
    4660   doxygen pass 1.
    4661  */
    4662 void DoxWriter::insertTitle(FakeNode* node, const QString& title)
    4663 {
    4664     switch (node->subType()) {
    4665     case FakeNode::Example:
    4666         if (exampleTitles.contains(title)) {
    4667             qWarning() << "DoxWriter::insertTitle():"
    4668                        << "Duplicate example title:"
    4669                        << title;
    4670         }
    4671         else {
    4672             exampleTitles[title] = node->name();
    4673             exampleTitlesInverse[node->name()] = title;
    4674         }
    4675         break;
    4676     case FakeNode::HeaderFile:
    4677         if (headerFileTitles.contains(title)) {
    4678             qWarning() << "DoxWriter::insertTitle():"
    4679                        << "Duplicate header file title:"
    4680                        << title;
    4681         }
    4682         else {
    4683             headerFileTitles[title] = node->name();
    4684             headerFileTitlesInverse[node->name()] = title;
    4685         }
    4686         break;
    4687     case FakeNode::File:
    4688         if (fileTitles.contains(title)) {
    4689             qWarning() << "DoxWriter::insertTitle():"
    4690                        << "Duplicate file title:"
    4691                        << title;
    4692         }
    4693         else {
    4694             fileTitles[title] = node->name();
    4695             fileTitlesInverse[node->name()] = title;
    4696         }
    4697         break;
    4698     case FakeNode::Group:
    4699         if (groupTitles.contains(title)) {
    4700             qWarning() << "DoxWriter::insertTitle():"
    4701                        << "Duplicate group title:"
    4702                        << title;
    4703         }
    4704         else {
    4705             groupTitles[title] = node->name();
    4706             groupTitlesInverse[node->name()] = title;
    4707         }
    4708         break;
    4709     case FakeNode::Module:
    4710         if (moduleTitles.contains(title)) {
    4711             qWarning() << "DoxWriter::insertTitle():"
    4712                        << "Duplicate module title:"
    4713                        << title;
    4714         }
    4715         else {
    4716             moduleTitles[title] = node->name();
    4717             moduleTitlesInverse[node->name()] = title;
    4718         }
    4719         break;
    4720     case FakeNode::Page:
    4721         if (pageTitles.contains(title)) {
    4722             qWarning() << "DoxWriter::insertTitle():"
    4723                        << "Duplicate page title:"
    4724                        << title;
    4725         }
    4726         else {
    4727             pageTitles[title] = node->name();
    4728             pageTitlesInverse[node->name()] = title;
    4729         }
    4730         break;
    4731     case FakeNode::ExternalPage:
    4732         if (externalPageTitles.contains(title)) {
    4733             qWarning() << "DoxWriter::insertTitle():"
    4734                        << "Duplicate external page title:"
    4735                        << title;
    4736         }
    4737         else {
    4738             externalPageTitles[title] = node->name();
    4739             externalPageTitlesInverse[node->name()] = title;
    4740         }
    4741         break;
    4742     default:
    4743         break;
    4744     }
    4745 }
    4746 
    4747 /*!
    4748  */
    4749 const QString* DoxWriter::getPageFile(const QString& title)
    4750 {
    4751     QStringMapEntry entry = pageTitles.find(title);
    4752     return (entry == pageTitles.end()) ? 0 : &entry.value();
    4753 }
    4754 
    4755 /*!
    4756  */
    4757 const QString* DoxWriter::getExamplePath(const QString& title)
    4758 {
    4759     QStringMapEntry entry = exampleTitles.find(title);
    4760     return (entry == exampleTitles.end()) ? 0 : &entry.value();
    4761 }
    4762 
    4763 /*!
    4764  */
    4765 const QString* DoxWriter::getFile(const QString& title)
    4766 {
    4767     QStringMapEntry entry = fileTitles.find(title);
    4768     return (entry == fileTitles.end()) ? 0 : &entry.value();
    4769 }
    4770 
    4771 /*!
    4772  */
    4773 const QString* DoxWriter::getHeaderFile(const QString& title)
    4774 {
    4775     QStringMapEntry entry = headerFileTitles.find(title);
    4776     return (entry == headerFileTitles.end()) ? 0 : &entry.value();
    4777 }
    4778 
    4779 /*!
    4780  */
    4781 const QString* DoxWriter::getGroup(const QString& title)
    4782 {
    4783     QStringMapEntry entry = groupTitles.find(title);
    4784     return (entry == groupTitles.end()) ? 0 : &entry.value();
    4785 }
    4786 
    4787 /*!
    4788  */
    4789 const QString* DoxWriter::getModule(const QString& title)
    4790 {
    4791     QStringMapEntry entry = moduleTitles.find(title);
    4792     return (entry == moduleTitles.end()) ? 0 : &entry.value();
    4793 }
    4794 
    4795 /*!
    4796  */
    4797 const QString* DoxWriter::getExternalPage(const QString& title)
    4798 {
    4799     QStringMapEntry entry = externalPageTitles.find(title);
    4800     return (entry == externalPageTitles.end()) ? 0 : &entry.value();
    4801 }
    4802 
    4803 /*!
    4804  */
    4805 const QString* DoxWriter::getPageTitle(const QString& text)
    4806 {
    4807     QStringMapEntry entry = pageTitlesInverse.find(text);
    4808     return (entry == pageTitlesInverse.end()) ? 0 : &entry.value();
    4809 }
    4810 
    4811 /*!
    4812  */
    4813 const QString* DoxWriter::getExampleTitle(const QString& text)
    4814 {
    4815     QStringMapEntry entry = exampleTitlesInverse.find(text);
    4816     return (entry == exampleTitlesInverse.end()) ? 0 : &entry.value();
    4817 }
    4818 
    4819 /*!
    4820  */
    4821 const QString* DoxWriter::getFileTitle(const QString& text)
    4822 {
    4823     QStringMapEntry entry = fileTitlesInverse.find(text);
    4824     return (entry == fileTitlesInverse.end()) ? 0 : &entry.value();
    4825 }
    4826 
    4827 /*!
    4828  */
    4829 const QString* DoxWriter::getHeaderFileTitle(const QString& text)
    4830 {
    4831     QStringMapEntry entry = headerFileTitlesInverse.find(text);
    4832     return (entry == headerFileTitlesInverse.end()) ? 0 : &entry.value();
    4833 }
    4834 
    4835 /*!
    4836  */
    4837 const QString* DoxWriter::getGroupTitle(const QString& text)
    4838 {
    4839     QStringMapEntry entry = groupTitlesInverse.find(text);
    4840     return (entry == groupTitlesInverse.end()) ? 0 : &entry.value();
    4841 }
    4842 
    4843 /*!
    4844  */
    4845 const QString* DoxWriter::getModuleTitle(const QString& text)
    4846 {
    4847     QStringMapEntry entry = moduleTitlesInverse.find(text);
    4848     return (entry == moduleTitlesInverse.end()) ? 0 : &entry.value();
    4849 }
    4850 
    4851 /*!
    4852  */
    4853 const QString* DoxWriter::getExternalPageTitle(const QString& text)
    4854 {
    4855     QStringMapEntry entry = externalPageTitlesInverse.find(text);
    4856     return (entry == externalPageTitlesInverse.end()) ? 0 : &entry.value();
    4857 }
    4858 
    4859 /*!
    4860   Serialize \a map to file \a name.
    4861  */
    4862 void DoxWriter::writeMap(const QStringMap& map, const QString& name)
    4863 {
    4864 
    4865     QFile file(name);
    4866     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    4867         qWarning() << "Unable to open" << name << "for writing.";
    4868         return;
    4869     }
    4870    
    4871     QTextStream out(&file);
    4872     QStringMap::const_iterator i = map.constBegin();
    4873     while (i != map.constEnd()) {
    4874         out << i.key() << "\n";
    4875         out << i.value() << "\n";
    4876         ++i;
    4877     }
    4878     file.close();
    4879 }
    4880 
    4881 /*!
    4882   Read file \a name into the \a map.
    4883  */
    4884 void DoxWriter::readMap(QStringMap& map, QStringMap& inverseMap, const QString& name)
    4885 {
    4886     QFile file(name);
    4887     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    4888         qWarning() << "Unable to open" << name << "for reading.";
    4889         return;
    4890     }
    4891    
    4892     QTextStream in(&file);
    4893     while (!in.atEnd()) {
    4894         QString title = in.readLine();
    4895         QString value = in.readLine();
    4896         map[title] = value;
    4897         inverseMap[value] = title;
    4898     }
    4899     file.close();
    4900 }
    4901 
    4902 /*!
    4903   Write the sets of titles to text files, one per line.
    4904  */
    4905 void DoxWriter::writeTitles()
    4906 {
    4907     if (!pageTitles.isEmpty())
    4908         writeMap(pageTitles,"pagetitles.txt");
    4909     if (!fileTitles.isEmpty())
    4910         writeMap(fileTitles,"filetitles.txt");
    4911     if (!headerFileTitles.isEmpty())
    4912         writeMap(headerFileTitles,"headerfiletitles.txt");
    4913     if (!exampleTitles.isEmpty())
    4914         writeMap(exampleTitles,"exampletitles.txt");
    4915     if (!moduleTitles.isEmpty())
    4916         writeMap(moduleTitles,"moduletitles.txt");
    4917     if (!groupTitles.isEmpty())
    4918         writeMap(groupTitles,"grouptitles.txt");
    4919     if (!externalPageTitles.isEmpty())
    4920         writeMap(externalPageTitles,"externalpagetitles.txt");
    4921 }
    4922 
    4923 /*!
    4924   Read the sets of titles from the titles files, one per line,
    4925   and insert each one into the appropriate title set.
    4926  */
    4927 void DoxWriter::readTitles()
    4928 {
    4929     readMap(pageTitles,pageTitlesInverse,"pagetitles.txt");
    4930     readMap(fileTitles,fileTitlesInverse,"filetitles.txt");
    4931     readMap(headerFileTitles,headerFileTitlesInverse,"headerfiletitles.txt");
    4932     readMap(exampleTitles,exampleTitlesInverse,"exampletitles.txt");
    4933     readMap(moduleTitles,moduleTitlesInverse,"moduletitles.txt");
    4934     readMap(groupTitles,groupTitlesInverse,"grouptitles.txt");
    4935     readMap(externalPageTitles,
    4936             externalPageTitlesInverse,
    4937             "externalpagetitles.txt");
    4938 }
    4939 
    4940 /*!
    4941   Serialize \a map to file \a name.
    4942  */
    4943 void DoxWriter::writeMultiMap(const QStringMultiMap& map, const QString& name)
    4944 {
    4945 
    4946     QFile file(name);
    4947     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    4948         qWarning() << "Unable to open" << name << "for writing.";
    4949         return;
    4950     }
    4951    
    4952     QTextStream out(&file);
    4953     QStringMultiMap::const_iterator i = map.constBegin();
    4954     while (i != map.constEnd()) {
    4955         out << i.key() << "\n";
    4956         out << i.value() << "\n";
    4957         ++i;
    4958     }
    4959     file.close();
    4960 }
    4961 
    4962 /*!
    4963   Write the4 property names and variable names to text files.
    4964  */
    4965 void DoxWriter::writeMembers()
    4966 {
    4967     if (!variables.isEmpty())
    4968         writeMultiMap(variables,"variables.txt");
    4969     if (!properties.isEmpty())
    4970         writeMultiMap(properties,"properties.txt");
    4971     if (!enums.isEmpty())
    4972         writeMultiMap(enums,"enums.txt");
    4973 }
    4974 
    4975 /*!
    4976   Read file \a name into the \a map.
    4977  */
    4978 void DoxWriter::readMultiMap(QStringMultiMap& map, const QString& name)
    4979 {
    4980     QFile file(name);
    4981     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    4982         qWarning() << "Unable to open" << name << "for reading.";
    4983         return;
    4984     }
    4985    
    4986     QTextStream in(&file);
    4987     while (!in.atEnd()) {
    4988         QString member = in.readLine();
    4989         QString className = in.readLine();
    4990         map.insert(member,className);
    4991     }
    4992     file.close();
    4993 }
    4994 
    4995 /*!
    4996   Read the property names and variable names from the test files.
    4997  */
    4998 void DoxWriter::readMembers()
    4999 {
    5000     readMultiMap(variables,"variables.txt");
    5001     readMultiMap(properties,"properties.txt");
    5002     readMultiMap(enums,"enums.txt");
    5003 }
    5004 
    5005 /*!
    5006   Return true if \a name is a property. Loads \a classes with
    5007   the names of all the classes in which \a name is a property.
    5008  */
    5009 bool DoxWriter::isProperty(const QString& name, QStringList& classes)
    5010 {
    5011     classes = properties.values(name);
    5012     return !classes.isEmpty();
    5013 }
    5014 
    5015 /*!
    5016   Return true if \a name is a variable. Loads \a classes with
    5017   the names of all the classes in which \a name is a variable.
    5018  */
    5019 bool DoxWriter::isVariable(const QString& name, QStringList& classes)
    5020 {
    5021     classes = variables.values(name);
    5022     return !classes.isEmpty();
    5023 }
    5024 
    5025 /*!
    5026   Return true if \a name is an enum type. Loads \a classes with
    5027   the names of all the classes in which \a name is an enum type.
    5028  */
    5029 bool DoxWriter::isEnum(const QString& name, QStringList& classes)
    5030 {
    5031     classes = enums.values(name);
    5032     return !classes.isEmpty();
    5033 }
    5034 #endif
    5035 
    50363085QT_END_NAMESPACE
Note: See TracChangeset for help on using the changeset viewer.