Changeset 561 for trunk/tools/linguist


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

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
10 deleted
79 edited
13 copied

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/tools/linguist/lconvert/main.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 Qt Linguist 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**
     
    4747#include <QtCore/QStringList>
    4848
     49#include <iostream>
     50
    4951static int usage(const QStringList &args)
    5052{
     
    5254
    5355    QString loaders;
    54     QString savers;
    55     QString line = QString(QLatin1String("    %1 - %2\n"));
    56     foreach (Translator::FileFormat format, Translator::registeredFileFormats()) {
     56    QString line(QLatin1String("    %1 - %2\n"));
     57    foreach (Translator::FileFormat format, Translator::registeredFileFormats())
    5758        loaders += line.arg(format.extension, -5).arg(format.description);
    58         if (format.fileType != Translator::FileFormat::SourceCode)
    59             savers += line.arg(format.extension, -5).arg(format.description);
    60     }
    61 
    62     qWarning("%s", qPrintable(QString(QLatin1String("\nUsage:\n"
     59
     60    std::cerr << qPrintable(QString(QLatin1String("\nUsage:\n"
    6361        "    lconvert [options] <infile> [<infile>...]\n\n"
    6462        "lconvert is part of Qt's Linguist tool chain. It can be used as a\n"
    65         "stand-alone tool to convert translation data files from one of the\n"
    66         "following input formats\n\n%1\n"
    67         "to one of the following output formats\n\n%2\n"
    68         "If multiple input files are specified the translations are merged with\n"
     63        "stand-alone tool to convert and filter translation data files.\n"
     64        "The following file formats are supported:\n\n%1\n"
     65        "If multiple input files are specified, they are merged with\n"
    6966        "translations from later files taking precedence.\n\n"
    7067        "Options:\n"
     
    8683        "    --output-format <outformat>\n"
    8784        "           Specify output format. See -if.\n\n"
     85        "    --input-codec <codec>\n"
     86        "           Specify encoding for QM and PO input files. Default is 'Latin1'\n"
     87        "           for QM and 'UTF-8' for PO files. UTF-8 is always tried as well for\n"
     88        "           QM, corresponding to the possible use of the trUtf8() function.\n\n"
     89        "    --output-codec <codec>\n"
     90        "           Specify encoding for PO output files. Default is 'UTF-8'.\n\n"
    8891        "    --drop-tags <regexp>\n"
    89         "           Drop named extra tags when writing 'ts' or 'xlf' files.\n"
     92        "           Drop named extra tags when writing TS or XLIFF files.\n"
    9093        "           May be specified repeatedly.\n\n"
    9194        "    --drop-translations\n"
     
    9497        "    --source-language <language>[_<region>]\n"
    9598        "           Specify/override the language of the source strings. Defaults to\n"
    96         "           POSIX if not specified and the file does not name it yet.\n"
     99        "           POSIX if not specified and the file does not name it yet.\n\n"
    97100        "    --target-language <language>[_<region>]\n"
    98101        "           Specify/override the language of the translation.\n"
     
    103106        "    --no-finished\n"
    104107        "           Drop finished messages.\n\n"
     108        "    --sort-contexts\n"
     109        "           Sort contexts in output TS file alphabetically.\n\n"
     110        "    --locations {absolute|relative|none}\n"
     111        "           Override how source code references are saved in TS files.\n"
     112        "           Default is absolute.\n\n"
     113        "    --no-ui-lines\n"
     114        "           Drop line numbers from references to UI files.\n\n"
    105115        "    --verbose\n"
    106116        "           be a bit more verbose\n\n"
     
    110120        "    1 on command line parse failures\n"
    111121        "    2 on read failures\n"
    112         "    3 on write failures\n")).arg(loaders).arg(savers)));
     122        "    3 on write failures\n")).arg(loaders));
    113123    return 1;
    114124}
     
    135145    bool noFinished = false;
    136146    bool verbose = false;
     147    bool noUiLines = false;
     148    Translator::LocationsType locations = Translator::DefaultLocations;
    137149
    138150    ConversionData cd;
     
    165177                return usage(args);
    166178            inFormat = args[i];
     179        } else if (args[i] == QLatin1String("-input-codec")) {
     180            if (++i >= args.size())
     181                return usage(args);
     182            cd.m_codecForSource = args[i].toLatin1();
     183        } else if (args[i] == QLatin1String("-output-codec")) {
     184            if (++i >= args.size())
     185                return usage(args);
     186            cd.m_outputCodec = args[i].toLatin1();
    167187        } else if (args[i] == QLatin1String("-drop-tag")) {
    168188            if (++i >= args.size())
     
    186206        } else if (args[i] == QLatin1String("-no-finished")) {
    187207            noFinished = true;
     208        } else if (args[i] == QLatin1String("-sort-contexts")) {
     209            cd.m_sortContexts = true;
     210        } else if (args[i] == QLatin1String("-locations")) {
     211            if (++i >= args.size())
     212                return usage(args);
     213            if (args[i] == QLatin1String("none"))
     214                locations = Translator::NoLocations;
     215            else if (args[i] == QLatin1String("relative"))
     216                locations = Translator::RelativeLocations;
     217            else if (args[i] == QLatin1String("absolute"))
     218                locations = Translator::AbsoluteLocations;
     219            else
     220                return usage(args);
     221        } else if (args[i] == QLatin1String("-no-ui-lines")) {
     222            noUiLines = true;
    188223        } else if (args[i] == QLatin1String("-verbose")) {
    189224            verbose = true;
     
    202237
    203238    tr.setLanguageCode(Translator::guessLanguageCodeFromFileName(inFiles[0].name));
    204     if (!targetLanguage.isEmpty())
    205         tr.setLanguageCode(targetLanguage);
    206     if (!sourceLanguage.isEmpty())
    207         tr.setSourceLanguageCode(sourceLanguage);
    208239
    209240    if (!tr.load(inFiles[0].name, cd, inFiles[0].format)) {
     
    211242        return 2;
    212243    }
    213     Translator::reportDuplicates(tr.resolveDuplicates(), inFiles[0].name, verbose);
     244    tr.reportDuplicates(tr.resolveDuplicates(), inFiles[0].name, verbose);
    214245
    215246    for (int i = 1; i < inFiles.size(); ++i) {
     
    219250            return 2;
    220251        }
    221         Translator::reportDuplicates(tr2.resolveDuplicates(), inFiles[i].name, verbose);
     252        tr2.reportDuplicates(tr2.resolveDuplicates(), inFiles[i].name, verbose);
    222253        for (int j = 0; j < tr2.messageCount(); ++j)
    223254            tr.replaceSorted(tr2.message(j));
    224255    }
    225256
     257    if (!targetLanguage.isEmpty())
     258        tr.setLanguageCode(targetLanguage);
     259    if (!sourceLanguage.isEmpty())
     260        tr.setSourceLanguageCode(sourceLanguage);
    226261    if (noObsolete)
    227262        tr.stripObsoleteMessages();
     
    230265    if (dropTranslations)
    231266        tr.dropTranslations();
    232 
     267    if (noUiLines)
     268        tr.dropUiLines();
     269    if (locations != Translator::DefaultLocations)
     270        tr.setLocationsType(locations);
     271
     272    tr.normalizeTranslations(cd);
     273    if (!cd.errors().isEmpty()) {
     274        qWarning("%s", qPrintable(cd.error()));
     275        cd.clearErrors();
     276    }
    233277    if (!tr.save(outFileName, cd, outFormat)) {
    234278        qWarning("%s", qPrintable(cd.error()));
  • trunk/tools/linguist/linguist/batchtranslation.ui

    r2 r561  
    44**
    55** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    6 ** Contact: Qt Software Information (qt-info@nokia.com)
     6** All rights reserved.
     7** Contact: Nokia Corporation (qt-info@nokia.com)
    78**
    89** This file is part of the Qt Linguist of the Qt Toolkit.
     
    2324** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2425**
    25 ** In addition, as a special exception, Nokia gives you certain
    26 ** additional rights. These rights are described in the Nokia Qt LGPL
    27 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    28 ** package.
     26** In addition, as a special exception, Nokia gives you certain additional
     27** rights.  These rights are described in the Nokia Qt LGPL Exception
     28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2929**
    3030** GNU General Public License Usage
     
    3636** met: http://www.gnu.org/copyleft/gpl.html.
    3737**
    38 ** If you are unsure which license is appropriate for your use, please
    39 ** contact the sales department at qt-sales@nokia.com.
     38** If you have questions regarding the use of this file, please contact
     39** Nokia at qt-info@nokia.com.
    4040** $QT_END_LICENSE$
    4141**
     
    105105       <widget class="QCheckBox" name="ckTranslateFinished">
    106106        <property name="toolTip">
    107          <string>Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked.</string>
     107         <string>Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked</string>
    108108        </property>
    109109        <property name="text">
     
    190190       <widget class="QLabel" name="label">
    191191        <property name="text">
    192          <string>The batch translator will search through the selected phrase books in the order given above.</string>
     192         <string>The batch translator will search through the selected phrase books in the order given above</string>
    193193        </property>
    194194        <property name="wordWrap">
  • trunk/tools/linguist/linguist/batchtranslationdialog.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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/batchtranslationdialog.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/errorsview.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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/errorsview.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/finddialog.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 Qt Linguist 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**
     
    5858
    5959    connect(findNxt, SIGNAL(clicked()), this, SLOT(emitFindNext()));
    60     connect(led, SIGNAL(textChanged(const QString &)), this, SLOT(verifyText(const QString &)));
     60    connect(led, SIGNAL(textChanged(QString)), this, SLOT(verifyText(QString)));
    6161
    6262    led->setFocus();
  • trunk/tools/linguist/linguist/finddialog.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/finddialog.ui

    r2 r561  
    44**
    55** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    6 ** Contact: Qt Software Information (qt-info@nokia.com)
     6** All rights reserved.
     7** Contact: Nokia Corporation (qt-info@nokia.com)
    78**
    89** This file is part of the Qt Linguist of the Qt Toolkit.
     
    2324** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2425**
    25 ** In addition, as a special exception, Nokia gives you certain
    26 ** additional rights. These rights are described in the Nokia Qt LGPL
    27 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    28 ** package.
     26** In addition, as a special exception, Nokia gives you certain additional
     27** rights.  These rights are described in the Nokia Qt LGPL Exception
     28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2929**
    3030** GNU General Public License Usage
     
    3636** met: http://www.gnu.org/copyleft/gpl.html.
    3737**
    38 ** If you are unsure which license is appropriate for your use, please
    39 ** contact the sales department at qt-sales@nokia.com.
     38** If you have questions regarding the use of this file, please contact
     39** Nokia at qt-info@nokia.com.
    4040** $QT_END_LICENSE$
    4141**
  • trunk/tools/linguist/linguist/formpreviewview.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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/formpreviewview.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/linguist.pro

    r511 r561  
    33DESTDIR = ../../../bin
    44
    5 QT += xml \
    6     network
     5QT += xml
    76
    87CONFIG += qt \
     
    2726    finddialog.cpp \
    2827    formpreviewview.cpp \
     28    globals.cpp \
    2929    main.cpp \
    3030    mainwindow.cpp \
     
    5050    finddialog.h \
    5151    formpreviewview.h \
     52    globals.h \
    5253    mainwindow.h \
    5354    messageeditor.h \
     
    8283target.path = $$[QT_INSTALL_BINS]
    8384INSTALLS += target
    84 linguisttranslations.files = *.qm
    85 linguisttranslations.path = $$[QT_INSTALL_TRANSLATIONS]
    86 INSTALLS += linguisttranslations
    8785phrasebooks.path = $$[QT_INSTALL_DATA]/phrasebooks
    8886
     
    9997RESOURCES += linguist.qrc
    10098
    101 TRANSLATIONS=$$[QT_INSTALL_TRANSLATIONS]/linguist_ja.ts \
    102              $$[QT_INSTALL_TRANSLATIONS]/linguist_pl.ts \
    103              $$[QT_INSTALL_TRANSLATIONS]/linguist_untranslated.ts \
    104              $$[QT_INSTALL_TRANSLATIONS]/linguist_zh_CN.ts \
    105              $$[QT_INSTALL_TRANSLATIONS]/linguist_zh_TW.ts \
    106              $$[QT_INSTALL_TRANSLATIONS]/linguist_de.ts \
    107              $$[QT_INSTALL_TRANSLATIONS]/linguist_fr.ts
     99TR_DIR = $$PWD/../../../translations
     100TRANSLATIONS = \
     101    $$TR_DIR/linguist_de.ts \
     102    $$TR_DIR/linguist_fr.ts \
     103    $$TR_DIR/linguist_ja.ts \
     104    $$TR_DIR/linguist_pl.ts \
     105    $$TR_DIR/linguist_ru.ts \
     106    $$TR_DIR/linguist_zh_CN.ts \
     107    $$TR_DIR/linguist_zh_TW.ts
    108108
    109109include(../../../src/qt_targets.pri)
  • trunk/tools/linguist/linguist/linguist.qrc

    r2 r561  
    3333        <file>images/down.png</file>
    3434        <file>images/editdelete.png</file>
     35        <file>images/minus.png</file>
     36        <file>images/plus.png</file>
    3537        <file>images/win/accelerator.png</file>
    3638        <file>images/win/book.png</file>
  • trunk/tools/linguist/linguist/linguist.rc

    r2 r561  
     1#include "winver.h"
     2
    13IDI_ICON1               ICON            DISCARDABLE     "linguist.ico"
     4
     5VS_VERSION_INFO VERSIONINFO
     6 FILEVERSION 1,0,0,0
     7 PRODUCTVERSION 1,0,0,0
     8 FILEFLAGS 0x0L
     9 FILEFLAGSMASK 0x3fL
     10 FILEOS 0x00040004L
     11 FILETYPE 0x1L
     12 FILESUBTYPE 0x0L
     13BEGIN
     14    BLOCK "StringFileInfo"
     15    BEGIN
     16        BLOCK "000004b0"
     17        BEGIN
     18            VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)"
     19            VALUE "FileDescription", "Qt Linguist"
     20            VALUE "FileVersion", "1.0.0.0"
     21            VALUE "LegalCopyright", "Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)."
     22            VALUE "InternalName", "linguist"
     23            VALUE "OriginalFilename", "linguist.exe"
     24            VALUE "ProductName", "Qt Linguist"
     25            VALUE "ProductVersion", "1.0.0.0"
     26        END
     27    END
     28    BLOCK "VarFileInfo"
     29    BEGIN
     30        VALUE "Translation", 0x0, 1200
     31    END
     32END
  • trunk/tools/linguist/linguist/main.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 Qt Linguist 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**
     
    4141
    4242#include "mainwindow.h"
     43#include "globals.h"
    4344
    4445#include <QtCore/QFile>
     
    8182
    8283    QTranslator translator;
    83     translator.load(QLatin1String("linguist_") + QLocale::system().name(), resourceDir);
    84     app.installTranslator(&translator);
    85 
    8684    QTranslator qtTranslator;
    87     qtTranslator.load(QLatin1String("qt_") + QLocale::system().name(), resourceDir);
    88     app.installTranslator(&qtTranslator);
     85    QString sysLocale = QLocale::system().name();
     86    if (translator.load(QLatin1String("linguist_") + sysLocale, resourceDir)) {
     87        app.installTranslator(&translator);
     88        if (qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir))
     89            app.installTranslator(&qtTranslator);
     90        else
     91            app.removeTranslator(&translator);
     92    }
    8993
    9094    app.setOrganizationName(QLatin1String("Trolltech"));
    9195    app.setApplicationName(QLatin1String("Linguist"));
    92     QString keybase(QString::number( (QT_VERSION >> 16) & 0xff ) +
    93         QLatin1Char('.') + QString::number( (QT_VERSION >> 8) & 0xff ) + QLatin1Char('/') );
    9496
    9597    QSettings config;
    9698
    9799    QWidget tmp;
    98     tmp.restoreGeometry(config.value(keybase + QLatin1String("Geometry/WindowGeometry")).toByteArray());
     100    tmp.restoreGeometry(config.value(settingPath("Geometry/WindowGeometry")).toByteArray());
    99101
    100102    QSplashScreen *splash = 0;
  • trunk/tools/linguist/linguist/mainwindow.cpp

    r511 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 Qt Linguist 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**
     
    5151#include "finddialog.h"
    5252#include "formpreviewview.h"
     53#include "globals.h"
    5354#include "messageeditor.h"
    5455#include "messagemodel.h"
     
    8283#include <QMessageBox>
    8384#include <QPrintDialog>
     85#include <QPrinter>
    8486#include <QProcess>
    8587#include <QRegExp>
     
    9799static const int MessageMS = 2500;
    98100
    99 const QString &settingsPrefix()
    100 {
    101     static QString prefix = QString(QLatin1String("%1.%2/"))
    102         .arg((QT_VERSION >> 16) & 0xff)
    103         .arg((QT_VERSION >> 8) & 0xff);
    104     return prefix;
    105 }
    106 
    107101enum Ending {
    108102    End_None,
     
    122116{
    123117    str = str.simplified();
    124     int ch = 0;
    125     if (!str.isEmpty())
    126         ch = str.right(1)[0].unicode();
    127 
    128     switch (ch) {
     118    if (str.isEmpty())
     119        return End_None;
     120
     121    switch (str.at(str.length() - 1).unicode()) {
    129122    case 0x002e: // full stop
    130         if (str.endsWith(QString(QLatin1String("..."))))
     123        if (str.endsWith(QLatin1String("...")))
    131124            return End_Ellipsis;
    132125        else
     
    266259    : QMainWindow(0, Qt::Window),
    267260      m_assistantProcess(0),
     261      m_printer(0),
    268262      m_findMatchCase(Qt::CaseInsensitive),
    269263      m_findIgnoreAccelerators(true),
     
    276270      m_statistics(0)
    277271{
     272    setUnifiedTitleAndToolBarOnMac(true);
    278273    m_ui.setupUi(this);
    279274
     
    311306    m_contextView->header()->setMovable(false);
    312307    m_contextView->setColumnHidden(0, true);
    313     m_contextView->header()->setResizeMode(1, QHeaderView::Stretch);
    314     m_contextView->header()->setResizeMode(2, QHeaderView::ResizeToContents);
    315308    m_contextView->header()->setStretchLastSection(false);
    316309
     
    341334    m_messageView->header()->setMovable(false);
    342335    m_messageView->setColumnHidden(0, true);
    343     m_messageView->setColumnHidden(2, true);
    344     // last visible column auto-stretches
    345336
    346337    m_messagesDock->setWidget(m_messageView);
     
    449440
    450441    modelCountChanged();
     442    initViewHeaders();
    451443    resetSorting();
    452444
     
    479471    connect(m_findDialog, SIGNAL(findNext(QString,DataModel::FindLocation,bool,bool)),
    480472            this, SLOT(findNext(QString,DataModel::FindLocation,bool,bool)));
    481     connect(m_translateDialog, SIGNAL(requestMatchUpdate(bool &)), SLOT(updateTranslateHit(bool &)));
     473    connect(m_translateDialog, SIGNAL(requestMatchUpdate(bool&)), SLOT(updateTranslateHit(bool&)));
    482474    connect(m_translateDialog, SIGNAL(activated(int)), SLOT(translate(int)));
    483475
     
    488480    readConfig();
    489481    m_statistics = 0;
     482
     483    connect(m_ui.actionLengthVariants, SIGNAL(toggled(bool)),
     484            m_messageEditor, SLOT(setLengthVariants(bool)));
     485    m_messageEditor->setLengthVariants(m_ui.actionLengthVariants->isChecked());
    490486
    491487    m_focusWatcher = new FocusWatcher(m_messageEditor, this);
     
    508504    delete m_dataModel;
    509505    delete m_statistics;
     506    delete m_printer;
     507}
     508
     509void MainWindow::initViewHeaders()
     510{
     511    m_contextView->header()->setResizeMode(1, QHeaderView::Stretch);
     512    m_contextView->header()->setResizeMode(2, QHeaderView::ResizeToContents);
     513    m_messageView->setColumnHidden(2, true);
     514    // last visible column auto-stretches
    510515}
    511516
     
    741746        m_dataModel->closeAll();
    742747        modelCountChanged();
     748        initViewHeaders();
    743749        recentFiles().closeGroup();
    744750        return true;
     
    875881}
    876882
     883QPrinter *MainWindow::printer()
     884{
     885    if (!m_printer)
     886        m_printer = new QPrinter;
     887    return m_printer;
     888}
     889
    877890void MainWindow::print()
    878891{
    879892#ifndef QT_NO_PRINTER
    880893    int pageNum = 0;
    881     QPrintDialog dlg(&m_printer, this);
     894    QPrintDialog dlg(printer(), this);
    882895    if (dlg.exec()) {
    883896        QApplication::setOverrideCursor(Qt::WaitCursor);
    884         m_printer.setDocName(m_dataModel->condensedSrcFileNames(true));
     897        printer()->setDocName(m_dataModel->condensedSrcFileNames(true));
    885898        statusBar()->showMessage(tr("Printing..."));
    886         PrintOut pout(&m_printer);
     899        PrintOut pout(printer());
    887900
    888901        for (int i = 0; i < m_dataModel->contextCount(); ++i) {
     
    12371250    int pageNum = 0;
    12381251
    1239     QPrintDialog dlg(&m_printer, this);
     1252    QPrintDialog dlg(printer(), this);
    12401253    if (dlg.exec()) {
    1241         m_printer.setDocName(phraseBook->fileName());
     1254        printer()->setDocName(phraseBook->fileName());
    12421255        statusBar()->showMessage(tr("Printing..."));
    1243         PrintOut pout(&m_printer);
     1256        PrintOut pout(printer());
    12441257        pout.setRule(PrintOut::ThinRule);
    12451258        foreach (const Phrase *p, phraseBook->phrases()) {
     
    13471360    version = version.arg(QLatin1String(QT_VERSION_STR));
    13481361
    1349     // TODO: Remove this variable for 4.6.0.  Must keep this way for 4.5.x due to string freeze.
    1350     QString edition;
    1351 
    13521362    box.setText(tr("<center><img src=\":/images/splash.png\"/></img><p>%1</p></center>"
    13531363                    "<p>Qt Linguist is a tool for adding translations to Qt "
    13541364                    "applications.</p>"
    1355                     "<p>%2</p>"
    13561365                    "<p>Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)."
    1357                     "</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND,"
    1358                     " INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A"
    1359                     " PARTICULAR PURPOSE.</p>").arg(version).arg(edition));
     1366                   ).arg(version));
    13601367
    13611368    box.setWindowTitle(QApplication::translate("AboutDialog", "Qt Linguist"));
     
    23522359}
    23532360
     2361static bool haveMnemonic(const QString &str)
     2362{
     2363    QString mnemonic = QKeySequence::mnemonic(str);
     2364    if (mnemonic == QLatin1String("Alt+Space")) {
     2365        // "Nobody" ever really uses these, and they are highly annoying
     2366        // because we get a lot of false positives.
     2367        return false;
     2368    }
     2369    return !mnemonic.isEmpty();
     2370}
     2371
    23542372void MainWindow::updateDanger(const MultiDataIndex &index, bool verbose)
    23552373{
     
    23752393            QStringList translations = m->translations();
    23762394
     2395            // Truncated variants are permitted to be "denormalized"
     2396            for (int i = 0; i < translations.count(); ++i) {
     2397                int sep = translations.at(i).indexOf(QChar(Translator::BinaryVariantSeparator));
     2398                if (sep >= 0)
     2399                    translations[i].truncate(sep);
     2400            }
     2401
    23772402            if (m_ui.actionAccelerators->isChecked()) {
    2378                 bool sk = !QKeySequence::mnemonic(source).isEmpty();
     2403                bool sk = haveMnemonic(source);
    23792404                bool tk = true;
    23802405                for (int i = 0; i < translations.count() && tk; ++i) {
    2381                     tk &= !QKeySequence::mnemonic(translations[i]).isEmpty();
     2406                    tk &= haveMnemonic(translations[i]);
    23822407                }
    23832408
     
    25032528void MainWindow::readConfig()
    25042529{
    2505     QString keybase = settingsPrefix();
    25062530    QSettings config;
    25072531
    25082532    QRect r(pos(), size());
    2509     restoreGeometry(config.value(keybase + QLatin1String("Geometry/WindowGeometry")).toByteArray());
    2510     restoreState(config.value(keybase + QLatin1String("MainWindowState")).toByteArray());
     2533    restoreGeometry(config.value(settingPath("Geometry/WindowGeometry")).toByteArray());
     2534    restoreState(config.value(settingPath("MainWindowState")).toByteArray());
    25112535
    25122536    m_ui.actionAccelerators->setChecked(
    2513         config.value(keybase + QLatin1String("Validators/Accelerator"), true).toBool());
     2537        config.value(settingPath("Validators/Accelerator"), true).toBool());
    25142538    m_ui.actionEndingPunctuation->setChecked(
    2515         config.value(keybase + QLatin1String("Validators/EndingPunctuation"), true).toBool());
     2539        config.value(settingPath("Validators/EndingPunctuation"), true).toBool());
    25162540    m_ui.actionPhraseMatches->setChecked(
    2517         config.value(keybase + QLatin1String("Validators/PhraseMatch"), true).toBool());
     2541        config.value(settingPath("Validators/PhraseMatch"), true).toBool());
    25182542    m_ui.actionPlaceMarkerMatches->setChecked(
    2519         config.value(keybase + QLatin1String("Validators/PlaceMarkers"), true).toBool());
     2543        config.value(settingPath("Validators/PlaceMarkers"), true).toBool());
     2544    m_ui.actionLengthVariants->setChecked(
     2545        config.value(settingPath("Options/LengthVariants"), false).toBool());
    25202546
    25212547    recentFiles().readConfig();
    25222548
    2523     int size = config.beginReadArray(keybase + QLatin1String("OpenedPhraseBooks"));
     2549    int size = config.beginReadArray(settingPath("OpenedPhraseBooks"));
    25242550    for (int i = 0; i < size; ++i) {
    25252551        config.setArrayIndex(i);
     
    25312557void MainWindow::writeConfig()
    25322558{
    2533     QString keybase = settingsPrefix();
    25342559    QSettings config;
    2535     config.setValue(keybase + QLatin1String("Geometry/WindowGeometry"),
     2560    config.setValue(settingPath("Geometry/WindowGeometry"),
    25362561        saveGeometry());
    2537     config.setValue(keybase + QLatin1String("Validators/Accelerator"),
     2562    config.setValue(settingPath("Validators/Accelerator"),
    25382563        m_ui.actionAccelerators->isChecked());
    2539     config.setValue(keybase + QLatin1String("Validators/EndingPunctuation"),
     2564    config.setValue(settingPath("Validators/EndingPunctuation"),
    25402565        m_ui.actionEndingPunctuation->isChecked());
    2541     config.setValue(keybase + QLatin1String("Validators/PhraseMatch"),
     2566    config.setValue(settingPath("Validators/PhraseMatch"),
    25422567        m_ui.actionPhraseMatches->isChecked());
    2543     config.setValue(keybase + QLatin1String("Validators/PlaceMarkers"),
     2568    config.setValue(settingPath("Validators/PlaceMarkers"),
    25442569        m_ui.actionPlaceMarkerMatches->isChecked());
    2545     config.setValue(keybase + QLatin1String("MainWindowState"),
     2570    config.setValue(settingPath("Options/LengthVariants"),
     2571        m_ui.actionLengthVariants->isChecked());
     2572    config.setValue(settingPath("MainWindowState"),
    25462573        saveState());
    25472574    recentFiles().writeConfig();
    25482575
    2549     config.beginWriteArray(keybase + QLatin1String("OpenedPhraseBooks"),
     2576    config.beginWriteArray(settingPath("OpenedPhraseBooks"),
    25502577        m_phraseBooks.size());
    25512578    for (int i = 0; i < m_phraseBooks.size(); ++i) {
  • trunk/tools/linguist/linguist/mainwindow.h

    r232 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 Qt Linguist 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**
     
    5252
    5353#include <QtGui/QMainWindow>
    54 #include <QtGui/QPrinter>
    5554
    5655QT_BEGIN_NAMESPACE
     
    6160class QLabel;
    6261class QMenu;
     62class QPrinter;
    6363class QProcess;
    6464class QIcon;
     
    7979class TranslateDialog;
    8080class TranslationSettingsDialog;
    81 
    82 const QString &settingsPrefix();
    8381
    8482class MainWindow : public QMainWindow
     
    182180
    183181    void updateStatistics();
     182    void initViewHeaders();
    184183    void modelCountChanged();
    185184    void setupMenuBar();
     
    202201    void releaseInternal(int model);
    203202    void saveInternal(int model);
     203
     204    QPrinter *printer();
    204205
    205206    // FIXME: move to DataModel
     
    230231    QMap<QAction *, PhraseBook *> m_phraseBookMenu[3];
    231232#ifndef QT_NO_PRINTER
    232     QPrinter m_printer;
     233    QPrinter *m_printer;
    233234#endif
    234235
  • trunk/tools/linguist/linguist/mainwindow.ui

    r2 r561  
    44**
    55** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    6 ** Contact: Qt Software Information (qt-info@nokia.com)
     6** All rights reserved.
     7** Contact: Nokia Corporation (qt-info@nokia.com)
    78**
    89** This file is part of the Qt Linguist of the Qt Toolkit.
     
    2324** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2425**
    25 ** In addition, as a special exception, Nokia gives you certain
    26 ** additional rights. These rights are described in the Nokia Qt LGPL
    27 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    28 ** package.
     26** In addition, as a special exception, Nokia gives you certain additional
     27** rights.  These rights are described in the Nokia Qt LGPL Exception
     28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2929**
    3030** GNU General Public License Usage
     
    3636** met: http://www.gnu.org/copyleft/gpl.html.
    3737**
    38 ** If you are unsure which license is appropriate for your use, please
    39 ** contact the sales department at qt-sales@nokia.com.
     38** If you have questions regarding the use of this file, please contact
     39** Nokia at qt-info@nokia.com.
    4040** $QT_END_LICENSE$
    4141**
     
    6161     <y>0</y>
    6262     <width>673</width>
    63      <height>30</height>
     63     <height>28</height>
    6464    </rect>
    6565   </property>
     
    117117    <addaction name="actionDisplayGuesses"/>
    118118    <addaction name="actionStatistics"/>
     119    <addaction name="actionLengthVariants"/>
    119120    <addaction name="separator"/>
    120121    <addaction name="menuToolbars"/>
     
    402403   </property>
    403404   <property name="toolTip">
    404     <string>Previous unfinished item.</string>
     405    <string>Previous unfinished item</string>
    405406   </property>
    406407   <property name="whatsThis">
     
    419420   </property>
    420421   <property name="toolTip">
    421     <string>Next unfinished item.</string>
     422    <string>Next unfinished item</string>
    422423   </property>
    423424   <property name="whatsThis">
     
    436437   </property>
    437438   <property name="toolTip">
    438     <string>Move to previous item.</string>
     439    <string>Move to previous item</string>
    439440   </property>
    440441   <property name="whatsThis">
     
    453454   </property>
    454455   <property name="toolTip">
    455     <string>Next item.</string>
     456    <string>Next item</string>
    456457   </property>
    457458   <property name="whatsThis">
     
    473474   </property>
    474475   <property name="toolTip">
    475     <string>Mark item as done and move to the next unfinished item.</string>
     476    <string>Mark item as done and move to the next unfinished item</string>
    476477   </property>
    477478   <property name="whatsThis">
     
    493494   </property>
    494495   <property name="toolTip">
     496    <string>Copies the source text into the translation field</string>
     497   </property>
     498   <property name="whatsThis">
    495499    <string>Copies the source text into the translation field.</string>
    496500   </property>
    497    <property name="whatsThis">
    498     <string>Copies the source text into the translation field.</string>
    499    </property>
    500501   <property name="shortcut">
    501502    <string>Ctrl+B</string>
     
    513514   </property>
    514515   <property name="toolTip">
    515     <string>Toggle the validity check of accelerators.</string>
     516    <string>Toggle the validity check of accelerators</string>
    516517   </property>
    517518   <property name="whatsThis">
     
    530531   </property>
    531532   <property name="toolTip">
    532     <string>Toggle the validity check of ending punctuation.</string>
     533    <string>Toggle the validity check of ending punctuation</string>
    533534   </property>
    534535   <property name="whatsThis">
     
    547548   </property>
    548549   <property name="toolTip">
    549     <string>Toggle checking that phrase suggestions are used.</string>
     550    <string>Toggle checking that phrase suggestions are used</string>
    550551   </property>
    551552   <property name="whatsThis">
     
    564565   </property>
    565566   <property name="toolTip">
    566     <string>Toggle the validity check of place markers.</string>
     567    <string>Toggle the validity check of place markers</string>
    567568   </property>
    568569   <property name="whatsThis">
     
    747748   </property>
    748749   <property name="whatsThis">
    749     <string>Create a Qt message file suitable for released applications from the current message file. The filename will automatically be determined from the name of the .ts file.</string>
     750    <string>Create a Qt message file suitable for released applications from the current message file. The filename will automatically be determined from the name of the TS file.</string>
    750751   </property>
    751752  </action>
     
    876877   <property name="shortcut">
    877878    <string>Ctrl+W</string>
     879   </property>
     880  </action>
     881  <action name="actionLengthVariants">
     882   <property name="checkable">
     883    <bool>true</bool>
     884   </property>
     885   <property name="text">
     886    <string>Length Variants</string>
    878887   </property>
    879888  </action>
  • trunk/tools/linguist/linguist/messageeditor.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 Qt Linguist 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**
    4040****************************************************************************/
    4141
    42 /*  TRANSLATOR MsgEdit
     42/*  TRANSLATOR MessageEditor
    4343
    4444  This is the right panel of the main window.
     
    7070static const char * language_strings[] =
    7171{
     72    QT_TRANSLATE_NOOP("MessageEditor", "Russian"),
    7273    QT_TRANSLATE_NOOP("MessageEditor", "German"),
    7374    QT_TRANSLATE_NOOP("MessageEditor", "Japanese"),
     
    8889      m_currentModel(-1),
    8990      m_currentNumerus(-1),
     91      m_lengthVariants(false),
    9092      m_undoAvail(false),
    9193      m_redoAvail(false),
    9294      m_cutAvail(false),
    9395      m_copyAvail(false),
    94       m_sourceSelected(false),
    95       m_pluralSourceSelected(false),
    96       m_currentSelected(false)
     96      m_selectionHolder(0),
     97      m_focusWidget(0)
    9798{
    9899    setObjectName(QLatin1String("scroll area"));
     
    122123            SLOT(setTargetLanguage(int)));
    123124
     125    m_tabOrderTimer.setSingleShot(true);
     126    connect(&m_tabOrderTimer, SIGNAL(timeout()), SLOT(reallyFixTabOrder()));
     127
    124128    clipboardChanged();
    125129
     
    134138    editorPage->setObjectName(QLatin1String("editorPage"));
    135139
    136     // Due to CSS being rather broken on the Mac style at the moment, only
    137     // use the border-image on non-Mac systems.
    138140    editorPage->setStyleSheet(QLatin1String(
    139 #ifndef Q_WS_MAC
    140141            "QFrame#editorPage { border-image: url(:/images/transbox.png) 12 16 16 12 repeat;"
    141142            "                    border-width: 12px 16px 16px 12px; }"
    142 #endif
    143143            "QFrame#editorPage { background-color: white; }"
    144144            "QLabel { font-weight: bold; }"
    145145            ));
    146 #ifdef Q_WS_MAC
    147     editorPage->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
    148 #endif
    149146    editorPage->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
    150147
     
    152149    m_source->setHideWhenEmpty(true);
    153150    m_source->setWhatsThis(tr("This area shows the source text."));
    154     connect(m_source, SIGNAL(selectionChanged()), SLOT(selectionChanged()));
     151    connect(m_source, SIGNAL(selectionChanged(QTextEdit*)),
     152            SLOT(selectionChanged(QTextEdit*)));
    155153
    156154    m_pluralSource = new FormWidget(tr("Source text (Plural)"), false);
    157155    m_pluralSource->setHideWhenEmpty(true);
    158156    m_pluralSource->setWhatsThis(tr("This area shows the plural form of the source text."));
    159     connect(m_pluralSource, SIGNAL(selectionChanged()), SLOT(selectionChanged()));
     157    connect(m_pluralSource, SIGNAL(selectionChanged(QTextEdit*)),
     158            SLOT(selectionChanged(QTextEdit*)));
    160159
    161160    m_commentText = new FormWidget(tr("Developer comments"), false);
     
    224223                        " They have no effect on the translated applications.") );
    225224    ed.transCommentText->getEditor()->installEventFilter(this);
    226     connect(ed.transCommentText, SIGNAL(selectionChanged()), SLOT(selectionChanged()));
    227     connect(ed.transCommentText, SIGNAL(textChanged()), SLOT(emitTranslatorCommentChanged()));
    228     connect(ed.transCommentText, SIGNAL(textChanged()), SLOT(resetHoverSelection()));
     225    connect(ed.transCommentText, SIGNAL(selectionChanged(QTextEdit*)),
     226            SLOT(selectionChanged(QTextEdit*)));
     227    connect(ed.transCommentText, SIGNAL(textChanged(QTextEdit*)),
     228            SLOT(emitTranslatorCommentChanged(QTextEdit*)));
     229    connect(ed.transCommentText, SIGNAL(textChanged(QTextEdit*)), SLOT(resetHoverSelection()));
    229230    connect(ed.transCommentText, SIGNAL(cursorPositionChanged()), SLOT(resetHoverSelection()));
     231    fixTabOrder();
    230232    QBoxLayout *box = new QVBoxLayout(ed.container);
    231233    box->setMargin(5);
     
    258260            if (m_currentNumerus >= m_editors[m_currentModel].transTexts.size())
    259261                m_currentNumerus = m_editors[m_currentModel].transTexts.size() - 1;
    260             activeEditor()->getEditor()->setFocus();
     262            activeEditor()->setFocus();
    261263        } else {
    262264            m_currentNumerus = -1;
     
    273275void MessageEditor::addPluralForm(int model, const QString &label, bool writable)
    274276{
    275     FormWidget *transEditor = new FormWidget(label, true);
    276     QFont font;
    277     font.setPointSize(static_cast<int>(m_editors[model].fontSize));
    278     transEditor->getEditor()->setFont(font);
     277    FormMultiWidget *transEditor = new FormMultiWidget(label);
     278    connect(transEditor, SIGNAL(editorCreated(QTextEdit*)), SLOT(editorCreated(QTextEdit*)));
    279279    transEditor->setEditingEnabled(writable);
    280280    transEditor->setHideWhenEmpty(!writable);
    281281    if (!m_editors[model].transTexts.isEmpty())
    282282        transEditor->setVisible(false);
     283    transEditor->setMultiEnabled(m_lengthVariants);
    283284    static_cast<QBoxLayout *>(m_editors[model].container->layout())->insertWidget(
    284285        m_editors[model].transTexts.count(), transEditor);
    285286
    286     transEditor->getEditor()->installEventFilter(this);
    287     connect(transEditor, SIGNAL(selectionChanged()), SLOT(selectionChanged()));
    288     connect(transEditor, SIGNAL(textChanged()), SLOT(emitTranslationChanged()));
    289     connect(transEditor, SIGNAL(textChanged()), SLOT(resetHoverSelection()));
     287    connect(transEditor, SIGNAL(selectionChanged(QTextEdit*)),
     288            SLOT(selectionChanged(QTextEdit*)));
     289    connect(transEditor, SIGNAL(textChanged(QTextEdit*)),
     290            SLOT(emitTranslationChanged(QTextEdit*)));
     291    connect(transEditor, SIGNAL(textChanged(QTextEdit*)), SLOT(resetHoverSelection()));
    290292    connect(transEditor, SIGNAL(cursorPositionChanged()), SLOT(resetHoverSelection()));
    291293
    292294    m_editors[model].transTexts << transEditor;
     295}
     296
     297void MessageEditor::editorCreated(QTextEdit *te)
     298{
     299    FormMultiWidget *snd = static_cast<FormMultiWidget *>(sender());
     300    for (int model = 0; ; ++model) {
     301        MessageEditorData med = m_editors.at(model);
     302        if (med.transTexts.contains(snd)) {
     303            QFont font;
     304            font.setPointSize(static_cast<int>(med.fontSize));
     305            te->setFont(font);
     306
     307            te->installEventFilter(this);
     308
     309            fixTabOrder();
     310            return;
     311        }
     312    }
     313}
     314
     315void MessageEditor::fixTabOrder()
     316{
     317    m_tabOrderTimer.start(0);
     318}
     319
     320void MessageEditor::reallyFixTabOrder()
     321{
     322    QWidget *prev = this;
     323    foreach (const MessageEditorData &med, m_editors) {
     324        foreach (FormMultiWidget *fmw, med.transTexts)
     325            foreach (QTextEdit *te, fmw->getEditors()) {
     326                setTabOrder(prev, te);
     327                prev = te;
     328            }
     329        QTextEdit *te = med.transCommentText->getEditor();
     330        setTabOrder(prev, te);
     331        prev = te;
     332    }
    293333}
    294334
     
    308348}
    309349
    310 static bool clearFormSelection(FormWidget *fw, FormWidget *te)
    311 {
    312     if (fw != te) {
    313         QTextEdit *t = fw->getEditor();
    314         bool oldBlockState = t->blockSignals(true);
    315         QTextCursor c = t->textCursor();
    316         c.clearSelection();
    317         t->setTextCursor(c);
    318         t->blockSignals(oldBlockState);
    319         return true;
    320     }
    321     return false;
    322 }
    323 
    324 // Clear the selection for all textedits except the sender
    325 void MessageEditor::selectionChanged()
    326 {
    327     if (!resetSelection(qobject_cast<FormWidget *>(sender())))
     350static void clearSelection(QTextEdit *t)
     351{
     352    bool oldBlockState = t->blockSignals(true);
     353    QTextCursor c = t->textCursor();
     354    c.clearSelection();
     355    t->setTextCursor(c);
     356    t->blockSignals(oldBlockState);
     357}
     358
     359void MessageEditor::selectionChanged(QTextEdit *te)
     360{
     361    if (te != m_selectionHolder) {
     362        if (m_selectionHolder)
     363            clearSelection(m_selectionHolder);
     364        m_selectionHolder = (te->textCursor().hasSelection() ? te : 0);
    328365        updateCanCutCopy();
    329 }
    330 
    331 bool MessageEditor::resetHoverSelection(FormWidget *fw)
    332 {
    333     if (m_sourceSelected) {
    334         if (clearFormSelection(m_source, fw)) {
    335             updateCanCutCopy();
    336             return true;
    337         }
    338     } else if (m_pluralSourceSelected) {
    339         if (clearFormSelection(m_pluralSource, fw)) {
    340             updateCanCutCopy();
    341             return true;
    342         }
    343     }
    344     return false;
    345 }
    346 
    347 bool MessageEditor::resetSelection(FormWidget *fw)
    348 {
    349     if (resetHoverSelection(fw))
    350         return true;
    351     if (m_currentSelected) {
    352         MessageEditorData &ed = m_editors[m_currentModel];
    353         FormWidget *cfw = (m_currentNumerus < 0) ? ed.transCommentText
    354                                                  : ed.transTexts[m_currentNumerus];
    355         if (clearFormSelection(cfw, fw)) {
    356             updateCanCutCopy();
    357             return true;
    358         }
    359     }
    360     return false;
     366    }
     367}
     368
     369void MessageEditor::resetHoverSelection()
     370{
     371    if (m_selectionHolder &&
     372        (m_selectionHolder == m_source->getEditor()
     373         || m_selectionHolder == m_pluralSource->getEditor()))
     374        resetSelection();
     375}
     376
     377void MessageEditor::resetSelection()
     378{
     379    if (m_selectionHolder) {
     380        clearSelection(m_selectionHolder);
     381        m_selectionHolder = 0;
     382        updateCanCutCopy();
     383    }
    361384}
    362385
     
    365388    for (int j = 0; j < m_editors.count(); ++j) {
    366389        for (int i = 0; i < m_editors[j].transTexts.count(); ++i)
    367             if (m_editors[j].transTexts[i]->getEditor()->hasFocus()) {
    368                 *model = j;
    369                 *numerus = i;
    370                 return;
    371             }
    372         if (m_editors[j].transCommentText->getEditor()->hasFocus()) {
     390            foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors())
     391                if (m_focusWidget == te) {
     392                    *model = j;
     393                    *numerus = i;
     394                    return;
     395                }
     396        if (m_focusWidget == m_editors[j].transCommentText->getEditor()) {
    373397            *model = j;
    374398            *numerus = -1;
     
    380404}
    381405
    382 FormWidget *MessageEditor::activeTranslation() const
     406QTextEdit *MessageEditor::activeTranslation() const
    383407{
    384408    if (m_currentNumerus < 0)
    385409        return 0;
    386     return m_editors[m_currentModel].transTexts[m_currentNumerus];
    387 }
    388 
    389 FormWidget *MessageEditor::activeOr1stTranslation() const
     410    const QList<FormatTextEdit *> &editors =
     411            m_editors[m_currentModel].transTexts[m_currentNumerus]->getEditors();
     412    foreach (QTextEdit *te, editors)
     413        if (te->hasFocus())
     414            return te;
     415    return editors.first();
     416}
     417
     418QTextEdit *MessageEditor::activeOr1stTranslation() const
    390419{
    391420    if (m_currentNumerus < 0) {
    392421        for (int i = 0; i < m_editors.size(); ++i)
    393422            if (m_editors[i].container->isVisible()
    394                 && !m_editors[i].transTexts[0]->getEditor()->isReadOnly())
    395                 return m_editors[i].transTexts[0];
     423                && !m_editors[i].transTexts.first()->getEditors().first()->isReadOnly())
     424                return m_editors[i].transTexts.first()->getEditors().first();
    396425        return 0;
    397426    }
    398     return m_editors[m_currentModel].transTexts[m_currentNumerus];
    399 }
    400 
    401 FormWidget *MessageEditor::activeTransComment() const
     427    return activeTranslation();
     428}
     429
     430QTextEdit *MessageEditor::activeTransComment() const
    402431{
    403432    if (m_currentModel < 0 || m_currentNumerus >= 0)
    404433        return 0;
    405     return m_editors[m_currentModel].transCommentText;
    406 }
    407 
    408 FormWidget *MessageEditor::activeEditor() const
    409 {
    410     if (FormWidget *fw = activeTransComment())
    411         return fw;
     434    return m_editors[m_currentModel].transCommentText->getEditor();
     435}
     436
     437QTextEdit *MessageEditor::activeEditor() const
     438{
     439    if (QTextEdit *te = activeTransComment())
     440        return te;
    412441    return activeTranslation();
    413442}
    414443
    415 FormWidget *MessageEditor::activeOr1stEditor() const
    416 {
    417     if (FormWidget *fw = activeTransComment())
    418         return fw;
     444QTextEdit *MessageEditor::activeOr1stEditor() const
     445{
     446    if (QTextEdit *te = activeTransComment())
     447        return te;
    419448    return activeOr1stTranslation();
    420449}
     
    424453    const QStringList &numerusForms = m_dataModel->model(model)->numerusForms();
    425454    const QString &langLocalized = m_dataModel->model(model)->localizedLanguage();
    426     bool added = false;
    427455    for (int i = 0; i < numerusForms.count(); ++i) {
    428456        const QString &label = tr("%1 translation (%2)").arg(langLocalized, numerusForms[i]);
    429457        if (!i)
    430458            m_editors[model].firstForm = label;
    431         if (i >= m_editors[model].transTexts.count()) {
     459        if (i >= m_editors[model].transTexts.count())
    432460            addPluralForm(model, label, m_dataModel->isModelWritable(model));
    433             QWidget *prev;
    434             if (i > 0)
    435                 prev = m_editors[model].transTexts[i - 1]->getEditor();
    436             else if (model)
    437                 prev = m_editors[model - 1].transCommentText->getEditor();
    438             else
    439                 prev = this;
    440             setTabOrder(prev, m_editors[model].transTexts[i]->getEditor());
    441             added = true;
    442         } else {
     461        else
    443462            m_editors[model].transTexts[i]->setLabel(label);
    444         }
    445463        m_editors[model].transTexts[i]->setVisible(!i || m_editors[model].pluralEditMode);
    446464        m_editors[model].transTexts[i]->setWhatsThis(
     
    452470    m_editors[model].invariantForm = tr("%1 translation").arg(langLocalized);
    453471    m_editors[model].transCommentText->setLabel(tr("%1 translator comments").arg(langLocalized));
    454     if (added)
    455         setTabOrder(m_editors[model].transTexts.last()->getEditor(), m_editors[model].transCommentText->getEditor());
    456472}
    457473
     
    460476    for (int j = 0; j < m_editors.count(); ++j) {
    461477        for (int i = 0; i < m_editors[j].transTexts.count(); ++i)
    462             if (m_editors[j].transTexts[i]->getEditor() == o)
    463                 return &m_editors[j];
     478            foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors())
     479                if (te == o)
     480                    return &m_editors[j];
    464481        if (m_editors[j].transCommentText->getEditor() == o)
    465482            return &m_editors[j];
     
    473490    font.setPointSize(static_cast<int>(med->fontSize));
    474491    for (int i = 0; i < med->transTexts.count(); ++i)
    475         med->transTexts[i]->getEditor()->setFont(font);
     492        foreach (QTextEdit *te, med->transTexts[i]->getEditors())
     493            te->setFont(font);
    476494    med->transCommentText->getEditor()->setFont(font);
    477495    return true;
     
    510528                    return true;
    511529                }
     530            } else if (ke->key() == Qt::Key_A) {
     531                return true;
    512532            }
    513533        }
     
    534554        }
    535555    } else if (e->type() == QEvent::FocusIn) {
    536         int model, numerus;
    537         activeModelAndNumerus(&model, &numerus);
    538         if (model != m_currentModel || numerus != m_currentNumerus) {
    539             resetSelection();
    540             m_currentModel = model;
    541             m_currentNumerus = numerus;
    542             emit activeModelChanged(activeModel());
    543             updateBeginFromSource();
    544             updateUndoRedo();
    545             updateCanPaste();
    546         }
     556        QWidget *widget = static_cast<QWidget *>(o);
     557        if (widget != m_focusWidget)
     558            trackFocus(widget);
    547559    }
    548560
    549561    return QScrollArea::eventFilter(o, e);
     562}
     563
     564void MessageEditor::grabFocus(QWidget *widget)
     565{
     566    if (widget != m_focusWidget) {
     567        widget->setFocus();
     568        trackFocus(widget);
     569    }
     570}
     571
     572void MessageEditor::trackFocus(QWidget *widget)
     573{
     574    m_focusWidget = widget;
     575
     576    int model, numerus;
     577    activeModelAndNumerus(&model, &numerus);
     578    if (model != m_currentModel || numerus != m_currentNumerus) {
     579        resetSelection();
     580        m_currentModel = model;
     581        m_currentNumerus = numerus;
     582        emit activeModelChanged(activeModel());
     583        updateBeginFromSource();
     584        updateUndoRedo();
     585        updateCanPaste();
     586    }
    550587}
    551588
     
    557594    for (int j = 0; j < m_editors.count(); ++j) {
    558595        setEditingEnabled(j, false);
    559         foreach (FormWidget *widget, m_editors[j].transTexts)
     596        foreach (FormMultiWidget *widget, m_editors[j].transTexts)
    560597            widget->clearTranslation();
    561598        m_editors[j].transCommentText->clearTranslation();
     
    644681    if (numerus >= ed.transTexts.count())
    645682        numerus = 0;
    646     FormWidget *transForm = ed.transTexts[numerus];
     683    FormMultiWidget *transForm = ed.transTexts[numerus];
    647684    transForm->setTranslation(translation, false);
    648685
     
    659696        numerus = m_currentNumerus;
    660697    }
    661     FormWidget *transForm = m_editors[latestModel].transTexts[numerus];
    662     transForm->getEditor()->setFocus();
     698    FormMultiWidget *transForm = m_editors[latestModel].transTexts[numerus];
     699    transForm->getEditors().first()->setFocus();
    663700    transForm->setTranslation(translation, true);
    664701
     
    669706{
    670707    MessageEditorData &ed = m_editors[model];
    671     foreach (FormWidget *widget, ed.transTexts)
     708    foreach (FormMultiWidget *widget, ed.transTexts)
    672709        widget->setEditingEnabled(enabled);
    673710    ed.transCommentText->setEditingEnabled(enabled);
     
    676713}
    677714
     715void MessageEditor::setLengthVariants(bool on)
     716{
     717    m_lengthVariants = on;
     718    foreach (const MessageEditorData &ed, m_editors)
     719        foreach (FormMultiWidget *widget, ed.transTexts)
     720            widget->setMultiEnabled(on);
     721}
     722
    678723void MessageEditor::undo()
    679724{
    680     activeEditor()->getEditor()->document()->undo();
     725    activeEditor()->document()->undo();
    681726}
    682727
    683728void MessageEditor::redo()
    684729{
    685     activeEditor()->getEditor()->document()->redo();
     730    activeEditor()->document()->redo();
    686731}
    687732
     
    690735    bool newUndoAvail = false;
    691736    bool newRedoAvail = false;
    692     if (FormWidget *fw = activeEditor()) {
    693         QTextDocument *doc = fw->getEditor()->document();
     737    if (QTextEdit *te = activeEditor()) {
     738        QTextDocument *doc = te->document();
    694739        newUndoAvail = doc->isUndoAvailable();
    695740        newRedoAvail = doc->isRedoAvailable();
     
    709754void MessageEditor::cut()
    710755{
    711     QTextEdit *editor = activeEditor()->getEditor();
    712     if (editor->textCursor().hasSelection())
    713         editor->cut();
     756    m_selectionHolder->cut();
    714757}
    715758
    716759void MessageEditor::copy()
    717760{
    718     QTextEdit *te;
    719     if ((te = m_source->getEditor())->textCursor().hasSelection()
    720         || (te = m_pluralSource->getEditor())->textCursor().hasSelection()
    721         || (te = activeEditor()->getEditor())->textCursor().hasSelection())
    722         te->copy();
     761    m_selectionHolder->copy();
    723762}
    724763
     
    728767    bool newCutState = false;
    729768
    730     m_sourceSelected = m_source->getEditor()->textCursor().hasSelection();
    731     m_pluralSourceSelected = m_pluralSource->getEditor()->textCursor().hasSelection();
    732     m_currentSelected = false;
    733 
    734     if (m_sourceSelected || m_pluralSourceSelected) {
     769    if (m_selectionHolder) {
    735770        newCopyState = true;
    736     } else if (FormWidget *fw = activeEditor()) {
    737         QTextEdit *te = fw->getEditor();
    738         if (te->textCursor().hasSelection()) {
    739             m_currentSelected = true;
    740             newCopyState = true;
    741             newCutState = !te->isReadOnly();
    742         }
     771        newCutState = !m_selectionHolder->isReadOnly();
    743772    }
    744773
     
    756785void MessageEditor::paste()
    757786{
    758     activeEditor()->getEditor()->paste();
     787    activeEditor()->paste();
    759788}
    760789
    761790void MessageEditor::updateCanPaste()
    762791{
    763     FormWidget *fw;
     792    QTextEdit *te;
    764793    emit pasteAvailable(!m_clipboardEmpty
    765                         && (fw = activeEditor()) && !fw->getEditor()->isReadOnly());
     794                        && (te = activeEditor()) && !te->isReadOnly());
    766795}
    767796
     
    778807    // if we really want the source text editor to be selected.
    779808    QTextEdit *te;
    780     FormWidget *fw;
    781809    if ((te = m_source->getEditor())->underMouse()
    782810        || (te = m_pluralSource->getEditor())->underMouse()
    783         || ((fw = activeEditor()) && (te = fw->getEditor())->hasFocus()))
     811        || ((te = activeEditor()) && te->hasFocus()))
    784812        te->selectAll();
    785813}
    786814
    787 void MessageEditor::emitTranslationChanged()
    788 {
    789     static_cast<FormWidget *>(sender())->getEditor()->setFocus(); // DND proofness
     815void MessageEditor::emitTranslationChanged(QTextEdit *widget)
     816{
     817    grabFocus(widget); // DND proofness
    790818    updateBeginFromSource();
    791819    updateUndoRedo();
     
    793821}
    794822
    795 void MessageEditor::emitTranslatorCommentChanged()
    796 {
    797     static_cast<FormWidget *>(sender())->getEditor()->setFocus(); // DND proofness
     823void MessageEditor::emitTranslatorCommentChanged(QTextEdit *widget)
     824{
     825    grabFocus(widget); // DND proofness
    798826    updateUndoRedo();
    799827    emit translatorCommentChanged(m_editors[m_currentModel].transCommentText->getTranslation());
     
    803831{
    804832    bool overwrite = false;
    805     if (FormWidget *transForm = activeTranslation()) {
    806         QTextEdit *activeEditor = transForm->getEditor();
     833    if (QTextEdit *activeEditor = activeTranslation())
    807834        overwrite = !activeEditor->isReadOnly()
    808835            && activeEditor->toPlainText().trimmed().isEmpty();
    809     }
    810836    emit beginFromSourceAvailable(overwrite);
    811837}
     
    822848{
    823849    if (!widget()->hasFocus())
    824         if (FormWidget *transForm = activeOr1stEditor())
    825             transForm->getEditor()->setFocus();
     850        if (QTextEdit *activeEditor = activeOr1stEditor())
     851            activeEditor->setFocus();
    826852}
    827853
     
    833859            m_currentNumerus = -1;
    834860            m_currentModel = -1;
     861            m_focusWidget = 0;
    835862            emit activeModelChanged(activeModel());
    836863            updateBeginFromSource();
     
    838865            updateCanPaste();
    839866        } else {
    840             m_editors[model].transTexts[0]->getEditor()->setFocus();
     867            m_editors[model].transTexts.first()->getEditors().first()->setFocus();
    841868        }
    842869    }
     
    849876            if (MessageItem *item = m_dataModel->messageItem(m_currentIndex, j))
    850877                if (item->type() == TranslatorMessage::Unfinished) {
    851                     m_editors[j].transTexts[0]->getEditor()->setFocus();
     878                    m_editors[j].transTexts.first()->getEditors().first()->setFocus();
    852879                    return true;
    853880                }
  • trunk/tools/linguist/linguist/messageeditor.h

    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 Qt Linguist 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**
     
    4646
    4747#include <QtCore/QLocale>
     48#include <QtCore/QTimer>
    4849
    4950#include <QtGui/QFrame>
     
    5960class FormatTextEdit;
    6061class FormWidget;
     62class FormMultiWidget;
    6163
    6264struct MessageEditorData {
    6365    QWidget *container;
    6466    FormWidget *transCommentText;
    65     QList<FormWidget*> transTexts;
     67    QList<FormMultiWidget *> transTexts;
    6668    QString invariantForm;
    6769    QString firstForm;
    68     float fontSize;
     70    qreal fontSize;
    6971    bool pluralEditMode;
    7072};
     
    109111    void setEditorFocus();
    110112    void setTranslation(int latestModel, const QString &translation);
     113    void setLengthVariants(bool on);
    111114
    112115private slots:
    113     void selectionChanged();
    114     bool resetHoverSelection(FormWidget *fw = 0);
    115     void emitTranslationChanged();
    116     void emitTranslatorCommentChanged();
     116    void editorCreated(QTextEdit *);
     117    void selectionChanged(QTextEdit *);
     118    void resetHoverSelection();
     119    void emitTranslationChanged(QTextEdit *);
     120    void emitTranslatorCommentChanged(QTextEdit *);
    117121    void updateCanPaste();
    118122    void clipboardChanged();
     
    121125    void allModelsDeleted();
    122126    void setTargetLanguage(int model);
     127    void reallyFixTabOrder();
    123128
    124129private:
     
    126131    void setEditingEnabled(int model, bool enabled);
    127132    bool focusNextUnfinished(int start);
    128     bool resetSelection(FormWidget *fw = 0);
     133    void resetSelection();
     134    void grabFocus(QWidget *widget);
     135    void trackFocus(QWidget *widget);
    129136    void activeModelAndNumerus(int *model, int *numerus) const;
    130     FormWidget *activeTranslation() const;
    131     FormWidget *activeOr1stTranslation() const;
    132     FormWidget *activeTransComment() const;
    133     FormWidget *activeEditor() const;
    134     FormWidget *activeOr1stEditor() const;
     137    QTextEdit *activeTranslation() const;
     138    QTextEdit *activeOr1stTranslation() const;
     139    QTextEdit *activeTransComment() const;
     140    QTextEdit *activeEditor() const;
     141    QTextEdit *activeOr1stEditor() const;
    135142    MessageEditorData *modelForWidget(const QObject *o);
    136143    int activeTranslationNumerus() const;
     
    140147    void updateCanCutCopy();
    141148    void addPluralForm(int model, const QString &label, bool writable);
     149    void fixTabOrder();
    142150    QPalette paletteForModel(int model) const;
    143151
     
    148156    int m_currentNumerus;
    149157
     158    bool m_lengthVariants;
     159
    150160    bool m_undoAvail;
    151161    bool m_redoAvail;
    152162    bool m_cutAvail;
    153163    bool m_copyAvail;
    154     bool m_sourceSelected;
    155     bool m_pluralSourceSelected;
    156     bool m_currentSelected;
    157164
    158165    bool m_clipboardEmpty;
    159166
     167    QTextEdit *m_selectionHolder;
     168    QWidget *m_focusWidget;
    160169    QBoxLayout *m_layout;
    161170    FormWidget *m_source;
     
    163172    FormWidget *m_commentText;
    164173    QList<MessageEditorData> m_editors;
     174
     175    QTimer m_tabOrderTimer;
    165176};
    166177
  • trunk/tools/linguist/linguist/messageeditorwidgets.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 Qt Linguist 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**
     
    4242#include "messageeditorwidgets.h"
    4343#include "messagehighlighter.h"
     44
     45#include <translator.h>
    4446
    4547#include <QAbstractTextDocumentLayout>
     
    5052#include <QLayout>
    5153#include <QMenu>
     54#include <QMessageBox>
    5255#include <QPainter>
    5356#include <QScrollArea>
    5457#include <QTextBlock>
    5558#include <QTextDocumentFragment>
     59#include <QToolButton>
    5660#include <QVBoxLayout>
    5761
     
    146150void FormatTextEdit::setPlainText(const QString &text, bool userAction)
    147151{
    148     bool oldBlockState = false;
    149152    if (!userAction) {
    150153        // Prevent contentsChanged signal
    151         oldBlockState = document()->blockSignals(true);
     154        bool oldBlockState = blockSignals(true);
    152155        document()->setUndoRedoEnabled(false);
    153156        ExpandingTextEdit::setPlainText(text);
     
    155158        m_highlighter->rehighlight();
    156159        document()->setUndoRedoEnabled(true);
    157         document()->blockSignals(oldBlockState);
     160        blockSignals(oldBlockState);
    158161    } else {
    159162        ExpandingTextEdit::setPlainText(text);
     
    179182    setLayout(layout);
    180183
    181     connect(m_editor->document(), SIGNAL(contentsChanged()), SIGNAL(textChanged()));
    182     connect(m_editor, SIGNAL(selectionChanged()), SIGNAL(selectionChanged()));
     184    connect(m_editor, SIGNAL(textChanged()), SLOT(slotTextChanged()));
     185    connect(m_editor, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()));
    183186    connect(m_editor, SIGNAL(cursorPositionChanged()), SIGNAL(cursorPositionChanged()));
     187}
     188
     189void FormWidget::slotTextChanged()
     190{
     191    emit textChanged(m_editor);
     192}
     193
     194void FormWidget::slotSelectionChanged()
     195{
     196    emit selectionChanged(m_editor);
    184197}
    185198
     
    199212
    200213
     214class ButtonWrapper : public QWidget
     215{
     216    // no Q_OBJECT: no need to, and don't want the useless moc file
     217
     218public:
     219    ButtonWrapper(QWidget *wrapee, QWidget *relator) : m_wrapee(wrapee)
     220    {
     221        setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored);
     222        QBoxLayout *box = new QVBoxLayout;
     223        box->setMargin(0);
     224        setLayout(box);
     225        box->addWidget(wrapee, 0, Qt::AlignBottom);
     226        if (relator)
     227            relator->installEventFilter(this);
     228    }
     229
     230protected:
     231    virtual bool eventFilter(QObject *object, QEvent *event)
     232    {
     233        if (event->type() == QEvent::Resize) {
     234            QWidget *relator = static_cast<QWidget *>(object);
     235            setFixedHeight((relator->height() + layout()->spacing() + m_wrapee->height()) / 2);
     236        }
     237        return false;
     238    }
     239
     240private:
     241    QWidget *m_wrapee;
     242};
     243
     244FormMultiWidget::FormMultiWidget(const QString &label, QWidget *parent)
     245        : QWidget(parent),
     246          m_hideWhenEmpty(false),
     247          m_multiEnabled(false),
     248          m_plusIcon(QIcon(QLatin1String(":/images/plus.png"))),  // make static
     249          m_minusIcon(QIcon(QLatin1String(":/images/minus.png")))
     250{
     251    m_label = new QLabel(this);
     252    m_label->setText(label);
     253
     254    m_plusButtons.append(
     255            new ButtonWrapper(makeButton(m_plusIcon, SLOT(plusButtonClicked())), 0));
     256}
     257
     258QAbstractButton *FormMultiWidget::makeButton(const QIcon &icon, const char *slot)
     259{
     260    QAbstractButton *btn = new QToolButton(this);
     261    btn->setIcon(icon);
     262    btn->setFixedSize(icon.availableSizes().first() /* + something */);
     263    btn->setFocusPolicy(Qt::NoFocus);
     264    connect(btn, SIGNAL(clicked()), slot);
     265    return btn;
     266}
     267
     268void FormMultiWidget::addEditor(int idx)
     269{
     270    FormatTextEdit *editor = new FormatTextEdit(this);
     271    m_editors.insert(idx, editor);
     272
     273    m_minusButtons.insert(idx, makeButton(m_minusIcon, SLOT(minusButtonClicked())));
     274    m_plusButtons.insert(idx + 1,
     275            new ButtonWrapper(makeButton(m_plusIcon, SLOT(plusButtonClicked())), editor));
     276
     277    connect(editor, SIGNAL(textChanged()), SLOT(slotTextChanged()));
     278    connect(editor, SIGNAL(selectionChanged()), SLOT(slotSelectionChanged()));
     279    connect(editor, SIGNAL(cursorPositionChanged()), SIGNAL(cursorPositionChanged()));
     280    editor->installEventFilter(this);
     281
     282    emit editorCreated(editor);
     283}
     284
     285bool FormMultiWidget::eventFilter(QObject *watched, QEvent *event)
     286{
     287    int i = 0;
     288    while (m_editors.at(i) != watched)
     289        if (++i >= m_editors.count()) // Happens when deleting an editor
     290            return false;
     291    if (event->type() == QEvent::FocusOut) {
     292        m_minusButtons.at(i)->setToolTip(QString());
     293        m_plusButtons.at(i)->setToolTip(QString());
     294        m_plusButtons.at(i + 1)->setToolTip(QString());
     295    } else if (event->type() == QEvent::FocusIn) {
     296        m_minusButtons.at(i)->setToolTip(/*: translate, but don't change */ tr("Alt+Delete"));
     297        m_plusButtons.at(i)->setToolTip(/*: translate, but don't change */ tr("Shift+Alt+Insert"));
     298        m_plusButtons.at(i + 1)->setToolTip(/*: translate, but don't change */ tr("Alt+Insert"));
     299    } else if (event->type() == QEvent::KeyPress) {
     300        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
     301        if (ke->modifiers() & Qt::AltModifier) {
     302            if (ke->key() == Qt::Key_Delete) {
     303                deleteEditor(i);
     304                return true;
     305            } else if (ke->key() == Qt::Key_Insert) {
     306                if (!(ke->modifiers() & Qt::ShiftModifier))
     307                    ++i;
     308                insertEditor(i);
     309                return true;
     310            }
     311        }
     312    }
     313    return false;
     314}
     315
     316void FormMultiWidget::updateLayout()
     317{
     318    delete layout();
     319
     320    QGridLayout *layout = new QGridLayout;
     321    layout->setMargin(0);
     322    setLayout(layout);
     323
     324    bool variants = m_multiEnabled && m_label->isEnabled();
     325
     326    layout->addWidget(m_label, 0, 0, 1, variants ? 3 : 1);
     327
     328    for (int i = 0; i < m_plusButtons.count(); ++i) {
     329        if (variants)
     330            layout->addWidget(m_plusButtons.at(i), 1 + i * 2, 0, 2, 1, Qt::AlignTop);
     331        m_plusButtons.at(i)->setVisible(variants);
     332    }
     333    for (int j = 0; j < m_minusButtons.count(); ++j) {
     334        if (variants)
     335            layout->addWidget(m_minusButtons.at(j), 2 + j * 2, 2, 2, 1, Qt::AlignVCenter);
     336        m_minusButtons.at(j)->setVisible(variants);
     337    }
     338    for (int k = 0; k < m_editors.count(); ++k)
     339        layout->addWidget(m_editors.at(k), 2 + k * 2, variants ? 1 : 0, 2, 1, Qt::AlignVCenter);
     340
     341    updateGeometry();
     342}
     343
     344void FormMultiWidget::slotTextChanged()
     345{
     346    emit textChanged(static_cast<QTextEdit *>(sender()));
     347}
     348
     349void FormMultiWidget::slotSelectionChanged()
     350{
     351    emit selectionChanged(static_cast<QTextEdit *>(sender()));
     352}
     353
     354void FormMultiWidget::setTranslation(const QString &text, bool userAction)
     355{
     356    QStringList texts = text.split(QChar(Translator::BinaryVariantSeparator), QString::KeepEmptyParts);
     357
     358    while (m_editors.count() > texts.count()) {
     359        delete m_minusButtons.takeLast();
     360        delete m_plusButtons.takeLast();
     361        delete m_editors.takeLast();
     362    }
     363    while (m_editors.count() < texts.count())
     364        addEditor(m_editors.count());
     365    updateLayout();
     366
     367    for (int i = 0; i < texts.count(); ++i)
     368        // XXX this will emit n textChanged signals
     369        m_editors.at(i)->setPlainText(texts.at(i), userAction);
     370
     371    if (m_hideWhenEmpty)
     372        setHidden(text.isEmpty());
     373}
     374
     375QString FormMultiWidget::getTranslation() const
     376{
     377    QString ret;
     378    for (int i = 0; i < m_editors.count(); ++i) {
     379        if (i)
     380            ret += QChar(Translator::BinaryVariantSeparator);
     381        ret += m_editors.at(i)->toPlainText();
     382    }
     383    return ret;
     384}
     385
     386void FormMultiWidget::setEditingEnabled(bool enable)
     387{
     388    // Use read-only state so that the text can still be copied
     389    for (int i = 0; i < m_editors.count(); ++i)
     390        m_editors.at(i)->setReadOnly(!enable);
     391    m_label->setEnabled(enable);
     392    if (m_multiEnabled)
     393        updateLayout();
     394}
     395
     396void FormMultiWidget::setMultiEnabled(bool enable)
     397{
     398    m_multiEnabled = enable;
     399    if (m_label->isEnabled())
     400        updateLayout();
     401}
     402
     403void FormMultiWidget::minusButtonClicked()
     404{
     405    int i = 0;
     406    while (m_minusButtons.at(i) != sender())
     407        ++i;
     408    deleteEditor(i);
     409}
     410
     411void FormMultiWidget::plusButtonClicked()
     412{
     413    QWidget *btn = static_cast<QAbstractButton *>(sender())->parentWidget();
     414    int i = 0;
     415    while (m_plusButtons.at(i) != btn)
     416        ++i;
     417    insertEditor(i);
     418}
     419
     420void FormMultiWidget::deleteEditor(int idx)
     421{
     422    if (m_editors.count() == 1) {
     423        // Don't just clear(), so the undo history is not lost
     424        QTextCursor c = m_editors.first()->textCursor();
     425        c.select(QTextCursor::Document);
     426        c.removeSelectedText();
     427    } else {
     428        if (!m_editors.at(idx)->toPlainText().isEmpty()) {
     429            if (QMessageBox::question(topLevelWidget(), tr("Confirmation - Qt Linguist"),
     430                                      tr("Delete non-empty length variant?"),
     431                                      QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes)
     432                != QMessageBox::Yes)
     433                return;
     434        }
     435        delete m_editors.takeAt(idx);
     436        delete m_minusButtons.takeAt(idx);
     437        delete m_plusButtons.takeAt(idx + 1);
     438        updateLayout();
     439        emit textChanged(m_editors.at((m_editors.count() == idx) ? idx - 1 : idx));
     440    }
     441}
     442
     443void FormMultiWidget::insertEditor(int idx)
     444{
     445    addEditor(idx);
     446    updateLayout();
     447    emit textChanged(m_editors.at(idx));
     448}
     449
    201450QT_END_NAMESPACE
  • trunk/tools/linguist/linguist/messageeditorwidgets.h

    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 Qt Linguist of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4343#define MESSAGEEDITORWIDGETS_H
    4444
     45#include <QIcon>
    4546#include <QImage>
    4647#include <QLabel>
     
    5253QT_BEGIN_NAMESPACE
    5354
     55class QAbstractButton;
    5456class QAction;
    5557class QContextMenuEvent;
     
    116118
    117119signals:
    118     void textChanged();
    119     void selectionChanged();
     120    void textChanged(QTextEdit *);
     121    void selectionChanged(QTextEdit *);
    120122    void cursorPositionChanged();
     123
     124private slots:
     125    void slotSelectionChanged();
     126    void slotTextChanged();
    121127
    122128private:
     
    126132};
    127133
     134/*
     135  Displays text fields & associated label
     136*/
     137class FormMultiWidget : public QWidget
     138{
     139    Q_OBJECT
     140public:
     141    FormMultiWidget(const QString &label, QWidget *parent = 0);
     142    void setLabel(const QString &label) { m_label->setText(label); }
     143    void setTranslation(const QString &text, bool userAction = false);
     144    void clearTranslation() { setTranslation(QString(), false); }
     145    QString getTranslation() const;
     146    void setEditingEnabled(bool enable);
     147    void setMultiEnabled(bool enable);
     148    void setHideWhenEmpty(bool optional) { m_hideWhenEmpty = optional; }
     149    const QList<FormatTextEdit *> &getEditors() const { return m_editors; }
     150
     151signals:
     152    void editorCreated(QTextEdit *);
     153    void textChanged(QTextEdit *);
     154    void selectionChanged(QTextEdit *);
     155    void cursorPositionChanged();
     156
     157protected:
     158    bool eventFilter(QObject *watched, QEvent *event);
     159
     160private slots:
     161    void slotTextChanged();
     162    void slotSelectionChanged();
     163    void minusButtonClicked();
     164    void plusButtonClicked();
     165
     166private:
     167    void addEditor(int idx);
     168    void updateLayout();
     169    QAbstractButton *makeButton(const QIcon &icon, const char *slot);
     170    void insertEditor(int idx);
     171    void deleteEditor(int idx);
     172
     173    QLabel *m_label;
     174    QList<FormatTextEdit *> m_editors;
     175    QList<QWidget *> m_plusButtons;
     176    QList<QAbstractButton *> m_minusButtons;
     177    bool m_hideWhenEmpty;
     178    bool m_multiEnabled;
     179    QIcon m_plusIcon, m_minusIcon;
     180};
     181
    128182QT_END_NAMESPACE
    129183
  • trunk/tools/linguist/linguist/messagehighlighter.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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/messagehighlighter.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/messagemodel.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 Qt Linguist 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**
     
    140140QStringList DataModel::normalizedTranslations(const MessageItem &m) const
    141141{
    142     return Translator::normalizedTranslations(m.message(), m_language, m_country);
     142    return Translator::normalizedTranslations(m.message(), m_numerusForms.count());
    143143}
    144144
     
    210210    }
    211211
    212     QSet<TranslatorMessagePtr> dupes = tor.resolveDuplicates();
    213     if (!dupes.isEmpty()) {
     212    Translator::Duplicates dupes = tor.resolveDuplicates();
     213    if (!dupes.byId.isEmpty() || !dupes.byContents.isEmpty()) {
    214214        QString err = tr("<qt>Duplicate messages found in '%1':").arg(Qt::escape(fileName));
    215215        int numdups = 0;
    216         foreach (const TranslatorMessagePtr &msg, dupes) {
     216        foreach (int i, dupes.byId) {
     217            if (++numdups >= 5) {
     218                err += tr("<p>[more duplicates omitted]");
     219                goto doWarn;
     220            }
     221            err += tr("<p>* ID: %1").arg(Qt::escape(tor.message(i).id()));
     222        }
     223        foreach (int j, dupes.byContents) {
     224            const TranslatorMessage &msg = tor.message(j);
    217225            if (++numdups >= 5) {
    218226                err += tr("<p>[more duplicates omitted]");
     
    220228            }
    221229            err += tr("<p>* Context: %1<br>* Source: %2")
    222                     .arg(Qt::escape(msg->context()), Qt::escape(msg->sourceText()));
    223             if (!msg->comment().isEmpty())
    224                 err += tr("<br>* Comment: %3").arg(Qt::escape(msg->comment()));
    225         }
     230                    .arg(Qt::escape(msg.context()), Qt::escape(msg.sourceText()));
     231            if (!msg.comment().isEmpty())
     232                err += tr("<br>* Comment: %3").arg(Qt::escape(msg.comment()));
     233        }
     234      doWarn:
    226235        QMessageBox::warning(parent, QObject::tr("Qt Linguist"), err);
    227236    }
     
    778787    m_numEditable = 0;
    779788    m_numMessages = 0;
    780     int delCol = m_dataModels.count();
    781     m_msgModel->beginRemoveColumns(QModelIndex(), 1, delCol);
    782     for (int i = m_multiContextList.size(); --i >= 0;) {
    783         m_msgModel->beginRemoveColumns(m_msgModel->createIndex(i, 0, 0), 1, delCol);
    784         m_msgModel->endRemoveColumns();
    785     }
    786789    qDeleteAll(m_dataModels);
    787790    m_dataModels.clear();
    788791    m_multiContextList.clear();
    789     m_msgModel->endRemoveColumns();
    790792    m_msgModel->reset();
    791793    emit allModelsDeleted();
  • trunk/tools/linguist/linguist/messagemodel.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/phrase.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 Qt Linguist 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**
     
    153153                              const QXmlAttributes &atts)
    154154{
    155     if (qName == QString(QLatin1String("QPH"))) {
     155    if (qName == QLatin1String("QPH")) {
    156156        m_language = atts.value(QLatin1String("language"));
    157157        m_sourceLanguage = atts.value(QLatin1String("sourcelanguage"));
    158     } else if (qName == QString(QLatin1String("phrase"))) {
     158    } else if (qName == QLatin1String("phrase")) {
    159159        source.truncate(0);
    160160        target.truncate(0);
     
    169169                            const QString &qName)
    170170{
    171     if (qName == QString(QLatin1String("source")))
     171    if (qName == QLatin1String("source"))
    172172        source = accum;
    173     else if (qName == QString(QLatin1String("target")))
     173    else if (qName == QLatin1String("target"))
    174174        target = accum;
    175     else if (qName == QString(QLatin1String("definition")))
     175    else if (qName == QLatin1String("definition"))
    176176        definition = accum;
    177     else if (qName == QString(QLatin1String("phrase")))
     177    else if (qName == QLatin1String("phrase"))
    178178        pb->m_phrases.append(new Phrase(source, target, definition, pb));
    179179    return true;
  • trunk/tools/linguist/linguist/phrase.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/phrasebookbox.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 Qt Linguist 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**
     
    5757QT_BEGIN_NAMESPACE
    5858
    59 #define NewPhrase tr("(New Entry)")
    60 
    6159PhraseBookBox::PhraseBookBox(PhraseBook *phraseBook, QWidget *parent)
    6260    : QDialog(parent),
     
    6462      m_translationSettingsDialog(0)
    6563{
     64
     65// This definition needs to be within class context for lupdate to find it
     66#define NewPhrase tr("(New Entry)")
     67
    6668    setupUi(this);
    6769    setWindowTitle(tr("%1[*] - Qt Linguist").arg(m_phraseBook->friendlyPhraseBookName()));
     
    8688    connect(definitionLed, SIGNAL(textChanged(QString)),
    8789            this, SLOT(definitionChanged(QString)));
    88     connect(phraseList->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)),
     90    connect(phraseList->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
    8991            this, SLOT(selectionChanged()));
    9092    connect(newBut, SIGNAL(clicked()), this, SLOT(newPhrase()));
  • trunk/tools/linguist/linguist/phrasebookbox.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/phrasebookbox.ui

    r2 r561  
    44**
    55** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    6 ** Contact: Qt Software Information (qt-info@nokia.com)
     6** All rights reserved.
     7** Contact: Nokia Corporation (qt-info@nokia.com)
    78**
    89** This file is part of the Qt Linguist of the Qt Toolkit.
     
    2324** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2425**
    25 ** In addition, as a special exception, Nokia gives you certain
    26 ** additional rights. These rights are described in the Nokia Qt LGPL
    27 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    28 ** package.
     26** In addition, as a special exception, Nokia gives you certain additional
     27** rights.  These rights are described in the Nokia Qt LGPL Exception
     28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2929**
    3030** GNU General Public License Usage
     
    3636** met: http://www.gnu.org/copyleft/gpl.html.
    3737**
    38 ** If you are unsure which license is appropriate for your use, please
    39 ** contact the sales department at qt-sales@nokia.com.
     38** If you have questions regarding the use of this file, please contact
     39** Nokia at qt-info@nokia.com.
    4040** $QT_END_LICENSE$
    4141**
  • trunk/tools/linguist/linguist/phrasemodel.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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/phrasemodel.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/phraseview.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 Qt Linguist 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**
    4040****************************************************************************/
    4141
     42#include "globals.h"
    4243#include "mainwindow.h"
    4344#include "messagemodel.h"
     
    6263static QString phraseViewHeaderKey()
    6364{
    64     return settingsPrefix() + QLatin1String("PhraseViewHeader");
     65    return settingPath("PhraseViewHeader");
    6566}
    6667
  • trunk/tools/linguist/linguist/phraseview.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/printout.cpp

    r232 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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/printout.h

    r232 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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/recentfiles.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 Qt Linguist 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**
     
    4141
    4242#include "recentfiles.h"
     43#include "globals.h"
    4344
    4445#include <QtCore/QDebug>
     
    5051QT_BEGIN_NAMESPACE
    5152
    52 const QString &settingsPrefix();
    53 
    5453static QString configKey()
    5554{
    56     return settingsPrefix() + QLatin1String("RecentlyOpenedFiles");
     55    return settingPath("RecentlyOpenedFiles");
    5756}
    5857
  • trunk/tools/linguist/linguist/recentfiles.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/sourcecodeview.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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/sourcecodeview.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/statistics.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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/statistics.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/statistics.ui

    r2 r561  
    44**
    55** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    6 ** Contact: Qt Software Information (qt-info@nokia.com)
     6** All rights reserved.
     7** Contact: Nokia Corporation (qt-info@nokia.com)
    78**
    89** This file is part of the Qt Linguist of the Qt Toolkit.
     
    2324** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2425**
    25 ** In addition, as a special exception, Nokia gives you certain
    26 ** additional rights. These rights are described in the Nokia Qt LGPL
    27 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    28 ** package.
     26** In addition, as a special exception, Nokia gives you certain additional
     27** rights.  These rights are described in the Nokia Qt LGPL Exception
     28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2929**
    3030** GNU General Public License Usage
     
    3636** met: http://www.gnu.org/copyleft/gpl.html.
    3737**
    38 ** If you are unsure which license is appropriate for your use, please
    39 ** contact the sales department at qt-sales@nokia.com.
     38** If you have questions regarding the use of this file, please contact
     39** Nokia at qt-info@nokia.com.
    4040** $QT_END_LICENSE$
    4141**
  • trunk/tools/linguist/linguist/translatedialog.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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/translatedialog.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/linguist/translatedialog.ui

    r2 r561  
    44**
    55** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    6 ** Contact: Qt Software Information (qt-info@nokia.com)
     6** All rights reserved.
     7** Contact: Nokia Corporation (qt-info@nokia.com)
    78**
    89** This file is part of the Qt Linguist of the Qt Toolkit.
     
    2324** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2425**
    25 ** In addition, as a special exception, Nokia gives you certain
    26 ** additional rights. These rights are described in the Nokia Qt LGPL
    27 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    28 ** package.
     26** In addition, as a special exception, Nokia gives you certain additional
     27** rights.  These rights are described in the Nokia Qt LGPL Exception
     28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2929**
    3030** GNU General Public License Usage
     
    3636** met: http://www.gnu.org/copyleft/gpl.html.
    3737**
    38 ** If you are unsure which license is appropriate for your use, please
    39 ** contact the sales department at qt-sales@nokia.com.
     38** If you have questions regarding the use of this file, please contact
     39** Nokia at qt-info@nokia.com.
    4040** $QT_END_LICENSE$
    4141**
  • trunk/tools/linguist/linguist/translationsettingsdialog.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 Qt Linguist 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**
     
    6161    m_ui.srcCbLanguageList->insertItem(0, QLatin1String("POSIX"), QVariant(QLocale::C));
    6262
    63     for (int i = QLocale::AnyCountry + 1; i < QLocale::LastCountry; ++i) {
    64         QString country = QLocale::countryToString(QLocale::Country(i));
    65         m_ui.srcCbCountryList->addItem(country, QVariant(i));
    66     }
    67     m_ui.srcCbCountryList->model()->sort(0, Qt::AscendingOrder);
    68     m_ui.srcCbCountryList->insertItem(0, tr("Any Country"), QVariant(QLocale::AnyCountry));
    69 
    7063    m_ui.tgtCbLanguageList->setModel(m_ui.srcCbLanguageList->model());
    71     m_ui.tgtCbCountryList->setModel(m_ui.srcCbCountryList->model());
    7264}
    7365
     
    8678    QString fn = QFileInfo(phraseBook->fileName()).baseName();
    8779    setWindowTitle(tr("Settings for '%1' - Qt Linguist").arg(fn));
     80}
     81
     82static void fillCountryCombo(const QVariant &lng, QComboBox *combo)
     83{
     84    combo->clear();
     85    QLocale::Language lang = QLocale::Language(lng.toInt());
     86    if (lang != QLocale::C) {
     87        foreach (QLocale::Country cntr, QLocale::countriesForLanguage(lang)) {
     88            QString country = QLocale::countryToString(cntr);
     89            combo->addItem(country, QVariant(cntr));
     90        }
     91        combo->model()->sort(0, Qt::AscendingOrder);
     92    }
     93    combo->insertItem(0, TranslationSettingsDialog::tr("Any Country"), QVariant(QLocale::AnyCountry));
     94    combo->setCurrentIndex(0);
     95}
     96
     97void TranslationSettingsDialog::on_srcCbLanguageList_currentIndexChanged(int idx)
     98{
     99    fillCountryCombo(m_ui.srcCbLanguageList->itemData(idx), m_ui.srcCbCountryList);
     100}
     101
     102void TranslationSettingsDialog::on_tgtCbLanguageList_currentIndexChanged(int idx)
     103{
     104    fillCountryCombo(m_ui.tgtCbLanguageList->itemData(idx), m_ui.tgtCbCountryList);
    88105}
    89106
  • trunk/tools/linguist/linguist/translationsettingsdialog.h

    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 Qt Linguist 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**
     
    6767private slots:
    6868    void on_buttonBox_accepted();
     69    void on_srcCbLanguageList_currentIndexChanged(int idx);
     70    void on_tgtCbLanguageList_currentIndexChanged(int idx);
    6971
    7072private:
  • trunk/tools/linguist/lrelease/lrelease.pro

    r385 r561  
    33DESTDIR         = ../../../bin
    44
    5 QT              -= gui
    6 
    7 CONFIG          += qt warn_on console
    8 CONFIG          -= app_bundle
    9 
    10 build_all:!build_pass {
    11     CONFIG -= build_all
    12     CONFIG += release
    13 }
    14 
    155DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII
    166SOURCES += main.cpp
    177
    18 include(../../../src/qt_professional.pri)
     8INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global # qlibraryinfo.cpp includes qconfig.cpp
     9SOURCES += \
     10    $$QT_SOURCE_TREE/src/corelib/global/qlibraryinfo.cpp \
     11    $$QT_SOURCE_TREE/src/corelib/io/qsettings.cpp
     12win32:SOURCES += $$QT_SOURCE_TREE/src/corelib/io/qsettings_win.cpp
     13macx:SOURCES += $$QT_SOURCE_TREE/src/corelib/io/qsettings_mac.cpp
     14
     15include(../../../src/tools/bootstrap/bootstrap.pri)
    1916include(../shared/formats.pri)
    2017include(../shared/proparser.pri)
    21 include(../shared/translatortools.pri)
     18
     19win32:LIBS += -ladvapi32   # for qsettings_win.cpp
    2220
    2321target.path=$$[QT_INSTALL_BINS]
  • trunk/tools/linguist/lrelease/main.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 Qt Linguist 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**
     
    4141
    4242#include "translator.h"
    43 #include "translatortools.h"
    44 #include "profileevaluator.h"
    45 
     43#include "proreader.h"
     44
     45#ifndef QT_BOOTSTRAPPED
    4646#include <QtCore/QCoreApplication>
     47#include <QtCore/QTranslator>
     48#endif
    4749#include <QtCore/QDebug>
    4850#include <QtCore/QDir>
     
    5355#include <QtCore/QStringList>
    5456#include <QtCore/QTextStream>
    55 #include <QtCore/QTranslator>
     57
     58QT_USE_NAMESPACE
     59
     60#ifdef QT_BOOTSTRAPPED
     61static void initBinaryDir(
     62#ifndef Q_OS_WIN
     63        const char *argv0
     64#endif
     65        );
     66#endif
    5667
    5768static void printOut(const QString & out)
     
    6879        "    lrelease [options] ts-files [-qm qm-file]\n\n"
    6980        "lrelease is part of Qt's Linguist tool chain. It can be used as a\n"
    70         "stand-alone tool to convert XML based translations files in the .ts\n"
    71         "format into the 'compiled' .qm format used by QTranslator objects.\n\n"
     81        "stand-alone tool to convert XML-based translations files in the TS\n"
     82        "format into the 'compiled' QM format used by QTranslator objects.\n\n"
    7283        "Options:\n"
    7384        "    -help  Display this information and exit\n"
     85        "    -idbased\n"
     86        "           Use IDs instead of source strings for message keying\n"
    7487        "    -compress\n"
    75         "           Compress the .qm files\n"
     88        "           Compress the QM files\n"
    7689        "    -nounfinished\n"
    7790        "           Do not include unfinished translations\n"
     
    7992        "           If the translated text is the same as\n"
    8093        "           the source text, do not include the message\n"
     94        "    -markuntranslated <prefix>\n"
     95        "           If a message has no real translation, use the source text\n"
     96        "           prefixed with the given string instead\n"
    8197        "    -silent\n"
    82         "           Don't explain what is being done\n"
     98        "           Do not explain what is being done\n"
    8399        "    -version\n"
    84100        "           Display the version of lrelease and exit\n"
     
    100116
    101117static bool releaseTranslator(Translator &tor, const QString &qmFileName,
    102     bool verbose, bool ignoreUnfinished,
    103     bool removeIdentical, TranslatorSaveMode mode)
    104 {
    105     Translator::reportDuplicates(tor.resolveDuplicates(), qmFileName, verbose);
    106 
    107     if (verbose)
     118    ConversionData &cd, bool removeIdentical)
     119{
     120    tor.reportDuplicates(tor.resolveDuplicates(), qmFileName, cd.isVerbose());
     121
     122    if (cd.isVerbose())
    108123        printOut(QCoreApplication::tr( "Updating '%1'...\n").arg(qmFileName));
    109124    if (removeIdentical) {
    110         if ( verbose )
     125        if (cd.isVerbose())
    111126            printOut(QCoreApplication::tr( "Removing translations equal to source text in '%1'...\n").arg(qmFileName));
    112127        tor.stripIdenticalSourceTranslations();
     
    120135    }
    121136
    122     ConversionData cd;
    123     cd.m_verbose = verbose;
    124     cd.m_ignoreUnfinished = ignoreUnfinished;
    125     cd.m_saveMode = mode;
     137    tor.normalizeTranslations(cd);
    126138    bool ok = tor.release(&file, cd);
    127139    file.close();
     
    137149}
    138150
    139 static bool releaseTsFile(const QString& tsFileName, bool verbose,
    140     bool ignoreUnfinished, bool removeIdentical, TranslatorSaveMode mode)
     151static bool releaseTsFile(const QString& tsFileName,
     152    ConversionData &cd, bool removeIdentical)
    141153{
    142154    Translator tor;
    143     if (!loadTsFile(tor, tsFileName, verbose))
     155    if (!loadTsFile(tor, tsFileName, cd.isVerbose()))
    144156        return false;
    145157
     
    153165    qmFileName += QLatin1String(".qm");
    154166
    155     return releaseTranslator(tor, qmFileName, verbose, ignoreUnfinished, removeIdentical, mode);
     167    return releaseTranslator(tor, qmFileName, cd, removeIdentical);
    156168}
    157169
    158170int main(int argc, char **argv)
    159171{
     172#ifdef QT_BOOTSTRAPPED
     173    initBinaryDir(
     174#ifndef Q_OS_WIN
     175            argv[0]
     176#endif
     177            );
     178#else
    160179    QCoreApplication app(argc, argv);
    161     QStringList args = app.arguments();
    162180    QTranslator translator;
    163181    if (translator.load(QLatin1String("lrelease_") + QLocale::system().name()))
    164182        app.installTranslator(&translator);
    165 
    166     bool verbose = true; // the default is true starting with Qt 4.2
    167     bool ignoreUnfinished = false;
    168     // the default mode is SaveEverything starting with Qt 4.2
    169     TranslatorSaveMode mode = SaveEverything;
     183#endif
     184
     185    ConversionData cd;
     186    cd.m_verbose = true; // the default is true starting with Qt 4.2
    170187    bool removeIdentical = false;
    171188    Translator tor;
     189    QStringList inputFiles;
    172190    QString outputFile;
    173     int numFiles = 0;
    174191
    175192    for (int i = 1; i < argc; ++i) {
    176         if (args[i] == QLatin1String("-compress")) {
    177             mode = SaveStripped;
    178             continue;
    179         } else if (args[i] == QLatin1String("-nocompress")) {
    180             mode = SaveEverything;
    181             continue;
    182         } else if (args[i] == QLatin1String("-removeidentical")) {
     193        if (!strcmp(argv[i], "-compress")) {
     194            cd.m_saveMode = SaveStripped;
     195            continue;
     196        } else if (!strcmp(argv[i], "-idbased")) {
     197            cd.m_idBased = true;
     198            continue;
     199        } else if (!strcmp(argv[i], "-nocompress")) {
     200            cd.m_saveMode = SaveEverything;
     201            continue;
     202        } else if (!strcmp(argv[i], "-removeidentical")) {
    183203            removeIdentical = true;
    184204            continue;
    185         } else if (args[i] == QLatin1String("-nounfinished")) {
    186             ignoreUnfinished = true;
    187             continue;
    188         } else if (args[i] == QLatin1String("-silent")) {
    189             verbose = false;
    190             continue;
    191         } else if (args[i] == QLatin1String("-verbose")) {
    192             verbose = true;
    193             continue;
    194         } else if (args[i] == QLatin1String("-version")) {
    195             printOut(QCoreApplication::tr( "lrelease version %1\n").arg(QLatin1String(QT_VERSION_STR)) );
    196             return 0;
    197         } else if (args[i] == QLatin1String("-qm")) {
     205        } else if (!strcmp(argv[i], "-nounfinished")) {
     206            cd.m_ignoreUnfinished = true;
     207            continue;
     208        } else if (!strcmp(argv[i], "-markuntranslated")) {
    198209            if (i == argc - 1) {
    199210                printUsage();
    200211                return 1;
    201212            }
    202             i++;
    203             outputFile = args[i];
    204         } else if (args[i] == QLatin1String("-help")) {
     213            cd.m_unTrPrefix = QString::fromLocal8Bit(argv[++i]);
     214        } else if (!strcmp(argv[i], "-silent")) {
     215            cd.m_verbose = false;
     216            continue;
     217        } else if (!strcmp(argv[i], "-verbose")) {
     218            cd.m_verbose = true;
     219            continue;
     220        } else if (!strcmp(argv[i], "-version")) {
     221            printOut(QCoreApplication::tr( "lrelease version %1\n").arg(QLatin1String(QT_VERSION_STR)) );
     222            return 0;
     223        } else if (!strcmp(argv[i], "-qm")) {
     224            if (i == argc - 1) {
     225                printUsage();
     226                return 1;
     227            }
     228            outputFile = QString::fromLocal8Bit(argv[++i]);
     229        } else if (!strcmp(argv[i], "-help")) {
    205230            printUsage();
    206231            return 0;
    207         } else if (args[i][0] == QLatin1Char('-')) {
     232        } else if (argv[i][0] == '-') {
    208233            printUsage();
    209234            return 1;
    210235        } else {
    211             numFiles++;
     236            inputFiles << QString::fromLocal8Bit(argv[i]);
    212237        }
    213238    }
    214239
    215     if (numFiles == 0) {
     240    if (inputFiles.isEmpty()) {
    216241        printUsage();
    217242        return 1;
    218243    }
    219244
    220     for (int i = 1; i < argc; ++i) {
    221         if (args[i][0] == QLatin1Char('-') || args[i] == outputFile)
    222             continue;
    223 
    224         if (args[i].endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
    225             || args[i].endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
     245    foreach (const QString &inputFile, inputFiles) {
     246        if (inputFile.endsWith(QLatin1String(".pro"), Qt::CaseInsensitive)
     247            || inputFile.endsWith(QLatin1String(".pri"), Qt::CaseInsensitive)) {
    226248            QHash<QByteArray, QStringList> varMap;
    227             bool ok = evaluateProFile(args[i], verbose, &varMap );
     249            bool ok = evaluateProFile(inputFile, cd.isVerbose(), &varMap);
    228250            if (ok) {
    229251                QStringList translations = varMap.value("TRANSLATIONS");
     
    231253                    qWarning("lrelease warning: Met no 'TRANSLATIONS' entry in"
    232254                             " project file '%s'\n",
    233                              qPrintable(args[i]));
     255                             qPrintable(inputFile));
    234256                } else {
    235257                    foreach (const QString &trans, translations)
    236                         if (!releaseTsFile(trans, verbose, ignoreUnfinished, removeIdentical, mode))
     258                        if (!releaseTsFile(trans, cd, removeIdentical))
    237259                            return 1;
    238260                }
    239261            } else {
    240262                qWarning("error: lrelease encountered project file functionality that is currently not supported.\n"
    241                     "You might want to consider using .ts files as input instead of a project file.\n"
     263                    "You might want to consider using TS files as input instead of a project file.\n"
    242264                    "Try the following syntax:\n"
    243265                    "    lrelease [options] ts-files [-qm qm-file]\n");
     
    245267        } else {
    246268            if (outputFile.isEmpty()) {
    247                 if (!releaseTsFile(args[i], verbose, ignoreUnfinished, removeIdentical, mode))
     269                if (!releaseTsFile(inputFile, cd, removeIdentical))
    248270                    return 1;
    249271            } else {
    250                 if (!loadTsFile(tor, args[i], verbose))
     272                if (!loadTsFile(tor, inputFile, cd.isVerbose()))
    251273                    return 1;
    252274            }
     
    255277
    256278    if (!outputFile.isEmpty())
    257         return releaseTranslator(tor, outputFile, verbose, ignoreUnfinished,
    258                                  removeIdentical, mode) ? 0 : 1;
     279        return releaseTranslator(tor, outputFile, cd, removeIdentical) ? 0 : 1;
    259280
    260281    return 0;
    261282}
     283
     284#ifdef QT_BOOTSTRAPPED
     285
     286#ifdef Q_OS_WIN
     287# include <windows.h>
     288#endif
     289
     290static QString binDir;
     291
     292static void initBinaryDir(
     293#ifndef Q_OS_WIN
     294        const char *_argv0
     295#endif
     296        )
     297{
     298#ifdef Q_OS_WIN
     299    wchar_t module_name[MAX_PATH];
     300    GetModuleFileName(0, module_name, MAX_PATH);
     301    QFileInfo filePath = QString::fromWCharArray(module_name);
     302    binDir = filePath.filePath();
     303#else
     304    QString argv0 = QFile::decodeName(QByteArray(_argv0));
     305    QString absPath;
     306
     307    if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) {
     308        /*
     309          If argv0 starts with a slash, it is already an absolute
     310          file path.
     311        */
     312        absPath = argv0;
     313    } else if (argv0.contains(QLatin1Char('/'))) {
     314        /*
     315          If argv0 contains one or more slashes, it is a file path
     316          relative to the current directory.
     317        */
     318        absPath = QDir::current().absoluteFilePath(argv0);
     319    } else {
     320        /*
     321          Otherwise, the file path has to be determined using the
     322          PATH environment variable.
     323        */
     324        QByteArray pEnv = qgetenv("PATH");
     325        QDir currentDir = QDir::current();
     326        QStringList paths = QString::fromLocal8Bit(pEnv.constData()).split(QLatin1String(":"));
     327        for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
     328            if ((*p).isEmpty())
     329                continue;
     330            QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
     331            QFileInfo candidate_fi(candidate);
     332            if (candidate_fi.exists() && !candidate_fi.isDir()) {
     333                binDir = candidate_fi.canonicalPath();
     334                return;
     335            }
     336        }
     337        return;
     338    }
     339
     340    QFileInfo fi(absPath);
     341    if (fi.exists())
     342        binDir = fi.canonicalPath();
     343#endif
     344}
     345
     346QT_BEGIN_NAMESPACE
     347
     348// The name is hard-coded in QLibraryInfo
     349QString qmake_libraryInfoFile()
     350{
     351    if (binDir.isEmpty())
     352        return QString();
     353    return QDir(binDir).filePath(QString::fromLatin1("qt.conf"));
     354}
     355
     356QT_END_NAMESPACE
     357
     358#endif // QT_BOOTSTRAPPED
  • trunk/tools/linguist/lupdate/lupdate.pro

    r385 r561  
    1515include(../shared/formats.pri)
    1616include(../shared/proparser.pri)
    17 include(../shared/translatortools.pri)
    1817
    19 SOURCES += main.cpp
     18SOURCES += \
     19    main.cpp \
     20    merge.cpp \
     21    ../shared/simtexth.cpp \
     22    \
     23    cpp.cpp \
     24    java.cpp \
     25    qscript.cpp \
     26    ui.cpp
     27
     28HEADERS += \
     29    lupdate.h \
     30    ../shared/simtexth.h
    2031
    2132DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
  • trunk/tools/linguist/lupdate/main.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 Qt Linguist 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**
    4040****************************************************************************/
    4141
    42 #include "translator.h"
    43 #include "translatortools.h"
    44 #include "profileevaluator.h"
     42#include "lupdate.h"
     43
     44#include <translator.h>
     45#include <profileevaluator.h>
     46#include <proreader.h>
    4547
    4648#include <QtCore/QCoreApplication>
     
    5355#include <QtCore/QTextCodec>
    5456
     57#include <iostream>
     58
    5559static QString m_defaultExtensions;
    5660
    57 static void printOut(const QString & out)
     61static void printErr(const QString & out)
    5862{
    5963    qWarning("%s", qPrintable(out));
    6064}
    6165
     66static void printOut(const QString & out)
     67{
     68    std::cerr << qPrintable(out);
     69}
     70
    6271static void recursiveFileInfoList(const QDir &dir,
    63     const QStringList &nameFilters, QDir::Filters filter, bool recursive,
     72    const QSet<QString> &nameFilters, QDir::Filters filter,
    6473    QFileInfoList *fileinfolist)
    6574{
    66     if (recursive)
    67         filter |= QDir::AllDirs;
    68     QFileInfoList entries = dir.entryInfoList(nameFilters, filter);
    69 
    70     QFileInfoList::iterator it;
    71     for (it = entries.begin(); it != entries.end(); ++it) {
    72         QString fname = it->fileName();
    73         if (fname != QLatin1String(".") && fname != QLatin1String("..")) {
    74             if (it->isDir())
    75                 recursiveFileInfoList(QDir(it->absoluteFilePath()), nameFilters, filter, recursive, fileinfolist);
    76             else
    77                 fileinfolist->append(*it);
    78         }
    79     }
     75    foreach (const QFileInfo &fi, dir.entryInfoList(filter))
     76        if (fi.isDir())
     77            recursiveFileInfoList(QDir(fi.absoluteFilePath()), nameFilters, filter, fileinfolist);
     78        else if (nameFilters.contains(fi.suffix()))
     79            fileinfolist->append(fi);
    8080}
    8181
     
    8484    printOut(QObject::tr(
    8585        "Usage:\n"
    86         "    lupdate [options] [project-file]\n"
     86        "    lupdate [options] [project-file]...\n"
    8787        "    lupdate [options] [source-file|path]... -ts ts-files\n\n"
    88         "lupdate is part of Qt's Linguist tool chain. It can be used as a\n"
    89         "stand-alone tool to create XML based translations files in the .ts\n"
    90         "format from translatable messages in C++ and Java source code.\n\n"
    91         "lupdate can also merge such messages into existing .ts files.\n\n"
     88        "lupdate is part of Qt's Linguist tool chain. It extracts translatable\n"
     89        "messages from Qt UI files, C++, Java and JavaScript/QtScript source code.\n"
     90        "Extracted messages are stored in textual translation source files (typically\n"
     91        "Qt TS XML). New and modified messages can be merged into existing TS files.\n\n"
    9292        "Options:\n"
    9393        "    -help  Display this information and exit.\n"
     
    103103        "           Do not explain what is being done.\n"
    104104        "    -no-sort\n"
    105         "           Do not sort contexts in .ts files.\n"
     105        "           Do not sort contexts in TS files.\n"
    106106        "    -no-recursive\n"
    107107        "           Do not recursively scan the following directories.\n"
    108108        "    -recursive\n"
    109         "           Recursively scan the following directories.\n"
     109        "           Recursively scan the following directories (default).\n"
     110        "    -I <includepath> or -I<includepath>\n"
     111        "           Additional location to look for include files.\n"
     112        "           May be specified multiple times.\n"
    110113        "    -locations {absolute|relative|none}\n"
    111         "           Specify/override how source code references are saved in ts files.\n"
     114        "           Specify/override how source code references are saved in TS files.\n"
    112115        "           Default is absolute.\n"
    113116        "    -no-ui-lines\n"
    114         "           Do not record line numbers in references to .ui files.\n"
     117        "           Do not record line numbers in references to UI files.\n"
    115118        "    -disable-heuristic {sametext|similartext|number}\n"
    116119        "           Disable the named merge heuristic. Can be specified multiple times.\n"
     
    119122        "           file syntax but different file suffix\n"
    120123        "    -source-language <language>[_<region>]\n"
    121         "           Specify/override the language of the source strings. Defaults to\n"
    122         "           POSIX if not specified and the file does not name it yet.\n"
     124        "           Specify the language of the source strings for new files.\n"
     125        "           Defaults to POSIX if not specified.\n"
    123126        "    -target-language <language>[_<region>]\n"
    124         "           Specify/override the language of the translation.\n"
    125         "           The target language is guessed from the file name if this option\n"
    126         "           is not specified and the file contents name no language yet.\n"
     127        "           Specify the language of the translations for new files.\n"
     128        "           Guessed from the file name if not specified.\n"
    127129        "    -version\n"
    128130        "           Display the version of lupdate and exit.\n"
     
    143145        if (QFile(fileName).exists()) {
    144146            if (!tor.load(fileName, cd, QLatin1String("auto"))) {
    145                 printOut(cd.error());
     147                printErr(cd.error());
    146148                *fail = true;
    147149                continue;
     
    166168            if (!targetLanguage.isEmpty())
    167169                tor.setLanguageCode(targetLanguage);
     170            else
     171                tor.setLanguageCode(Translator::guessLanguageCodeFromFileName(fileName));
    168172            if (!sourceLanguage.isEmpty())
    169173                tor.setSourceLanguageCode(sourceLanguage);
     
    179183            printOut(QObject::tr("Updating '%1'...\n").arg(fn));
    180184
     185        UpdateOptions theseOptions = options;
    181186        if (tor.locationsType() == Translator::NoLocations) // Could be set from file
    182             options |= NoLocations;
    183         Translator out = merge(tor, fetchedTor, options, err);
     187            theseOptions |= NoLocations;
     188        Translator out = merge(tor, fetchedTor, theseOptions, err);
    184189        if (!codecForTr.isEmpty())
    185190            out.setCodecName(codecForTr);
     
    198203        out.stripEmptyContexts();
    199204
     205        out.normalizeTranslations(cd);
     206        if (!cd.errors().isEmpty()) {
     207            printErr(cd.error());
     208            cd.clearErrors();
     209        }
    200210        if (!out.save(fileName, cd, QLatin1String("auto"))) {
    201             printOut(cd.error());
     211            printErr(cd.error());
    202212            *fail = true;
    203213        }
     
    217227    QStringList tsFileNames;
    218228    QStringList proFiles;
     229    QMultiHash<QString, QString> allCSources;
     230    QSet<QString> projectRoots;
    219231    QStringList sourceFiles;
     232    QStringList includePath;
    220233    QString targetLanguage;
    221234    QString sourceLanguage;
     
    230243
    231244    QString extensions = m_defaultExtensions;
    232     QStringList extensionsNameFilters;
     245    QSet<QString> extensionsNameFilters;
    233246
    234247    for (int  i = 1; i < argc; ++i) {
     
    343356            proFiles += args[i];
    344357            numFiles++;
     358            continue;
     359        } else if (arg.startsWith(QLatin1String("-I"))) {
     360            if (arg.length() == 2) {
     361                ++i;
     362                if (i == argc) {
     363                    qWarning("The -I option should be followed by a path.");
     364                    return 1;
     365                }
     366                includePath += args[i];
     367            } else {
     368                includePath += args[i].mid(2);
     369            }
    345370            continue;
    346371        } else if (arg.startsWith(QLatin1String("-")) && arg != QLatin1String("-")) {
     
    388413                    printOut(QObject::tr("Scanning directory '%1'...").arg(arg));
    389414                QDir dir = QDir(fi.filePath());
     415                projectRoots.insert(dir.absolutePath() + QLatin1Char('/'));
    390416                if (extensionsNameFilters.isEmpty()) {
    391                     extensions = extensions.trimmed();
    392                     // Remove the potential dot in front of each extension
    393                     if (extensions.startsWith(QLatin1Char('.')))
    394                         extensions.remove(0,1);
    395                     extensions.replace(QLatin1String(",."), QLatin1String(","));
    396 
    397                     extensions.insert(0, QLatin1String("*."));
    398                     extensions.replace(QLatin1Char(','), QLatin1String(",*."));
    399                     extensionsNameFilters = extensions.split(QLatin1Char(','));
     417                    foreach (QString ext, extensions.split(QLatin1Char(','))) {
     418                        ext = ext.trimmed();
     419                        if (ext.startsWith(QLatin1Char('.')))
     420                            ext.remove(0, 1);
     421                        extensionsNameFilters.insert(ext);
     422                    }
    400423                }
    401424                QDir::Filters filters = QDir::Files | QDir::NoSymLinks;
     425                if (recursiveScan)
     426                    filters |= QDir::AllDirs | QDir::NoDotAndDotDot;
    402427                QFileInfoList fileinfolist;
    403                 recursiveFileInfoList(dir, extensionsNameFilters, filters,
    404                     recursiveScan, &fileinfolist);
    405                 QFileInfoList::iterator ii;
    406                 QString fn;
    407                 for (ii = fileinfolist.begin(); ii != fileinfolist.end(); ++ii) {
    408                     // Make sure the path separator is stored with '/' in the ts file
    409                     sourceFiles << ii->canonicalFilePath().replace(QLatin1Char('\\'), QLatin1Char('/'));
     428                recursiveFileInfoList(dir, extensionsNameFilters, filters, &fileinfolist);
     429                int scanRootLen = dir.absolutePath().length();
     430                foreach (const QFileInfo &fi, fileinfolist) {
     431                    QString fn = QDir::cleanPath(fi.absoluteFilePath());
     432                    sourceFiles << fn;
     433
     434                    if (!fn.endsWith(QLatin1String(".java"))
     435                        && !fn.endsWith(QLatin1String(".ui"))
     436                        && !fn.endsWith(QLatin1String(".js"))
     437                        && !fn.endsWith(QLatin1String(".qs"))) {
     438                        int offset = 0;
     439                        int depth = 0;
     440                        do {
     441                            offset = fn.lastIndexOf(QLatin1Char('/'), offset - 1);
     442                            QString ffn = fn.mid(offset + 1);
     443                            allCSources.insert(ffn, fn);
     444                        } while (++depth < 3 && offset > scanRootLen);
     445                    }
    410446                }
    411447            } else {
    412                 sourceFiles << fi.canonicalFilePath().replace(QLatin1Char('\\'), QLatin1Char('/'));
     448                sourceFiles << QDir::cleanPath(fi.absoluteFilePath());;
    413449            }
    414450        }
    415451    } // for args
    416452
     453    foreach (const QString &proFile, proFiles)
     454        projectRoots.insert(QDir::cleanPath(QFileInfo(proFile).absolutePath()) + QLatin1Char('/'));
    417455
    418456    bool firstPass = true;
     
    422460        cd.m_defaultContext = defaultContext;
    423461        cd.m_noUiLines = options & NoUiLines;
     462        cd.m_projectRoots = projectRoots;
     463        cd.m_includePath = includePath;
     464        cd.m_allCSources = allCSources;
    424465
    425466        QStringList tsFiles = tsFileNames;
     
    451492            }
    452493
    453             evaluateProFile(visitor, &variables);
     494            cd.m_includePath += visitor.values(QLatin1String("INCLUDEPATH"));
     495
     496            evaluateProFile(visitor, &variables, pfi.absolutePath());
    454497
    455498            sourceFiles = variables.value("SOURCES");
     
    459502                codecForTr = tmp.first().toLatin1();
    460503                fetchedTor.setCodecName(codecForTr);
     504                cd.m_outputCodec = codecForTr;
    461505            }
    462506            tmp = variables.value("CODECFORSRC");
     
    473517        }
    474518
     519        QStringList sourceFilesCpp;
    475520        for (QStringList::iterator it = sourceFiles.begin(); it != sourceFiles.end(); ++it) {
    476             if (it->endsWith(QLatin1String(".java"), Qt::CaseInsensitive)) {
    477                 cd.m_sourceFileName = *it;
    478                 fetchedTor.load(*it, cd, QLatin1String("java"));
    479                 //fetchtr_java(*it, &fetchedTor, defaultContext, true, codecForSource);
    480             }
    481             else if (it->endsWith(QLatin1String(".ui"), Qt::CaseInsensitive)) {
    482                 fetchedTor.load(*it, cd, QLatin1String("ui"));
    483                 //fetchedTor.load(*it + QLatin1String(".h"), cd, QLatin1String("cpp"));
    484                 //fetchtr_ui(*it, &fetchedTor, defaultContext, true);
    485                 //fetchtr_cpp(*it + QLatin1String(".h"), &fetchedTor,
    486                 //             defaultContext, false, codecForSource);
    487             }
     521            if (it->endsWith(QLatin1String(".java"), Qt::CaseInsensitive))
     522                loadJava(fetchedTor, *it, cd);
     523            else if (it->endsWith(QLatin1String(".ui"), Qt::CaseInsensitive)
     524                     || it->endsWith(QLatin1String(".jui"), Qt::CaseInsensitive))
     525                loadUI(fetchedTor, *it, cd);
    488526            else if (it->endsWith(QLatin1String(".js"), Qt::CaseInsensitive)
    489                 || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive)) {
    490                 fetchedTor.load(*it, cd, QLatin1String("js"));
    491             } else {
    492                 fetchedTor.load(*it, cd, QLatin1String("cpp"));
    493                 //fetchtr_cpp(*it, &fetchedTor, defaultContext, true, codecForSource);
    494             }
    495         }
     527                     || it->endsWith(QLatin1String(".qs"), Qt::CaseInsensitive))
     528                loadQScript(fetchedTor, *it, cd);
     529            else
     530                sourceFilesCpp << *it;
     531        }
     532        loadCPP(fetchedTor, sourceFilesCpp, cd);
    496533        if (!cd.error().isEmpty())
    497534            printOut(cd.error());
  • trunk/tools/linguist/phrasebooks/french.qph

    r2 r561  
    1 <!DOCTYPE QPH><QPH language="fr">
     1<!DOCTYPE QPH>
     2<QPH language="fr">
    23<phrase>
    34    <source>About</source>
     
    11021103    <target>Oui</target>
    11031104</phrase>
     1105<phrase>
     1106    <source>Split</source>
     1107    <target>Scinder</target>
     1108</phrase>
     1109<phrase>
     1110    <source>&amp;Edit</source>
     1111    <target>&amp;Édition</target>
     1112</phrase>
     1113<phrase>
     1114    <source>&amp;Redo</source>
     1115    <target>Re&amp;faire</target>
     1116</phrase>
     1117<phrase>
     1118    <source>debugger</source>
     1119    <target>débogueur</target>
     1120</phrase>
     1121<phrase>
     1122    <source>Start Debugger</source>
     1123    <target>Lancer le débogueur</target>
     1124</phrase>
     1125<phrase>
     1126    <source>Executable:</source>
     1127    <target>Exécutable:</target>
     1128</phrase>
     1129<phrase>
     1130    <source>Filter:</source>
     1131    <target>Filtre:</target>
     1132</phrase>
     1133<phrase>
     1134    <source>Clear</source>
     1135    <target>Effacer</target>
     1136</phrase>
     1137<phrase>
     1138    <source>Host and port:</source>
     1139    <target>HÃŽte et port:</target>
     1140</phrase>
     1141<phrase>
     1142    <source>Architecture:</source>
     1143    <target>Architecture:</target>
     1144</phrase>
     1145<phrase>
     1146    <source>Server start script:</source>
     1147    <target>Script de démarrage du serveur:</target>
     1148</phrase>
     1149<phrase>
     1150    <source>&amp;Undo</source>
     1151    <target>Annu&amp;ler</target>
     1152</phrase>
     1153<phrase>
     1154    <source>Add Bookmark</source>
     1155    <target>Ajouter un signet</target>
     1156</phrase>
     1157<phrase>
     1158    <source>Bookmark:</source>
     1159    <target>Signet:</target>
     1160</phrase>
     1161<phrase>
     1162    <source>Add in Folder:</source>
     1163    <target>Ajouter dans le dossier:</target>
     1164</phrase>
     1165<phrase>
     1166    <source>+</source>
     1167    <target>+</target>
     1168</phrase>
     1169<phrase>
     1170    <source>New Folder</source>
     1171    <target>Nouveau dossier</target>
     1172</phrase>
     1173<phrase>
     1174    <source>Bookmarks</source>
     1175    <target>Signets</target>
     1176</phrase>
     1177<phrase>
     1178    <source>Rename Folder</source>
     1179    <target>Renommer le dossier</target>
     1180</phrase>
     1181<phrase>
     1182    <source>Bookmark</source>
     1183    <target>Signet</target>
     1184</phrase>
     1185<phrase>
     1186    <source>Remove</source>
     1187    <target>Retirer</target>
     1188</phrase>
     1189<phrase>
     1190    <source>Delete Folder</source>
     1191    <target>Supprimer le dossier</target>
     1192</phrase>
     1193<phrase>
     1194    <source>Add</source>
     1195    <target>Ajouter</target>
     1196</phrase>
     1197<phrase>
     1198    <source>Move Up</source>
     1199    <target>Vers le Haut</target>
     1200</phrase>
     1201<phrase>
     1202    <source>Move Down</source>
     1203    <target>Vers le Bas</target>
     1204</phrase>
     1205<phrase>
     1206    <source>Show Bookmark</source>
     1207    <target>Afficher le signet</target>
     1208</phrase>
     1209<phrase>
     1210    <source>Show Bookmark in New Tab</source>
     1211    <target>Afficher le signet dans un nouvel onglet</target>
     1212</phrase>
     1213<phrase>
     1214    <source>Delete Bookmark</source>
     1215    <target>Supprimer le signet</target>
     1216</phrase>
     1217<phrase>
     1218    <source>Rename Bookmark</source>
     1219    <target>Renommer le signet</target>
     1220</phrase>
     1221<phrase>
     1222    <source>Previous Bookmark</source>
     1223    <target>Signet précédent</target>
     1224</phrase>
     1225<phrase>
     1226    <source>Next Bookmark</source>
     1227    <target>Signet suivant</target>
     1228</phrase>
     1229<phrase>
     1230    <source>Condition:</source>
     1231    <target>Condition:</target>
     1232</phrase>
     1233<phrase>
     1234    <source>Working Directory:</source>
     1235    <target>Répertoire de travail:</target>
     1236</phrase>
     1237<phrase>
     1238    <source>Environment</source>
     1239    <target>Environnement</target>
     1240</phrase>
     1241<phrase>
     1242    <source>Arguments</source>
     1243    <target>Arguments</target>
     1244</phrase>
     1245<phrase>
     1246    <source>Build directory:</source>
     1247    <target>Répertoire de compilation:</target>
     1248</phrase>
     1249<phrase>
     1250    <source>Path:</source>
     1251    <target>Chemin:</target>
     1252</phrase>
     1253<phrase>
     1254    <source>General</source>
     1255    <target>Général</target>
     1256</phrase>
     1257<phrase>
     1258    <source>Username:</source>
     1259    <target>Nom d&apos;utilisateur:</target>
     1260</phrase>
     1261<phrase>
     1262    <source>User interface</source>
     1263    <target>Interface utilisateur</target>
     1264</phrase>
     1265<phrase>
     1266    <source>Open Link</source>
     1267    <target>Ouvrir le lien</target>
     1268</phrase>
     1269<phrase>
     1270    <source> [read only]</source>
     1271    <target> [lecture seule]</target>
     1272</phrase>
     1273<phrase>
     1274    <source> [directory]</source>
     1275    <target> [répertoire]</target>
     1276</phrase>
     1277<phrase>
     1278    <source>Close All</source>
     1279    <target>Fermer tout</target>
     1280</phrase>
     1281<phrase>
     1282    <source>Failed!</source>
     1283    <target>Échec!</target>
     1284</phrase>
     1285<phrase>
     1286    <source>Proceed</source>
     1287    <target>Continuer</target>
     1288</phrase>
     1289<phrase>
     1290    <source>Make writable</source>
     1291    <target>Rendre inscriptible</target>
     1292</phrase>
     1293<phrase>
     1294    <source>Qt Creator</source>
     1295    <target>Qt Creator</target>
     1296</phrase>
     1297<phrase>
     1298    <source>&amp;File</source>
     1299    <target>&amp;Fichier</target>
     1300</phrase>
     1301<phrase>
     1302    <source>Activate %1</source>
     1303    <target>Activer %1</target>
     1304</phrase>
     1305<phrase>
     1306    <source>New Project</source>
     1307    <target>Nouveau projet</target>
     1308</phrase>
     1309<phrase>
     1310    <source>Close %1</source>
     1311    <target>Fermer %1</target>
     1312</phrase>
     1313<phrase>
     1314    <source>*</source>
     1315    <target>*</target>
     1316</phrase>
     1317<phrase>
     1318    <source>&amp;Change</source>
     1319    <target>&amp;Modifier</target>
     1320</phrase>
     1321<phrase>
     1322    <source>Close Other Editors</source>
     1323    <target>Fermer les autres éditeurs</target>
     1324</phrase>
     1325<phrase>
     1326    <source>Close All Except %1</source>
     1327    <target>Fermer tout sauf %1</target>
     1328</phrase>
     1329<phrase>
     1330    <source>Remove</source>
     1331    <target>Suppression</target>
     1332</phrase>
     1333<phrase>
     1334    <source>About...</source>
     1335    <target>À propos
</target>
     1336</phrase>
     1337<phrase>
     1338    <source>Minimize</source>
     1339    <target>Minimiser</target>
     1340</phrase>
     1341<phrase>
     1342    <source>Remove</source>
     1343    <target>Supprimer</target>
     1344</phrase>
     1345<phrase>
     1346    <source>Select All</source>
     1347    <target>Sélectionner tout</target>
     1348</phrase>
     1349<phrase>
     1350    <source>Cannot create directory: %1</source>
     1351    <target>Impossible de créer le répertoire : %1</target>
     1352</phrase>
     1353<phrase>
     1354    <source></source>
     1355    <target></target>
     1356</phrase>
     1357<phrase>
     1358    <source>Whole &amp;words</source>
     1359    <target>M&amp;ots complets</target>
     1360</phrase>
     1361<phrase>
     1362    <source>Title:</source>
     1363    <target>Titre :</target>
     1364</phrase>
     1365<phrase>
     1366    <source>Fonts</source>
     1367    <target>Polices</target>
     1368</phrase>
     1369<phrase>
     1370    <source>Insert</source>
     1371    <target>Insérer</target>
     1372</phrase>
     1373<phrase>
     1374    <source>Size</source>
     1375    <target>Taille</target>
     1376</phrase>
     1377<phrase>
     1378    <source>List View</source>
     1379    <target>Affichage liste</target>
     1380</phrase>
     1381<phrase>
     1382    <source>Read-only</source>
     1383    <target>Lecture seule</target>
     1384</phrase>
     1385<phrase>
     1386    <source>Minimize</source>
     1387    <target>Réduire</target>
     1388</phrase>
     1389<phrase>
     1390    <source>Maximize</source>
     1391    <target>Maximiser</target>
     1392</phrase>
     1393<phrase>
     1394    <source>Retry</source>
     1395    <target>Réessayer</target>
     1396</phrase>
     1397<phrase>
     1398    <source>Dock</source>
     1399    <target>Attacher</target>
     1400</phrase>
     1401<phrase>
     1402    <source>&amp;Redo</source>
     1403    <target>&amp;Rétablir</target>
     1404</phrase>
     1405<phrase>
     1406    <source>Edit</source>
     1407    <target>Éditer</target>
     1408</phrase>
     1409<phrase>
     1410    <source>PATH:</source>
     1411    <target>PATH :</target>
     1412</phrase>
     1413<phrase>
     1414    <source>Change:</source>
     1415    <target>Modification :</target>
     1416</phrase>
     1417<phrase>
     1418    <source>Edit...</source>
     1419    <target>Modifier...</target>
     1420</phrase>
     1421<phrase>
     1422    <source>&amp;Username:</source>
     1423    <target>&amp;Utilisateur :</target>
     1424</phrase>
     1425<phrase>
     1426    <source>Link</source>
     1427    <target>Lien</target>
     1428</phrase>
     1429<phrase>
     1430    <source>Paste:</source>
     1431    <target>Collage :</target>
     1432</phrase>
     1433<phrase>
     1434    <source>Label</source>
     1435    <target>Libellé</target>
     1436</phrase>
     1437<phrase>
     1438    <source>&amp;Debug</source>
     1439    <target>&amp;Déboguer</target>
     1440</phrase>
    11041441</QPH>
  • trunk/tools/linguist/phrasebooks/polish.qph

    r2 r561  
    532532<phrase>
    533533    <source>You need a commercial</source>
    534     <target>Aby móc sprzedawać aplikację utworzone przy pomocy Qt potrzebujesz wersji komercyjnej. Proszę sprawdzić &lt;a href=&quot;http://qtsoftware.com/company/model.html&quot;&gt;qtsoftware.com/company/model.html&lt;/a&gt; dla poznania sposobu licencjonowania Qt.</target>
     534    <target>Aby móc sprzedawać aplikację utworzone przy pomocy Qt potrzebujesz wersji komercyjnej. Proszę sprawdzić &lt;a href=&quot;http://qt.nokia.com/about&quot;&gt;qt.nokia.com/about&lt;/a&gt; dla poznania sposobu licencjonowania Qt.</target>
    535535</phrase>
    536536<phrase>
  • trunk/tools/linguist/phrasebooks/russian.qph

    r2 r561  
    1 <!DOCTYPE QPH><QPH language="ru">
     1<!DOCTYPE QPH>
     2<QPH language="ru">
    23<phrase>
    34    <source>About</source>
     
    1011<phrase>
    1112    <source>accessibility</source>
    12     <target>уЎПбствП</target>
     13    <target>спецОальМые вПзЌПжМПстО</target>
    1314</phrase>
    1415<phrase>
     
    7172</phrase>
    7273<phrase>
    73     <source>Back</source>
    74     <target>НазаЎ</target>
    75 </phrase>
    76 <phrase>
    7774    <source>boxed edit</source>
    7875    <target>ПкМП реЎактОрПваМОя</target>
     
    120117<phrase>
    121118    <source>Close button</source>
    122     <target>кМПпка закрытОя</target>
     119    <target>КМПпка закрытОя</target>
    123120</phrase>
    124121<phrase>
    125122    <source>collapse</source>
    126     <target>краÑ
    127 </target>
     123    <target>сверМуть</target>
    128124</phrase>
    129125<phrase>
     
    206202    <source>disjoint selection</source>
    207203    <target>разЎелОть выбраММые элеЌеМты</target>
    208 </phrase>
    209 <phrase>
    210     <source>dock</source>
    211     <target>ЎПк</target>
    212204</phrase>
    213205<phrase>
     
    262254<phrase>
    263255    <source>expand</source>
    264     <target>расшОрять</target>
     256    <target>разверМуть</target>
    265257</phrase>
    266258<phrase>
     
    290282<phrase>
    291283    <source>Find Next</source>
    292     <target>ПрПЎПлжОть пПОск</target>
     284    <target>НайтО Ўалее</target>
    293285</phrase>
    294286<phrase>
    295287    <source>Find What</source>
    296     <target>ППОск</target>
     288    <target>Искать</target>
    297289</phrase>
    298290<phrase>
    299291    <source>folder</source>
    300     <target>каталПг</target>
     292    <target>папка</target>
    301293</phrase>
    302294<phrase>
     
    310302<phrase>
    311303    <source>font style</source>
    312     <target>стОль шрОфта</target>
     304    <target>МачертаМОе</target>
    313305</phrase>
    314306<phrase>
     
    354346</phrase>
    355347<phrase>
    356     <source>icon</source>
    357     <target>пОктПграЌЌа</target>
     348    <source>Icon</source>
     349    <target>ЗМачПк</target>
    358350</phrase>
    359351<phrase>
     
    391383<phrase>
    392384    <source>landscape</source>
    393     <target>альбПЌ</target>
     385    <target>альбПЌМая</target>
    394386</phrase>
    395387<phrase>
     
    411403<phrase>
    412404    <source>list view</source>
    413     <target>ЎревПвОЎМый спОсПк</target>
     405    <target>спОсПк</target>
    414406</phrase>
    415407<phrase>
     
    520512<phrase>
    521513    <source>OK</source>
    522     <target>OK</target>
     514    <target>ОК</target>
    523515</phrase>
    524516<phrase>
     
    533525<phrase>
    534526    <source>OLE embedded object</source>
    535     <target>вМеЎреММый OLE-Пбъект</target>
     527    <target>вМеЎрёММый OLE-Пбъект</target>
    536528</phrase>
    537529<phrase>
     
    541533<phrase>
    542534    <source>OLE nondefault drag and drop</source>
    543     <target>преЎПпреЎелеММый OLE-ЌеÑ
     535    <target>преЎПпреЎелёММый OLE-ЌеÑ
    544536аМОзЌ</target>
    545537</phrase>
     
    566558<phrase>
    567559    <source>Page Setup</source>
    568     <target>шаг устаМПвкО</target>
     560    <target>ПараЌетры страМОцы</target>
    569561</phrase>
    570562<phrase>
     
    634626<phrase>
    635627    <source>portrait</source>
    636     <target>пПртрет</target>
     628    <target>кМОжМая</target>
    637629</phrase>
    638630<phrase>
    639631    <source>press</source>
    640     <target>МажОЌать</target>
     632    <target>Мажать</target>
    641633</phrase>
    642634<phrase>
     
    769761<phrase>
    770762    <source>secondary window</source>
    771     <target>пПЎчОМеММПе ПкМП</target>
     763    <target>пПЎчОМёММПе ПкМП</target>
    772764</phrase>
    773765<phrase>
     
    777769<phrase>
    778770    <source>Select All</source>
    779     <target>ВыЎелОть все</target>
     771    <target>ВыЎелОть всё</target>
    780772</phrase>
    781773<phrase>
     
    873865<phrase>
    874866    <source>status bar</source>
    875     <target>статусМая стрПка</target>
     867    <target>стрПка сПстПяМОя</target>
    876868</phrase>
    877869<phrase>
    878870    <source>Stop</source>
    879     <target>СтПп</target>
     871    <target>ОстаМПвОть</target>
    880872</phrase>
    881873<phrase>
     
    909901<phrase>
    910902    <source>toggle key</source>
    911     <target>кМПпка-выключатель</target>
     903    <target>кМПпка-переключатель</target>
    912904</phrase>
    913905<phrase>
     
    916908</phrase>
    917909<phrase>
    918     <source>tooltip</source>
    919     <target>всплывающая пПЎсказка</target>
    920 </phrase>
    921 <phrase>
    922910    <source>tree view control</source>
    923911    <target>ЎревПвОЎМый спОсПк</target>
     
    991979    <target>Да</target>
    992980</phrase>
     981<phrase>
     982    <source>No</source>
     983    <target>Нет</target>
     984</phrase>
     985<phrase>
     986    <source>Options</source>
     987    <target>ПараЌетры</target>
     988</phrase>
     989<phrase>
     990    <source>directory</source>
     991    <target>каталПг</target>
     992</phrase>
     993<phrase>
     994    <source>Finish</source>
     995    <target>ЗавершОть</target>
     996</phrase>
     997<phrase>
     998    <source>Continue</source>
     999    <target>ПрПЎПлжОть</target>
     1000</phrase>
     1001<phrase>
     1002    <source>advanced</source>
     1003    <target>расшОреММый</target>
     1004</phrase>
     1005<phrase>
     1006    <source>layout</source>
     1007    <target>кПЌпПМПвка</target>
     1008</phrase>
     1009<phrase>
     1010    <source>layout</source>
     1011    <target>кПЌпПМПвщОк</target>
     1012</phrase>
     1013<phrase>
     1014    <source>plugin</source>
     1015    <target>ЌПЎуль</target>
     1016</phrase>
     1017<phrase>
     1018    <source>script</source>
     1019    <target>сцеМарОй</target>
     1020</phrase>
     1021<phrase>
     1022    <source>spacer</source>
     1023    <target>разЎелОтель</target>
     1024</phrase>
     1025<phrase>
     1026    <source>tabbar</source>
     1027    <target>паМель вклаЎПк</target>
     1028</phrase>
     1029<phrase>
     1030    <source>whitespace</source>
     1031    <target>сОЌвПл прПбела</target>
     1032</phrase>
     1033<phrase>
     1034    <source>Forward</source>
     1035    <target>ВперёЎ</target>
     1036</phrase>
     1037<phrase>
     1038    <source>Back</source>
     1039    <target>НазаЎ</target>
     1040</phrase>
     1041<phrase>
     1042    <source>Search wrapped</source>
     1043    <target>ППОск с Мачала</target>
     1044</phrase>
     1045<phrase>
     1046    <source>OK</source>
     1047    <target>Закрыть</target>
     1048</phrase>
     1049<phrase>
     1050    <source>Match case</source>
     1051    <target>С учётПЌ регОстра</target>
     1052</phrase>
     1053<phrase>
     1054    <source>Case Sensitive</source>
     1055    <target>УчОтывать регОстр</target>
     1056</phrase>
     1057<phrase>
     1058    <source>Whole words</source>
     1059    <target>СлПва целОкПЌ</target>
     1060</phrase>
     1061<phrase>
     1062    <source>Find Next</source>
     1063    <target>НайтО слеЎующее</target>
     1064</phrase>
     1065<phrase>
     1066    <source>Find Previous</source>
     1067    <target>НайтО преЎыЎущее</target>
     1068</phrase>
     1069<phrase>
     1070    <source>Case Sensitive</source>
     1071    <target>УчОтывать регОстр сОЌвПлПв</target>
     1072</phrase>
     1073<phrase>
     1074    <source>Whole words only</source>
     1075    <target>ТПлькП слПва целОкПЌ</target>
     1076</phrase>
     1077<phrase>
     1078    <source>Subwindow</source>
     1079    <target>ДПчерМее ПкМП</target>
     1080</phrase>
     1081<phrase>
     1082    <source>Next</source>
     1083    <target>Далее</target>
     1084</phrase>
     1085<phrase>
     1086    <source>tree view</source>
     1087    <target>ЎревПвОЎМый спОсПк</target>
     1088</phrase>
     1089<phrase>
     1090    <source>ToolTip</source>
     1091    <target>ППЎсказка</target>
     1092</phrase>
     1093<phrase>
     1094    <source>Checkable</source>
     1095    <target>ПереключаеЌПе</target>
     1096</phrase>
     1097<phrase>
     1098    <source>Style</source>
     1099    <target>НачертаМОе</target>
     1100</phrase>
     1101<phrase>
     1102    <source>Point size</source>
     1103    <target>РазЌер</target>
     1104</phrase>
     1105<phrase>
     1106    <source>Family</source>
     1107    <target>КрОфт</target>
     1108</phrase>
     1109<phrase>
     1110    <source>Writing system</source>
     1111    <target>СОстеЌа пОсьЌа</target>
     1112</phrase>
     1113<phrase>
     1114    <source>OK</source>
     1115    <target>УЎалОть</target>
     1116</phrase>
     1117<phrase>
     1118    <source>Style</source>
     1119    <target>СтОль</target>
     1120</phrase>
     1121<phrase>
     1122    <source>Edit</source>
     1123    <target>ИзЌеМОть</target>
     1124</phrase>
     1125<phrase>
     1126    <source>Invalid</source>
     1127    <target>НекПрректМый</target>
     1128</phrase>
     1129<phrase>
     1130    <source>Invalid</source>
     1131    <target>НекПрректМая</target>
     1132</phrase>
     1133<phrase>
     1134    <source>Invalid</source>
     1135    <target>НекПрректМПе</target>
     1136</phrase>
     1137<phrase>
     1138    <source>tag</source>
     1139    <target>тэг</target>
     1140</phrase>
     1141<phrase>
     1142    <source>tab order</source>
     1143    <target>пПряЎПк ПбÑ
     1144ПЎа</target>
     1145</phrase>
     1146<phrase>
     1147    <source>Ascending</source>
     1148    <target>ПП вПзрастаМОю</target>
     1149</phrase>
     1150<phrase>
     1151    <source>Descending</source>
     1152    <target>ПП убываМОю</target>
     1153</phrase>
     1154<phrase>
     1155    <source>Reset</source>
     1156    <target>СбрПсОть</target>
     1157</phrase>
     1158<phrase>
     1159    <source>Sort order</source>
     1160    <target>ППряЎПк сПртОрПвкО</target>
     1161</phrase>
     1162<phrase>
     1163    <source>Appearance</source>
     1164    <target>ВМешМОй вОЎ</target>
     1165</phrase>
     1166<phrase>
     1167    <source>View</source>
     1168    <target>ПрПсЌПтр</target>
     1169</phrase>
     1170<phrase>
     1171    <source>Actions</source>
     1172    <target>ДействОя</target>
     1173</phrase>
     1174<phrase>
     1175    <source>Table of Contents</source>
     1176    <target>ОглавлеМОе</target>
     1177</phrase>
    9931178</QPH>
  • trunk/tools/linguist/qdoc.conf

    r2 r561  
    44OUTPUTDIR       = $QTDIR/tools/linguist/doc/html
    55BASE            = file:$QTDIR/tools/linguist/doc/html/
    6 COMPANY         = Trolltech
     6COMPANY         = Nokia Corporation and/or its subsidiary(-ies)
    77PRODUCT         = Qt Linguist
    88VERSIONSYM      = QT_VERSION_STR
  • trunk/tools/linguist/shared/abstractproitemvisitor.h

    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 Qt Linguist 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**
     
    5050{
    5151    virtual ~AbstractProItemVisitor() {}
    52     virtual bool visitBeginProBlock(ProBlock *block) = 0;
    53     virtual bool visitEndProBlock(ProBlock *block) = 0;
    5452
    55     virtual bool visitBeginProVariable(ProVariable *variable) = 0;
    56     virtual bool visitEndProVariable(ProVariable *variable) = 0;
     53    virtual ProItem::ProItemReturn visitBeginProBlock(ProBlock *block) = 0;
     54    virtual void visitEndProBlock(ProBlock *block) = 0;
    5755
    58     virtual bool visitBeginProFile(ProFile *value) = 0;
    59     virtual bool visitEndProFile(ProFile *value) = 0;
     56    virtual ProItem::ProItemReturn visitProLoopIteration() = 0;
     57    virtual void visitProLoopCleanup() = 0;
    6058
    61     virtual bool visitProValue(ProValue *value) = 0;
    62     virtual bool visitProFunction(ProFunction *function) = 0;
    63     virtual bool visitProOperator(ProOperator *function) = 0;
    64     virtual bool visitProCondition(ProCondition *function) = 0;
     59    virtual void visitBeginProVariable(ProVariable *variable) = 0;
     60    virtual void visitEndProVariable(ProVariable *variable) = 0;
     61
     62    virtual ProItem::ProItemReturn visitBeginProFile(ProFile *value) = 0;
     63    virtual ProItem::ProItemReturn visitEndProFile(ProFile *value) = 0;
     64
     65    virtual void visitProValue(ProValue *value) = 0;
     66    virtual ProItem::ProItemReturn visitProFunction(ProFunction *function) = 0;
     67    virtual void visitProOperator(ProOperator *function) = 0;
     68    virtual void visitProCondition(ProCondition *function) = 0;
    6569};
    6670
  • trunk/tools/linguist/shared/formats.pri

    r2 r561  
    2020    $$PWD/po.cpp \
    2121    $$PWD/ts.cpp \
    22     $$PWD/ui.cpp \
    23     $$PWD/cpp.cpp \
    24     $$PWD/java.cpp \
    25     $$PWD/qscript.cpp \
    2622    $$PWD/xliff.cpp
  • trunk/tools/linguist/shared/numerus.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 Qt Linguist 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**
     
    4242#include "translator.h"
    4343
    44 #include <QtCore/QCoreApplication>
    4544#include <QtCore/QByteArray>
    4645#include <QtCore/QDebug>
     
    6160    { Q_MOD_10 | Q_EQ, 1, Q_AND, Q_MOD_100 | Q_NEQ, 11, Q_NEWRULE,
    6261      Q_NEQ, 0 };
     62static const uchar icelandicRules[] =
     63    { Q_MOD_10 | Q_EQ, 1, Q_AND, Q_MOD_100 | Q_NEQ, 11 };
    6364static const uchar irishStyleRules[] =
    6465    { Q_EQ, 1, Q_NEWRULE,
    6566      Q_EQ, 2 };
    66 static const uchar czechRules[] =
    67     { Q_MOD_100 | Q_EQ, 1, Q_NEWRULE,
    68       Q_MOD_100 | Q_BETWEEN, 2, 4 };
    6967static const uchar slovakRules[] =
    7068    { Q_EQ, 1, Q_NEWRULE,
     
    7573static const uchar lithuanianRules[] =
    7674    { Q_MOD_10 | Q_EQ, 1, Q_AND, Q_MOD_100 | Q_NEQ, 11, Q_NEWRULE,
    77       Q_MOD_10 | Q_EQ, 2, Q_AND, Q_MOD_100 | Q_NOT_BETWEEN, 10, 19 };
     75      Q_MOD_10 | Q_NEQ, 0, Q_AND, Q_MOD_100 | Q_NOT_BETWEEN, 10, 19 };
    7876static const uchar russianStyleRules[] =
    7977    { Q_MOD_10 | Q_EQ, 1, Q_AND, Q_MOD_100 | Q_NEQ, 11, Q_NEWRULE,
     
    103101      Q_EQ, 2, Q_NEWRULE,
    104102      Q_MOD_100 | Q_BETWEEN, 3, 10, Q_NEWRULE,
    105       Q_MOD_100 | Q_NEQ, 0 };
     103      Q_MOD_100 | Q_NOT | Q_BETWEEN, 0, 2 };
     104static const uchar tagalogRules[] =
     105    { Q_LEQ, 1, Q_NEWRULE,
     106      Q_MOD_10 | Q_EQ, 4, Q_OR, Q_MOD_10 | Q_EQ, 6, Q_OR, Q_MOD_10 | Q_EQ, 9 };
     107static const uchar catalanRules[] =
     108    { Q_EQ, 1, Q_NEWRULE,
     109      Q_LEAD_1000 | Q_EQ, 11 };
    106110
    107111static const char * const japaneseStyleForms[] = { "Universal Form", 0 };
    108112static const char * const englishStyleForms[] = { "Singular", "Plural", 0 };
    109113static const char * const frenchStyleForms[] = { "Singular", "Plural", 0 };
     114static const char * const icelandicForms[] = { "Singular", "Plural", 0 };
    110115static const char * const latvianForms[] = { "Singular", "Plural", "Nullar", 0 };
    111116static const char * const irishStyleForms[] = { "Singular", "Dual", "Plural", 0 };
    112 static const char * const czechForms[] = { "Singular", "Dual", "Plural", 0 };
    113 static const char * const slovakForms[] = { "Singular", "Dual", "Plural", 0 };
     117static const char * const slovakForms[] = { "Singular", "Paucal", "Plural", 0 };
    114118static const char * const macedonianForms[] = { "Singular", "Dual", "Plural", 0 };
    115 static const char * const lithuanianForms[] = { "Singular", "Dual", "Plural", 0 };
     119static const char * const lithuanianForms[] = { "Singular", "Paucal", "Plural", 0 };
    116120static const char * const russianStyleForms[] = { "Singular", "Dual", "Plural", 0 };
    117121static const char * const polishForms[] = { "Singular", "Paucal", "Plural", 0 };
    118 static const char * const romanianForms[] =
    119     { "Singular", "Plural Form for 2 to 19", "Plural", 0 };
     122static const char * const romanianForms[] = { "Singular", "Paucal", "Plural", 0 };
    120123static const char * const slovenianForms[] = { "Singular", "Dual", "Trial", "Plural", 0 };
    121124static const char * const malteseForms[] =
    122     { "Singular", "Plural Form for 2 to 10", "Plural Form for 11 to 19", "Plural", 0 };
     125    { "Singular", "Paucal", "Greater Paucal", "Plural", 0 };
    123126static const char * const welshForms[] =
    124127    { "Nullar", "Singular", "Dual", "Sexal", "Plural", 0 };
    125128static const char * const arabicForms[] =
    126     { "Nullar", "Singular", "Dual", "Minority Plural", "Plural", "Plural Form for 100, 200, ...", 0 };
     129    { "Nullar", "Singular", "Dual", "Minority Plural", "Plural", "Plural (100-102, ...)", 0 };
     130static const char * const tagalogForms[] =
     131    { "Singular", "Plural (consonant-ended)", "Plural (vowel-ended)", 0 };
     132static const char * const catalanForms[] = { "Singular", "Undecal (11)", "Plural", 0 };
    127133
    128134#define EOL QLocale::C
     
    148154    QLocale::Thai,
    149155    QLocale::Tibetan,
     156    QLocale::Turkish,
    150157    QLocale::Vietnamese,
    151158    QLocale::Yoruba,
     
    170177    QLocale::Bulgarian,
    171178    QLocale::Cambodian,
    172     QLocale::Catalan,
    173179    QLocale::Cornish,
    174180    QLocale::Corsican,
     
    191197    QLocale::Hebrew,
    192198    QLocale::Hindi,
    193     QLocale::Icelandic,
    194199    QLocale::Interlingua,
    195200    QLocale::Interlingue,
     
    232237    QLocale::Swahili,
    233238    QLocale::Swedish,
    234     QLocale::Tagalog,
    235239    QLocale::Tajik,
    236240    QLocale::Tamil,
     
    239243    QLocale::TongaLanguage,
    240244    QLocale::Tsonga,
    241     QLocale::Turkish,
    242245    QLocale::Turkmen,
    243246    QLocale::Twi,
    244247    QLocale::Uigur,
     248    QLocale::Urdu,
    245249    QLocale::Uzbek,
    246250    QLocale::Volapuk,
     
    262266};
    263267static const QLocale::Language latvianLanguage[] = { QLocale::Latvian, EOL };
     268static const QLocale::Language icelandicLanguage[] = { QLocale::Icelandic, EOL };
    264269static const QLocale::Language irishStyleLanguages[] = {
    265270    QLocale::Divehi,
     
    275280    EOL
    276281};
    277 static const QLocale::Language czechLanguage[] = { QLocale::Czech, EOL };
    278 static const QLocale::Language slovakLanguage[] = { QLocale::Slovak, EOL };
     282static const QLocale::Language slovakLanguages[] = { QLocale::Slovak, QLocale::Czech, EOL };
    279283static const QLocale::Language macedonianLanguage[] = { QLocale::Macedonian, EOL };
    280284static const QLocale::Language lithuanianLanguage[] = { QLocale::Lithuanian, EOL };
     
    299303static const QLocale::Language welshLanguage[] = { QLocale::Welsh, EOL };
    300304static const QLocale::Language arabicLanguage[] = { QLocale::Arabic, EOL };
     305static const QLocale::Language tagalogLanguage[] = { QLocale::Tagalog, EOL };
     306static const QLocale::Language catalanLanguage[] = { QLocale::Catalan, EOL };
    301307
    302308static const QLocale::Country frenchStyleCountries[] = {
     
    321327      frenchStyleCountries },
    322328    { latvianRules, sizeof(latvianRules), latvianForms, latvianLanguage, 0 },
     329    { icelandicRules, sizeof(icelandicRules), icelandicForms, icelandicLanguage, 0 },
    323330    { irishStyleRules, sizeof(irishStyleRules), irishStyleForms, irishStyleLanguages, 0 },
    324     { czechRules, sizeof(czechRules), czechForms, czechLanguage, 0 },
    325     { slovakRules, sizeof(slovakRules), slovakForms, slovakLanguage, 0 },
     331    { slovakRules, sizeof(slovakRules), slovakForms, slovakLanguages, 0 },
    326332    { macedonianRules, sizeof(macedonianRules), macedonianForms, macedonianLanguage, 0 },
    327333    { lithuanianRules, sizeof(lithuanianRules), lithuanianForms, lithuanianLanguage, 0 },
     
    332338    { malteseRules, sizeof(malteseRules), malteseForms, malteseLanguage, 0 },
    333339    { welshRules, sizeof(welshRules), welshForms, welshLanguage, 0 },
    334     { arabicRules, sizeof(arabicRules), arabicForms, arabicLanguage, 0 }
     340    { arabicRules, sizeof(arabicRules), arabicForms, arabicLanguage, 0 },
     341    { tagalogRules, sizeof(tagalogRules), tagalogForms, tagalogLanguage, 0 },
     342    { catalanRules, sizeof(catalanRules), catalanForms, catalanLanguage, 0 }
    335343};
    336344
  • trunk/tools/linguist/shared/po.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 Qt Linguist 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**
     
    360360    const QChar newline = QLatin1Char('\n');
    361361    QTextStream in(&dev);
     362    in.setCodec(cd.m_codecForSource.isEmpty() ? QByteArray("UTF-8") : cd.m_codecForSource);
    362363    bool error = false;
    363364
     
    396397            while (true) {
    397398                int idx = line.indexOf(QLatin1Char(' '), prefix.length());
    398                 item.msgStr.append(slurpEscapedString(lines, l, idx, prefix, cd));
     399                QString str = slurpEscapedString(lines, l, idx, prefix, cd);
     400                str.replace(QChar(Translator::TextVariantSeparator),
     401                            QChar(Translator::BinaryVariantSeparator));
     402                item.msgStr.append(str);
    399403                if (l + 1 >= lines.size() || !isTranslationLine(lines.at(l + 1)))
    400404                    break;
     
    552556    bool ok = true;
    553557    QTextStream out(&dev);
    554     //qDebug() << "OUT CODEC: " << out.codec()->name();
     558    out.setCodec(cd.m_outputCodec.isEmpty() ? QByteArray("UTF-8") : cd.m_outputCodec);
    555559
    556560    bool first = true;
     
    634638                plural = msg.sourceText();
    635639            out << poEscapedString(prefix, QLatin1String("msgid_plural"), noWrap, plural);
    636             QStringList translations = translator.normalizedTranslations(msg, cd, &ok);
     640            const QStringList &translations = msg.translations();
    637641            for (int i = 0; i != translations.size(); ++i) {
     642                QString str = translations.at(i);
     643                str.replace(QChar(Translator::BinaryVariantSeparator),
     644                            QChar(Translator::TextVariantSeparator));
    638645                out << poEscapedString(prefix, QString::fromLatin1("msgstr[%1]").arg(i), noWrap,
    639                                        translations.at(i));
     646                                       str);
    640647            }
    641648        }
  • trunk/tools/linguist/shared/profileevaluator.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 Qt Linguist 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**
     
    4545
    4646#include <QtCore/QByteArray>
     47#include <QtCore/QDateTime>
    4748#include <QtCore/QDebug>
    4849#include <QtCore/QDir>
     
    5758#include <QtCore/QTextStream>
    5859
     60#ifdef Q_OS_UNIX
     61#include <unistd.h>
     62#include <sys/utsname.h>
     63#else
     64#include <Windows.h>
     65#endif
     66#include <stdio.h>
     67#include <stdlib.h>
     68
    5969#ifdef Q_OS_WIN32
    6070#define QT_POPEN _popen
     71#define QT_PCLOSE _pclose
    6172#else
    6273#define QT_POPEN popen
     74#define QT_PCLOSE pclose
    6375#endif
    6476
    6577QT_BEGIN_NAMESPACE
     78
     79///////////////////////////////////////////////////////////////////////
     80//
     81// Option
     82//
     83///////////////////////////////////////////////////////////////////////
     84
     85QString
     86Option::fixString(QString string, uchar flags)
     87{
     88    // XXX Ripped out caching, so this will be slow. Should not matter for current uses.
     89
     90    //fix the environment variables
     91    if (flags & Option::FixEnvVars) {
     92        int rep;
     93        QRegExp reg_variableName(QLatin1String("\\$\\(.*\\)"));
     94        reg_variableName.setMinimal(true);
     95        while ((rep = reg_variableName.indexIn(string)) != -1)
     96            string.replace(rep, reg_variableName.matchedLength(),
     97                           QString::fromLocal8Bit(qgetenv(string.mid(rep + 2, reg_variableName.matchedLength() - 3).toLatin1().constData()).constData()));
     98    }
     99
     100    //canonicalize it (and treat as a path)
     101    if (flags & Option::FixPathCanonicalize) {
     102#if 0
     103        string = QFileInfo(string).canonicalFilePath();
     104#endif
     105        string = QDir::cleanPath(string);
     106    }
     107
     108    if (string.length() > 2 && string[0].isLetter() && string[1] == QLatin1Char(':'))
     109        string[0] = string[0].toLower();
     110
     111    //fix separators
     112    Q_ASSERT(!((flags & Option::FixPathToLocalSeparators) && (flags & Option::FixPathToTargetSeparators)));
     113    if (flags & Option::FixPathToLocalSeparators) {
     114#if defined(Q_OS_WIN32)
     115        string = string.replace(QLatin1Char('/'), QLatin1Char('\\'));
     116#else
     117        string = string.replace(QLatin1Char('\\'), QLatin1Char('/'));
     118#endif
     119    } else if (flags & Option::FixPathToTargetSeparators) {
     120        string = string.replace(QLatin1Char('/'), Option::dir_sep)
     121                       .replace(QLatin1Char('\\'), Option::dir_sep);
     122    }
     123
     124    if ((string.startsWith(QLatin1Char('"')) && string.endsWith(QLatin1Char('"'))) ||
     125        (string.startsWith(QLatin1Char('\'')) && string.endsWith(QLatin1Char('\''))))
     126        string = string.mid(1, string.length() - 2);
     127
     128    return string;
     129}
    66130
    67131///////////////////////////////////////////////////////////////////////
     
    75139public:
    76140    Private(ProFileEvaluator *q_);
     141
     142    ProFileEvaluator *q;
     143    int m_lineNo;                                   // Error reporting
     144    bool m_verbose;
     145
     146    /////////////// Reading pro file
    77147
    78148    bool read(ProFile *pro);
     
    88158    void finalizeBlock();
    89159
    90     // implementation of AbstractProItemVisitor
    91     bool visitBeginProBlock(ProBlock *block);
    92     bool visitEndProBlock(ProBlock *block);
    93     bool visitBeginProVariable(ProVariable *variable);
    94     bool visitEndProVariable(ProVariable *variable);
    95     bool visitBeginProFile(ProFile *value);
    96     bool visitEndProFile(ProFile *value);
    97     bool visitProValue(ProValue *value);
    98     bool visitProFunction(ProFunction *function);
    99     bool visitProOperator(ProOperator *oper);
    100     bool visitProCondition(ProCondition *condition);
    101 
    102     QStringList valuesDirect(const QString &variableName) const { return m_valuemap[variableName]; }
    103     QStringList values(const QString &variableName) const;
    104     QStringList values(const QString &variableName, const ProFile *pro) const;
    105     QString propertyValue(const QString &val) const;
    106 
    107     bool isActiveConfig(const QString &config, bool regex = false);
    108     QStringList expandPattern(const QString &pattern);
    109     void expandPatternHelper(const QString &relName, const QString &absName,
    110         QStringList &sources_out);
    111     QStringList expandVariableReferences(const QString &value);
    112     QStringList evaluateExpandFunction(const QString &function, const QString &arguments);
    113     QString format(const char *format) const;
    114 
    115     QString currentFileName() const;
    116     QString getcwd() const;
    117     ProFile *currentProFile() const;
    118 
    119     bool evaluateConditionalFunction(const QString &function, const QString &arguments, bool *result);
    120     bool evaluateFile(const QString &fileName, bool *result);
    121     bool evaluateFeatureFile(const QString &fileName, bool *result);
    122 
    123     QStringList qmakeFeaturePaths();
    124 
    125     ProFileEvaluator *q;
    126 
    127160    QStack<ProBlock *> m_blockstack;
    128161    ProBlock *m_block;
     
    133166    bool m_syntaxError;
    134167    bool m_contNextLine;
    135     bool m_condition;
    136     bool m_invertNext;
     168    bool m_inQuote;
     169    int m_parens;
     170
     171    /////////////// Evaluating pro file contents
     172
     173    // implementation of AbstractProItemVisitor
     174    ProItem::ProItemReturn visitBeginProBlock(ProBlock *block);
     175    void visitEndProBlock(ProBlock *block);
     176    ProItem::ProItemReturn visitProLoopIteration();
     177    void visitProLoopCleanup();
     178    void visitBeginProVariable(ProVariable *variable);
     179    void visitEndProVariable(ProVariable *variable);
     180    ProItem::ProItemReturn visitBeginProFile(ProFile *value);
     181    ProItem::ProItemReturn visitEndProFile(ProFile *value);
     182    void visitProValue(ProValue *value);
     183    ProItem::ProItemReturn visitProFunction(ProFunction *function);
     184    void visitProOperator(ProOperator *oper);
     185    void visitProCondition(ProCondition *condition);
     186
     187    QStringList valuesDirect(const QString &variableName) const { return m_valuemap[variableName]; }
     188    QStringList values(const QString &variableName) const;
     189    QStringList values(const QString &variableName, const ProFile *pro) const;
     190    QStringList values(const QString &variableName, const QHash<QString, QStringList> &place,
     191                       const ProFile *pro) const;
     192    QString propertyValue(const QString &val) const;
     193
     194    bool isActiveConfig(const QString &config, bool regex = false);
     195    QStringList expandVariableReferences(const QString &value);
     196    void doVariableReplace(QString *str);
     197    QStringList evaluateExpandFunction(const QString &function, const QString &arguments);
     198    QString format(const char *format) const;
     199
     200    QString currentFileName() const;
     201    QString currentDirectory() const;
     202    ProFile *currentProFile() const;
     203
     204    ProItem::ProItemReturn evaluateConditionalFunction(const QString &function, const QString &arguments);
     205    bool evaluateFile(const QString &fileName);
     206    bool evaluateFeatureFile(const QString &fileName);
     207
     208    static inline ProItem::ProItemReturn returnBool(bool b)
     209        { return b ? ProItem::ReturnTrue : ProItem::ReturnFalse; }
     210
     211    QStringList evaluateFunction(ProBlock *funcPtr, const QStringList &argumentsList, bool *ok);
     212
     213    QStringList qmakeFeaturePaths();
     214
     215    struct State {
     216        bool condition;
     217        bool prevCondition;
     218    } m_sts;
     219    bool m_invertNext; // Short-lived, so not in State
     220    int m_skipLevel;
     221    bool m_cumulative;
     222    bool m_isFirstVariableValue;
    137223    QString m_lastVarName;
    138224    ProVariable::VariableOperator m_variableOperator;
    139     int m_lineNo;                                   // Error reporting
     225    QString m_origfile;
    140226    QString m_oldPath;                              // To restore the current path to the path
    141227    QStack<ProFile*> m_profileStack;                // To handle 'include(a.pri), so we can track back to 'a.pro' when finished with 'a.pri'
     228    struct ProLoop {
     229        QString variable;
     230        QStringList oldVarVal;
     231        QStringList list;
     232        int index;
     233        bool infinite;
     234    };
     235    QStack<ProLoop> m_loopStack;
     236
     237    // we need the following two variables for handling
     238    // CONFIG = foo bar $$CONFIG
     239    QHash<QString, QStringList> m_tempValuemap;         // used while evaluating (variable operator value1 value2 ...)
     240    QHash<const ProFile*, QHash<QString, QStringList> > m_tempFilevaluemap; // used while evaluating (variable operator value1 value2 ...)
    142241
    143242    QHash<QString, QStringList> m_valuemap;         // VariableName must be us-ascii, the content however can be non-us-ascii.
    144243    QHash<const ProFile*, QHash<QString, QStringList> > m_filevaluemap; // Variables per include file
    145244    QHash<QString, QString> m_properties;
    146     QString m_origfile;
     245    QString m_outputDir;
     246
     247    bool m_definingTest;
     248    QString m_definingFunc;
     249    QHash<QString, ProBlock *> m_testFunctions;
     250    QHash<QString, ProBlock *> m_replaceFunctions;
     251    QStringList m_returnValue;
     252    QStack<QHash<QString, QStringList> > m_valuemapStack;
     253    QStack<QHash<const ProFile*, QHash<QString, QStringList> > > m_filevaluemapStack;
    147254
    148255    int m_prevLineNo;                               // Checking whether we're assigning the same TARGET
    149256    ProFile *m_prevProFile;                         // See m_prevLineNo
    150 
    151     bool m_verbose;
    152257};
     258
     259Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::State, Q_PRIMITIVE_TYPE);
     260Q_DECLARE_TYPEINFO(ProFileEvaluator::Private::ProLoop, Q_MOVABLE_TYPE);
    153261
    154262ProFileEvaluator::Private::Private(ProFileEvaluator *q_)
    155263  : q(q_)
    156264{
     265    // Global parser state
    157266    m_prevLineNo = 0;
    158267    m_prevProFile = 0;
     268
     269    // Configuration, more or less
    159270    m_verbose = true;
     271    m_cumulative = true;
     272
     273    // Evaluator state
     274    m_sts.condition = false;
     275    m_sts.prevCondition = false;
     276    m_invertNext = false;
     277    m_skipLevel = 0;
     278    m_isFirstVariableValue = true;
     279    m_definingFunc.clear();
    160280}
    161281
     
    168288    }
    169289
     290    // Parser state
    170291    m_block = 0;
    171292    m_commentItem = 0;
     293    m_inQuote = false;
     294    m_parens = 0;
    172295    m_contNextLine = false;
    173296    m_syntaxError = false;
     
    193316        return false;
    194317
    195     ushort quote = 0;
    196     int parens = 0;
    197     bool contNextLine = false;
     318    int parens = m_parens;
     319    bool inQuote = m_inQuote;
     320    bool escaped = false;
    198321    QString line = line0.simplified();
    199322
    200323    for (int i = 0; !m_syntaxError && i < line.length(); ++i) {
    201324        ushort c = line.at(i).unicode();
    202         if (quote && c == quote)
    203             quote = 0;
    204         else if (c == '(')
    205             ++parens;
    206         else if (c == ')')
    207             --parens;
    208         else if (c == '"' && (i == 0 || line.at(i - 1).unicode() != '\\'))
    209             quote = c;
    210         else if (!parens && !quote) {
    211             if (c == '#') {
    212                 insertComment(line.mid(i + 1));
    213                 contNextLine = m_contNextLine;
    214                 break;
    215             }
    216             if (c == '\\' && i >= line.count() - 1) {
    217                 updateItem();
    218                 contNextLine = true;
     325        if (c == '#') { // Yep - no escaping possible
     326            insertComment(line.mid(i + 1));
     327            escaped = m_contNextLine;
     328            break;
     329        }
     330        if (!escaped) {
     331            if (c == '\\') {
     332                escaped = true;
     333                m_proitem += c;
    219334                continue;
    220             }
    221             if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) {
    222                 if (c == ' ')
    223                     updateItem();
    224                 else
    225                     m_proitem += c;
     335            } else if (c == '"') {
     336                inQuote = !inQuote;
     337                m_proitem += c;
    226338                continue;
    227339            }
    228             if (c == ':') {
    229                 enterScope(false);
    230                 continue;
    231             }
    232             if (c == '{') {
    233                 enterScope(true);
    234                 continue;
    235             }
    236             if (c == '}') {
    237                 leaveScope();
    238                 continue;
    239             }
    240             if (c == '=') {
    241                 insertVariable(line, &i);
    242                 continue;
    243             }
    244             if (c == '|' || c == '!') {
    245                 insertOperator(c);
    246                 continue;
     340        } else {
     341            escaped = false;
     342        }
     343        if (!inQuote) {
     344            if (c == '(') {
     345                ++parens;
     346            } else if (c == ')') {
     347                --parens;
     348            } else if (!parens) {
     349                if (m_block && (m_block->blockKind() & ProBlock::VariableKind)) {
     350                    if (c == ' ')
     351                        updateItem();
     352                    else
     353                        m_proitem += c;
     354                    continue;
     355                }
     356                if (c == ':') {
     357                    enterScope(false);
     358                    continue;
     359                }
     360                if (c == '{') {
     361                    enterScope(true);
     362                    continue;
     363                }
     364                if (c == '}') {
     365                    leaveScope();
     366                    continue;
     367                }
     368                if (c == '=') {
     369                    insertVariable(line, &i);
     370                    continue;
     371                }
     372                if (c == '|' || c == '!') {
     373                    insertOperator(c);
     374                    continue;
     375                }
    247376            }
    248377        }
     
    250379        m_proitem += c;
    251380    }
    252     m_contNextLine = contNextLine;
    253 
    254     if (!m_syntaxError) {
     381    m_inQuote = inQuote;
     382    m_parens = parens;
     383    m_contNextLine = escaped;
     384    if (escaped) {
     385        m_proitem.chop(1);
    255386        updateItem();
    256         if (!m_contNextLine)
     387        return true;
     388    } else {
     389        if (!m_syntaxError) {
     390            updateItem();
    257391            finalizeBlock();
    258     }
    259     return !m_syntaxError;
     392            return true;
     393        }
     394        return false;
     395    }
    260396}
    261397
     
    276412    ProVariable::VariableOperator opkind;
    277413
     414    if (m_proitem.isEmpty()) // Line starting with '=', like a conflict marker
     415        return;
     416
    278417    switch (m_proitem.at(m_proitem.length() - 1).unicode()) {
    279418        case '+':
     
    450589
    451590
    452 bool ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block)
    453 {
    454     if (block->blockKind() == ProBlock::ScopeKind) {
    455         m_invertNext = false;
    456         m_condition = false;
    457     }
    458     return true;
    459 }
    460 
    461 bool ProFileEvaluator::Private::visitEndProBlock(ProBlock *block)
    462 {
    463     Q_UNUSED(block);
    464     return true;
    465 }
    466 
    467 bool ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable)
     591ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProBlock(ProBlock *block)
     592{
     593    if (block->blockKind() & ProBlock::ScopeContentsKind) {
     594        if (!m_definingFunc.isEmpty()) {
     595            if (!m_skipLevel || m_cumulative) {
     596                QHash<QString, ProBlock *> *hash =
     597                        (m_definingTest ? &m_testFunctions : &m_replaceFunctions);
     598                if (ProBlock *def = hash->value(m_definingFunc))
     599                    def->deref();
     600                hash->insert(m_definingFunc, block);
     601                block->ref();
     602                block->setBlockKind(block->blockKind() | ProBlock::FunctionBodyKind);
     603            }
     604            m_definingFunc.clear();
     605            return ProItem::ReturnSkip;
     606        } else if (!(block->blockKind() & ProBlock::FunctionBodyKind)) {
     607            if (!m_sts.condition)
     608                ++m_skipLevel;
     609            else
     610                Q_ASSERT(!m_skipLevel);
     611        }
     612    } else {
     613        if (!m_skipLevel) {
     614            if (m_sts.condition) {
     615                m_sts.prevCondition = true;
     616                m_sts.condition = false;
     617            }
     618        } else {
     619            Q_ASSERT(!m_sts.condition);
     620        }
     621    }
     622    return ProItem::ReturnTrue;
     623}
     624
     625void ProFileEvaluator::Private::visitEndProBlock(ProBlock *block)
     626{
     627    if ((block->blockKind() & ProBlock::ScopeContentsKind)
     628        && !(block->blockKind() & ProBlock::FunctionBodyKind)) {
     629        if (m_skipLevel) {
     630            Q_ASSERT(!m_sts.condition);
     631            --m_skipLevel;
     632        } else if (!(block->blockKind() & ProBlock::SingleLine)) {
     633            // Conditionals contained inside this block may have changed the state.
     634            // So we reset it here to make an else following us do the right thing.
     635            m_sts.condition = true;
     636        }
     637    }
     638}
     639
     640ProItem::ProItemReturn ProFileEvaluator::Private::visitProLoopIteration()
     641{
     642    ProLoop &loop = m_loopStack.top();
     643
     644    if (loop.infinite) {
     645        if (!loop.variable.isEmpty())
     646            m_valuemap[loop.variable] = QStringList(QString::number(loop.index++));
     647        if (loop.index > 1000) {
     648            q->errorMessage(format("ran into infinite loop (> 1000 iterations)."));
     649            return ProItem::ReturnFalse;
     650        }
     651    } else {
     652        QString val;
     653        do {
     654            if (loop.index >= loop.list.count())
     655                return ProItem::ReturnFalse;
     656            val = loop.list.at(loop.index++);
     657        } while (val.isEmpty()); // stupid, but qmake is like that
     658        m_valuemap[loop.variable] = QStringList(val);
     659    }
     660    return ProItem::ReturnTrue;
     661}
     662
     663void ProFileEvaluator::Private::visitProLoopCleanup()
     664{
     665    ProLoop &loop = m_loopStack.top();
     666    m_valuemap[loop.variable] = loop.oldVarVal;
     667    m_loopStack.pop_back();
     668}
     669
     670void ProFileEvaluator::Private::visitBeginProVariable(ProVariable *variable)
    468671{
    469672    m_lastVarName = variable->variable();
    470673    m_variableOperator = variable->variableOperator();
    471     return true;
    472 }
    473 
    474 bool ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable)
     674    m_isFirstVariableValue = true;
     675    m_tempValuemap = m_valuemap;
     676    m_tempFilevaluemap = m_filevaluemap;
     677}
     678
     679void ProFileEvaluator::Private::visitEndProVariable(ProVariable *variable)
    475680{
    476681    Q_UNUSED(variable);
     682    m_valuemap = m_tempValuemap;
     683    m_filevaluemap = m_tempFilevaluemap;
    477684    m_lastVarName.clear();
    478     return true;
    479 }
    480 
    481 bool ProFileEvaluator::Private::visitProOperator(ProOperator *oper)
     685}
     686
     687void ProFileEvaluator::Private::visitProOperator(ProOperator *oper)
    482688{
    483689    m_invertNext = (oper->operatorKind() == ProOperator::NotOperator);
    484     return true;
    485 }
    486 
    487 bool ProFileEvaluator::Private::visitProCondition(ProCondition *cond)
    488 {
    489     if (!m_condition) {
    490         if (m_invertNext)
    491             m_condition |= !isActiveConfig(cond->text(), true);
    492         else
    493             m_condition |= isActiveConfig(cond->text(), true);
    494     }
    495     return true;
    496 }
    497 
    498 bool ProFileEvaluator::Private::visitBeginProFile(ProFile * pro)
     690}
     691
     692void ProFileEvaluator::Private::visitProCondition(ProCondition *cond)
     693{
     694    if (!m_skipLevel) {
     695        if (!cond->text().compare(QLatin1String("else"), Qt::CaseInsensitive)) {
     696            m_sts.condition = !m_sts.prevCondition;
     697        } else {
     698            m_sts.prevCondition = false;
     699            if (!m_sts.condition && isActiveConfig(cond->text(), true) ^ m_invertNext)
     700                m_sts.condition = true;
     701        }
     702    }
     703    m_invertNext = false;
     704}
     705
     706ProItem::ProItemReturn ProFileEvaluator::Private::visitBeginProFile(ProFile * pro)
    499707{
    500708    PRE(pro);
    501     bool ok = true;
    502709    m_lineNo = pro->lineNumber();
     710    if (m_origfile.isEmpty())
     711        m_origfile = pro->fileName();
    503712    if (m_oldPath.isEmpty()) {
    504713        // change the working directory for the initial profile we visit, since
    505714        // that is *the* profile. All the other times we reach this function will be due to
    506715        // include(file) or load(file)
     716
    507717        m_oldPath = QDir::currentPath();
     718
    508719        m_profileStack.push(pro);
    509         ok = QDir::setCurrent(pro->directoryName());
    510     }
    511 
    512     if (m_origfile.isEmpty())
    513         m_origfile = pro->fileName();
    514 
    515     return ok;
    516 }
    517 
    518 bool ProFileEvaluator::Private::visitEndProFile(ProFile * pro)
     720
     721        const QString mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS"));
     722        if (!mkspecDirectory.isEmpty()) {
     723            bool cumulative = m_cumulative;
     724            m_cumulative = false;
     725            // This is what qmake does, everything set in the mkspec is also set
     726            // But this also creates a lot of problems
     727            evaluateFile(mkspecDirectory + QLatin1String("/default/qmake.conf"));
     728            evaluateFile(mkspecDirectory + QLatin1String("/features/default_pre.prf"));
     729            m_cumulative = cumulative;
     730        }
     731
     732        return returnBool(QDir::setCurrent(pro->directoryName()));
     733    }
     734
     735    return ProItem::ReturnTrue;
     736}
     737
     738ProItem::ProItemReturn ProFileEvaluator::Private::visitEndProFile(ProFile * pro)
    519739{
    520740    PRE(pro);
    521     bool ok = true;
    522741    m_lineNo = pro->lineNumber();
    523742    if (m_profileStack.count() == 1 && !m_oldPath.isEmpty()) {
     743        const QString &mkspecDirectory = propertyValue(QLatin1String("QMAKE_MKSPECS"));
     744        if (!mkspecDirectory.isEmpty()) {
     745            bool cumulative = m_cumulative;
     746            m_cumulative = false;
     747
     748            evaluateFile(mkspecDirectory + QLatin1String("/features/default_post.prf"));
     749
     750            QSet<QString> processed;
     751            forever {
     752                bool finished = true;
     753                QStringList configs = valuesDirect(QLatin1String("CONFIG"));
     754                for (int i = configs.size() - 1; i >= 0; --i) {
     755                    const QString config = configs[i].toLower();
     756                    if (!processed.contains(config)) {
     757                        processed.insert(config);
     758                        if (evaluateFile(mkspecDirectory + QLatin1String("/features/")
     759                                         + config + QLatin1String(".prf"))) {
     760                            finished = false;
     761                            break;
     762                        }
     763                    }
     764                }
     765                if (finished)
     766                    break;
     767            }
     768
     769            foreach (ProBlock *itm, m_replaceFunctions)
     770                itm->deref();
     771            m_replaceFunctions.clear();
     772            foreach (ProBlock *itm, m_testFunctions)
     773                itm->deref();
     774            m_testFunctions.clear();
     775
     776            m_cumulative = cumulative;
     777        }
     778
    524779        m_profileStack.pop();
    525         ok = QDir::setCurrent(m_oldPath);
    526     }
    527     return ok;
    528 }
    529 
    530 bool ProFileEvaluator::Private::visitProValue(ProValue *value)
     780        return returnBool(QDir::setCurrent(m_oldPath));
     781    }
     782
     783    return ProItem::ReturnTrue;
     784}
     785
     786static void replaceInList(QStringList *varlist,
     787        const QRegExp &regexp, const QString &replace, bool global)
     788{
     789    for (QStringList::Iterator varit = varlist->begin(); varit != varlist->end(); ) {
     790        if ((*varit).contains(regexp)) {
     791            (*varit).replace(regexp, replace);
     792            if ((*varit).isEmpty())
     793                varit = varlist->erase(varit);
     794            else
     795                ++varit;
     796            if(!global)
     797                break;
     798        } else {
     799            ++varit;
     800        }
     801    }
     802}
     803
     804void ProFileEvaluator::Private::visitProValue(ProValue *value)
    531805{
    532806    PRE(value);
     
    545819            && m_lineNo == m_prevLineNo
    546820            && currentProFile() == m_prevProFile) {
    547         QStringList targets = m_valuemap.value(QLatin1String("TARGET"));
    548         m_valuemap.remove(QLatin1String("TARGET"));
     821        QStringList targets = m_tempValuemap.value(QLatin1String("TARGET"));
     822        m_tempValuemap.remove(QLatin1String("TARGET"));
    549823        QStringList lastTarget(targets.takeLast());
    550824        lastTarget << v.join(QLatin1String(" "));
     
    555829    m_prevProFile = currentProFile();
    556830
    557     // The following two blocks fix bug 180128 by making all "interesting"
    558     // file name absolute in each .pro file, not just the top most one
    559     if (varName == QLatin1String("SOURCES")
    560             || varName == QLatin1String("HEADERS")
    561             || varName == QLatin1String("INTERFACES")
    562             || varName == QLatin1String("FORMS")
    563             || varName == QLatin1String("FORMS3")
    564             || varName == QLatin1String("RESOURCES")) {
    565         // matches only existent files, expand certain(?) patterns
    566         QStringList vv;
    567         for (int i = v.count(); --i >= 0; )
    568             vv << expandPattern(v[i]);
    569         v = vv;
    570     }
    571 
    572     if (varName == QLatin1String("TRANSLATIONS")) {
    573         // also matches non-existent files, but does not expand pattern
    574         QString dir = QFileInfo(currentFileName()).absolutePath();
    575         dir += QLatin1Char('/');
    576         for (int i = v.count(); --i >= 0; )
    577             v[i] = QFileInfo(dir, v[i]).absoluteFilePath();
    578     }
    579 
    580831    switch (m_variableOperator) {
    581         case ProVariable::UniqueAddOperator:    // *
    582             insertUnique(&m_valuemap, varName, v, true);
    583             insertUnique(&m_filevaluemap[currentProFile()], varName, v, true);
    584             break;
    585832        case ProVariable::SetOperator:          // =
    586         case ProVariable::AddOperator:          // +
    587             insertUnique(&m_valuemap, varName, v, false);
    588             insertUnique(&m_filevaluemap[currentProFile()], varName, v, false);
    589             break;
    590         case ProVariable::RemoveOperator:       // -
    591             // fix me: interaction between AddOperator and RemoveOperator
    592             insertUnique(&m_valuemap, varName.prepend(QLatin1Char('-')), v, false);
    593             insertUnique(&m_filevaluemap[currentProFile()],
    594                          varName.prepend(QLatin1Char('-')), v, false);
    595             break;
    596         case ProVariable::ReplaceOperator:      // ~
     833            if (!m_cumulative) {
     834                if (!m_skipLevel) {
     835                    if (m_isFirstVariableValue) {
     836                        m_tempValuemap[varName] = v;
     837                        m_tempFilevaluemap[currentProFile()][varName] = v;
     838                    } else { // handle lines "CONFIG = foo bar"
     839                        m_tempValuemap[varName] += v;
     840                        m_tempFilevaluemap[currentProFile()][varName] += v;
     841                    }
     842                }
     843            } else {
     844                // We are greedy for values.
     845                m_tempValuemap[varName] += v;
     846                m_tempFilevaluemap[currentProFile()][varName] += v;
     847            }
     848            break;
     849        case ProVariable::UniqueAddOperator:    // *=
     850            if (!m_skipLevel || m_cumulative) {
     851                insertUnique(&m_tempValuemap, varName, v);
     852                insertUnique(&m_tempFilevaluemap[currentProFile()], varName, v);
     853            }
     854            break;
     855        case ProVariable::AddOperator:          // +=
     856            if (!m_skipLevel || m_cumulative) {
     857                m_tempValuemap[varName] += v;
     858                m_tempFilevaluemap[currentProFile()][varName] += v;
     859            }
     860            break;
     861        case ProVariable::RemoveOperator:       // -=
     862            if (!m_cumulative) {
     863                if (!m_skipLevel) {
     864                    removeEach(&m_tempValuemap, varName, v);
     865                    removeEach(&m_tempFilevaluemap[currentProFile()], varName, v);
     866                }
     867            } else {
     868                // We are stingy with our values, too.
     869            }
     870            break;
     871        case ProVariable::ReplaceOperator:      // ~=
    597872            {
    598873                // DEFINES ~= s/a/b/?[gqi]
    599874
    600 /*              Create a superset by executing replacement + adding items that have changed
    601                 to original list. We're not sure if this is really the right approach, so for
    602                 the time being we will just do nothing ...
    603 
     875                doVariableReplace(&val);
     876                if (val.length() < 4 || val[0] != QLatin1Char('s')) {
     877                    q->logMessage(format("the ~= operator can handle only the s/// function."));
     878                    break;
     879                }
    604880                QChar sep = val.at(1);
    605881                QStringList func = val.split(sep);
    606882                if (func.count() < 3 || func.count() > 4) {
    607                     q->logMessage(format("'~= operator '(function s///) expects 3 or 4 arguments."));
    608                     return false;
    609                 }
    610                 if (func[0] != QLatin1String("s")) {
    611                     q->logMessage(format("~= operator can only handle s/// function."));
    612                     return false;
     883                    q->logMessage(format("the s/// function expects 3 or 4 arguments."));
     884                    break;
    613885                }
    614886
     
    626898                QRegExp regexp(pattern, case_sense ? Qt::CaseSensitive : Qt::CaseInsensitive);
    627899
    628                 QStringList replaceList = replaceInList(m_valuemap.value(varName), regexp, replace,
    629                                                         global);
    630                 // Add changed entries to list
    631                 foreach (const QString &entry, replaceList)
    632                     if (!m_valuemap.value(varName).contains(entry))
    633                         insertUnique(&m_valuemap, varName, QStringList() << entry, false);
    634 
    635                 replaceList = replaceInList(m_filevaluemap[currentProFile()].value(varName), regexp,
    636                                       replace, global);
    637                 foreach (const QString &entry, replaceList)
    638                     if (!m_filevaluemap[currentProFile()].value(varName).contains(entry))
    639                         insertUnique(&m_filevaluemap[currentProFile()], varName,
    640                                      QStringList() << entry, false); */
    641             }
    642             break;
    643 
    644     }
    645     return true;
    646 }
    647 
    648 bool ProFileEvaluator::Private::visitProFunction(ProFunction *func)
    649 {
    650     m_lineNo = func->lineNumber();
    651     bool result = true;
    652     bool ok = true;
    653     QString text = func->text();
    654     int lparen = text.indexOf(QLatin1Char('('));
    655     int rparen = text.lastIndexOf(QLatin1Char(')'));
    656     Q_ASSERT(lparen < rparen);
    657 
    658     QString arguments = text.mid(lparen + 1, rparen - lparen - 1);
    659     QString funcName = text.left(lparen);
    660     ok &= evaluateConditionalFunction(funcName.trimmed(), arguments, &result);
    661     return ok;
     900                if (!m_skipLevel || m_cumulative) {
     901                    // We could make a union of modified and unmodified values,
     902                    // but this will break just as much as it fixes, so leave it as is.
     903                    replaceInList(&m_tempValuemap[varName], regexp, replace, global);
     904                    replaceInList(&m_tempFilevaluemap[currentProFile()][varName], regexp, replace, global);
     905                }
     906            }
     907            break;
     908
     909    }
     910    m_isFirstVariableValue = false;
     911}
     912
     913ProItem::ProItemReturn ProFileEvaluator::Private::visitProFunction(ProFunction *func)
     914{
     915    // Make sure that called subblocks don't inherit & destroy the state
     916    bool invertThis = m_invertNext;
     917    m_invertNext = false;
     918    if (!m_skipLevel)
     919        m_sts.prevCondition = false;
     920    if (m_cumulative || !m_sts.condition) {
     921        QString text = func->text();
     922        int lparen = text.indexOf(QLatin1Char('('));
     923        int rparen = text.lastIndexOf(QLatin1Char(')'));
     924        Q_ASSERT(lparen < rparen);
     925        QString arguments = text.mid(lparen + 1, rparen - lparen - 1);
     926        QString funcName = text.left(lparen);
     927        m_lineNo = func->lineNumber();
     928        ProItem::ProItemReturn result = evaluateConditionalFunction(funcName.trimmed(), arguments);
     929        if (result != ProItem::ReturnFalse && result != ProItem::ReturnTrue)
     930            return result;
     931        if (!m_skipLevel && ((result == ProItem::ReturnTrue) ^ invertThis))
     932            m_sts.condition = true;
     933    }
     934    return ProItem::ReturnTrue;
    662935}
    663936
     
    667940    QStringList concat;
    668941    {
    669         const QString base_concat = QDir::separator() + QString(QLatin1String("features"));
     942        const QString base_concat = QDir::separator() + QLatin1String("features");
    670943        concat << base_concat + QDir::separator() + QLatin1String("mac");
    671944        concat << base_concat + QDir::separator() + QLatin1String("macx");
     
    676949        concat << base_concat;
    677950    }
    678     const QString mkspecs_concat = QDir::separator() + QString(QLatin1String("mkspecs"));
     951    const QString mkspecs_concat = QDir::separator() + QLatin1String("mkspecs");
    679952    QStringList feature_roots;
    680953    QByteArray mkspec_path = qgetenv("QMAKEFEATURES");
     
    7791052}
    7801053
    781 QString ProFileEvaluator::Private::getcwd() const
     1054QString ProFileEvaluator::Private::currentDirectory() const
    7821055{
    7831056    ProFile *cur = m_profileStack.top();
    7841057    return cur->directoryName();
     1058}
     1059
     1060void ProFileEvaluator::Private::doVariableReplace(QString *str)
     1061{
     1062    *str = expandVariableReferences(*str).join(QString(Option::field_sep));
    7851063}
    7861064
     
    9991277}
    10001278
     1279QStringList ProFileEvaluator::Private::evaluateFunction(
     1280        ProBlock *funcPtr, const QStringList &argumentsList, bool *ok)
     1281{
     1282    bool oki;
     1283    QStringList ret;
     1284
     1285    if (m_valuemapStack.count() >= 100) {
     1286        q->errorMessage(format("ran into infinite recursion (depth > 100)."));
     1287        oki = false;
     1288    } else {
     1289        State sts = m_sts;
     1290        m_valuemapStack.push(m_valuemap);
     1291        m_filevaluemapStack.push(m_filevaluemap);
     1292
     1293        QStringList args;
     1294        for (int i = 0; i < argumentsList.count(); ++i) {
     1295            QStringList theArgs = expandVariableReferences(argumentsList[i]);
     1296            args += theArgs;
     1297            m_valuemap[QString::number(i+1)] = theArgs;
     1298        }
     1299        m_valuemap[QLatin1String("ARGS")] = args;
     1300        oki = (funcPtr->Accept(this) != ProItem::ReturnFalse); // True || Return
     1301        ret = m_returnValue;
     1302        m_returnValue.clear();
     1303
     1304        m_valuemap = m_valuemapStack.pop();
     1305        m_filevaluemap = m_filevaluemapStack.pop();
     1306        m_sts = sts;
     1307    }
     1308    if (ok)
     1309        *ok = oki;
     1310    if (oki)
     1311        return ret;
     1312    return QStringList();
     1313}
     1314
    10011315QStringList ProFileEvaluator::Private::evaluateExpandFunction(const QString &func, const QString &arguments)
    10021316{
    10031317    QStringList argumentsList = split_arg_list(arguments);
     1318
     1319    if (ProBlock *funcPtr = m_replaceFunctions.value(func, 0))
     1320        return evaluateFunction(funcPtr, argumentsList, 0);
    10041321
    10051322    QStringList args;
     
    10131330                      E_REPLACE };
    10141331
    1015     static QHash<QString, int> *expands = 0;
    1016     if (!expands) {
    1017         expands = new QHash<QString, int>;
    1018         expands->insert(QLatin1String("member"), E_MEMBER);                //v (implemented)
    1019         expands->insert(QLatin1String("first"), E_FIRST);                  //v
    1020         expands->insert(QLatin1String("last"), E_LAST);                    //v
    1021         expands->insert(QLatin1String("cat"), E_CAT);
    1022         expands->insert(QLatin1String("fromfile"), E_FROMFILE);
    1023         expands->insert(QLatin1String("eval"), E_EVAL);
    1024         expands->insert(QLatin1String("list"), E_LIST);
    1025         expands->insert(QLatin1String("sprintf"), E_SPRINTF);
    1026         expands->insert(QLatin1String("join"), E_JOIN);                    //v
    1027         expands->insert(QLatin1String("split"), E_SPLIT);                  //v
    1028         expands->insert(QLatin1String("basename"), E_BASENAME);            //v
    1029         expands->insert(QLatin1String("dirname"), E_DIRNAME);              //v
    1030         expands->insert(QLatin1String("section"), E_SECTION);
    1031         expands->insert(QLatin1String("find"), E_FIND);
    1032         expands->insert(QLatin1String("system"), E_SYSTEM);                //v
    1033         expands->insert(QLatin1String("unique"), E_UNIQUE);
    1034         expands->insert(QLatin1String("quote"), E_QUOTE);                  //v
    1035         expands->insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND);
    1036         expands->insert(QLatin1String("upper"), E_UPPER);
    1037         expands->insert(QLatin1String("lower"), E_LOWER);
    1038         expands->insert(QLatin1String("re_escape"), E_RE_ESCAPE);
    1039         expands->insert(QLatin1String("files"), E_FILES);
    1040         expands->insert(QLatin1String("prompt"), E_PROMPT);
    1041         expands->insert(QLatin1String("replace"), E_REPLACE);
    1042     }
    1043     ExpandFunc func_t = ExpandFunc(expands->value(func.toLower()));
     1332    static QHash<QString, int> expands;
     1333    if (expands.isEmpty()) {
     1334        expands.insert(QLatin1String("member"), E_MEMBER);
     1335        expands.insert(QLatin1String("first"), E_FIRST);
     1336        expands.insert(QLatin1String("last"), E_LAST);
     1337        expands.insert(QLatin1String("cat"), E_CAT);
     1338        expands.insert(QLatin1String("fromfile"), E_FROMFILE); // implementation disabled (see comment below)
     1339        expands.insert(QLatin1String("eval"), E_EVAL);
     1340        expands.insert(QLatin1String("list"), E_LIST);
     1341        expands.insert(QLatin1String("sprintf"), E_SPRINTF);
     1342        expands.insert(QLatin1String("join"), E_JOIN);
     1343        expands.insert(QLatin1String("split"), E_SPLIT);
     1344        expands.insert(QLatin1String("basename"), E_BASENAME);
     1345        expands.insert(QLatin1String("dirname"), E_DIRNAME);
     1346        expands.insert(QLatin1String("section"), E_SECTION);
     1347        expands.insert(QLatin1String("find"), E_FIND);
     1348        expands.insert(QLatin1String("system"), E_SYSTEM);
     1349        expands.insert(QLatin1String("unique"), E_UNIQUE);
     1350        expands.insert(QLatin1String("quote"), E_QUOTE);
     1351        expands.insert(QLatin1String("escape_expand"), E_ESCAPE_EXPAND);
     1352        expands.insert(QLatin1String("upper"), E_UPPER);
     1353        expands.insert(QLatin1String("lower"), E_LOWER);
     1354        expands.insert(QLatin1String("re_escape"), E_RE_ESCAPE);
     1355        expands.insert(QLatin1String("files"), E_FILES);
     1356        expands.insert(QLatin1String("prompt"), E_PROMPT); // interactive, so cannot be implemented
     1357        expands.insert(QLatin1String("replace"), E_REPLACE);
     1358    }
     1359    ExpandFunc func_t = ExpandFunc(expands.value(func.toLower()));
    10441360
    10451361    QStringList ret;
     
    10871403            break;
    10881404        }
     1405        case E_SPRINTF:
     1406            if(args.count() < 1) {
     1407                q->logMessage(format("sprintf(format, ...) requires at least one argument"));
     1408            } else {
     1409                QString tmp = args.at(0);
     1410                for (int i = 1; i < args.count(); ++i)
     1411                    tmp = tmp.arg(args.at(i));
     1412                ret = split_value_list(tmp);
     1413            }
     1414            break;
    10891415        case E_JOIN: {
    10901416            if (args.count() < 1 || args.count() > 4) {
     
    11061432        case E_SPLIT: {
    11071433            if (args.count() != 2) {
    1108                 q->logMessage(format("split(var, sep) requires two arguments"));
     1434                q->logMessage(format("split(var, sep) requires one or two arguments"));
    11091435            } else {
    1110                 QString sep = args.at(1);
     1436                const QString &sep = (args.count() == 2) ? args[1] : QString(Option::field_sep);
    11111437                foreach (const QString &var, values(args.first()))
    11121438                    foreach (const QString &splt, var.split(sep))
     
    11791505            break;
    11801506        }
    1181         case E_SYSTEM: {
    1182             if (m_condition) {
     1507        case E_CAT:
     1508            if (args.count() < 1 || args.count() > 2) {
     1509                q->logMessage(format("cat(file, singleline=true) requires one or two arguments."));
     1510            } else {
     1511                QString file = args[0];
     1512                file = Option::fixPathToLocalOS(file);
     1513
     1514                bool singleLine = true;
     1515                if (args.count() > 1)
     1516                    singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive));
     1517
     1518                QFile qfile(file);
     1519                if (qfile.open(QIODevice::ReadOnly)) {
     1520                    QTextStream stream(&qfile);
     1521                    while (!stream.atEnd()) {
     1522                        ret += split_value_list(stream.readLine().trimmed());
     1523                        if (!singleLine)
     1524                            ret += QLatin1String("\n");
     1525                    }
     1526                    qfile.close();
     1527                }
     1528            }
     1529            break;
     1530#if 0 // Used only by Qt's configure for caching
     1531        case E_FROMFILE:
     1532            if (args.count() != 2) {
     1533                q->logMessage(format("fromfile(file, variable) requires two arguments."));
     1534            } else {
     1535                QString file = args[0], seek_variableName = args[1];
     1536
     1537                ProFile pro(Option::fixPathToLocalOS(file));
     1538
     1539                ProFileEvaluator visitor;
     1540                visitor.setVerbose(m_verbose);
     1541                visitor.setCumulative(m_cumulative);
     1542
     1543                if (!visitor.queryProFile(&pro))
     1544                    break;
     1545
     1546                if (!visitor.accept(&pro))
     1547                    break;
     1548
     1549                ret = visitor.values(seek_variableName);
     1550            }
     1551            break;
     1552#endif
     1553        case E_EVAL: {
     1554            if (args.count() != 1) {
     1555                q->logMessage(format("eval(variable) requires one argument"));
     1556
     1557            } else {
     1558                ret += values(args.at(0));
     1559            }
     1560            break; }
     1561        case E_LIST: {
     1562            static int x = 0;
     1563            QString tmp;
     1564            tmp.sprintf(".QMAKE_INTERNAL_TMP_variableName_%d", x++);
     1565            ret = QStringList(tmp);
     1566            QStringList lst;
     1567            foreach (const QString &arg, args)
     1568                lst += split_value_list(arg);
     1569            m_valuemap[tmp] = lst;
     1570            break; }
     1571        case E_FIND:
     1572            if (args.count() != 2) {
     1573                q->logMessage(format("find(var, str) requires two arguments."));
     1574            } else {
     1575                QRegExp regx(args[1]);
     1576                foreach (const QString &val, values(args.first()))
     1577                    if (regx.indexIn(val) != -1)
     1578                        ret += val;
     1579            }
     1580            break;
     1581        case E_SYSTEM:
     1582            if (!m_skipLevel) {
    11831583                if (args.count() < 1 || args.count() > 2) {
    11841584                    q->logMessage(format("system(execute) requires one or two arguments."));
     
    11881588                    bool singleLine = true;
    11891589                    if (args.count() > 1)
    1190                         singleLine = (args[1].toLower() == QLatin1String("true"));
     1590                        singleLine = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive));
    11911591                    QString output;
    11921592                    while (proc && !feof(proc)) {
     
    12021602                    }
    12031603                    ret += split_value_list(output);
    1204                 }
    1205             }
    1206             break; }
     1604                    if (proc)
     1605                        QT_PCLOSE(proc);
     1606                }
     1607            }
     1608            break;
     1609        case E_UNIQUE:
     1610            if(args.count() != 1) {
     1611                q->logMessage(format("unique(var) requires one argument."));
     1612            } else {
     1613                foreach (const QString &var, values(args.first()))
     1614                    if (!ret.contains(var))
     1615                        ret.append(var);
     1616            }
     1617            break;
    12071618        case E_QUOTE:
    12081619            for (int i = 0; i < args.count(); ++i)
    12091620                ret += QStringList(args.at(i));
    12101621            break;
     1622        case E_ESCAPE_EXPAND:
     1623            for (int i = 0; i < args.size(); ++i) {
     1624                QChar *i_data = args[i].data();
     1625                int i_len = args[i].length();
     1626                for (int x = 0; x < i_len; ++x) {
     1627                    if (*(i_data+x) == QLatin1Char('\\') && x < i_len-1) {
     1628                        if (*(i_data+x+1) == QLatin1Char('\\')) {
     1629                            ++x;
     1630                        } else {
     1631                            struct {
     1632                                char in, out;
     1633                            } mapped_quotes[] = {
     1634                                { 'n', '\n' },
     1635                                { 't', '\t' },
     1636                                { 'r', '\r' },
     1637                                { 0, 0 }
     1638                            };
     1639                            for (int i = 0; mapped_quotes[i].in; ++i) {
     1640                                if (*(i_data+x+1) == QLatin1Char(mapped_quotes[i].in)) {
     1641                                    *(i_data+x) = QLatin1Char(mapped_quotes[i].out);
     1642                                    if (x < i_len-2)
     1643                                        memmove(i_data+x+1, i_data+x+2, (i_len-x-2)*sizeof(QChar));
     1644                                    --i_len;
     1645                                    break;
     1646                                }
     1647                            }
     1648                        }
     1649                    }
     1650                }
     1651                ret.append(QString(i_data, i_len));
     1652            }
     1653            break;
     1654        case E_RE_ESCAPE:
     1655            for (int i = 0; i < args.size(); ++i)
     1656                ret += QRegExp::escape(args[i]);
     1657            break;
     1658        case E_UPPER:
     1659        case E_LOWER:
     1660            for (int i = 0; i < args.count(); ++i)
     1661                if (func_t == E_UPPER)
     1662                    ret += args[i].toUpper();
     1663                else
     1664                    ret += args[i].toLower();
     1665            break;
     1666        case E_FILES:
     1667            if (args.count() != 1 && args.count() != 2) {
     1668                q->logMessage(format("files(pattern, recursive=false) requires one or two arguments"));
     1669            } else {
     1670                bool recursive = false;
     1671                if (args.count() == 2)
     1672                    recursive = (!args[1].compare(QLatin1String("true"), Qt::CaseInsensitive) || args[1].toInt());
     1673                QStringList dirs;
     1674                QString r = Option::fixPathToLocalOS(args[0]);
     1675                int slash = r.lastIndexOf(QDir::separator());
     1676                if (slash != -1) {
     1677                    dirs.append(r.left(slash));
     1678                    r = r.mid(slash+1);
     1679                } else {
     1680                    dirs.append(QString());
     1681                }
     1682
     1683                const QRegExp regex(r, Qt::CaseSensitive, QRegExp::Wildcard);
     1684                for (int d = 0; d < dirs.count(); d++) {
     1685                    QString dir = dirs[d];
     1686                    if (!dir.isEmpty() && !dir.endsWith(Option::dir_sep))
     1687                        dir += QLatin1Char('/');
     1688
     1689                    QDir qdir(dir);
     1690                    for (int i = 0; i < (int)qdir.count(); ++i) {
     1691                        if (qdir[i] == QLatin1String(".") || qdir[i] == QLatin1String(".."))
     1692                            continue;
     1693                        QString fname = dir + qdir[i];
     1694                        if (QFileInfo(fname).isDir()) {
     1695                            if (recursive)
     1696                                dirs.append(fname);
     1697                        }
     1698                        if (regex.exactMatch(qdir[i]))
     1699                            ret += fname;
     1700                    }
     1701                }
     1702            }
     1703            break;
     1704        case E_REPLACE:
     1705            if(args.count() != 3 ) {
     1706                q->logMessage(format("replace(var, before, after) requires three arguments"));
     1707            } else {
     1708                const QRegExp before(args[1]);
     1709                const QString after(args[2]);
     1710                foreach (QString val, values(args.first()))
     1711                    ret += val.replace(before, after);
     1712            }
     1713            break;
    12111714        case 0:
    1212             q->logMessage(format("'%1' is not a function").arg(func));
     1715            q->logMessage(format("'%1' is not a recognized replace function").arg(func));
    12131716            break;
    12141717        default:
     
    12201723}
    12211724
    1222 bool ProFileEvaluator::Private::evaluateConditionalFunction(const QString &function,
    1223     const QString &arguments, bool *result)
     1725ProItem::ProItemReturn ProFileEvaluator::Private::evaluateConditionalFunction(
     1726        const QString &function, const QString &arguments)
    12241727{
    12251728    QStringList argumentsList = split_arg_list(arguments);
     1729
     1730    if (ProBlock *funcPtr = m_testFunctions.value(function, 0)) {
     1731        bool ok;
     1732        QStringList ret = evaluateFunction(funcPtr, argumentsList, &ok);
     1733        if (ok) {
     1734            if (ret.isEmpty()) {
     1735                return ProItem::ReturnTrue;
     1736            } else {
     1737                if (ret.first() != QLatin1String("false")) {
     1738                    if (ret.first() == QLatin1String("true")) {
     1739                        return ProItem::ReturnTrue;
     1740                    } else {
     1741                        bool ok;
     1742                        int val = ret.first().toInt(&ok);
     1743                        if (ok) {
     1744                            if (val)
     1745                                return ProItem::ReturnTrue;
     1746                        } else {
     1747                            q->logMessage(format("Unexpected return value from test '%1': %2")
     1748                                          .arg(function).arg(ret.join(QLatin1String(" :: "))));
     1749                        }
     1750                    }
     1751                }
     1752            }
     1753        }
     1754        return ProItem::ReturnFalse;
     1755    }
     1756
    12261757    QString sep;
    12271758    sep.append(Option::field_sep);
    1228 
    12291759    QStringList args;
    12301760    for (int i = 0; i < argumentsList.count(); ++i)
    12311761        args += expandVariableReferences(argumentsList[i]).join(sep);
    12321762
    1233     enum ConditionFunc { CF_CONFIG = 1, CF_CONTAINS, CF_COUNT, CF_EXISTS, CF_INCLUDE,
    1234         CF_LOAD, CF_ISEMPTY, CF_SYSTEM, CF_MESSAGE};
    1235 
    1236     static QHash<QString, int> *functions = 0;
    1237     if (!functions) {
    1238         functions = new QHash<QString, int>;
    1239         functions->insert(QLatin1String("load"), CF_LOAD);         //v
    1240         functions->insert(QLatin1String("include"), CF_INCLUDE);   //v
    1241         functions->insert(QLatin1String("message"), CF_MESSAGE);   //v
    1242         functions->insert(QLatin1String("warning"), CF_MESSAGE);   //v
    1243         functions->insert(QLatin1String("error"), CF_MESSAGE);     //v
    1244     }
    1245 
    1246     bool cond = false;
    1247     bool ok = true;
    1248 
    1249     ConditionFunc func_t = (ConditionFunc)functions->value(function);
     1763    enum TestFunc { T_REQUIRES=1, T_GREATERTHAN, T_LESSTHAN, T_EQUALS,
     1764                    T_EXISTS, T_EXPORT, T_CLEAR, T_UNSET, T_EVAL, T_CONFIG, T_SYSTEM,
     1765                    T_RETURN, T_BREAK, T_NEXT, T_DEFINED, T_CONTAINS, T_INFILE,
     1766                    T_COUNT, T_ISEMPTY, T_INCLUDE, T_LOAD, T_DEBUG, T_MESSAGE, T_IF,
     1767                    T_FOR, T_DEFINE_TEST, T_DEFINE_REPLACE };
     1768
     1769    static QHash<QString, int> functions;
     1770    if (functions.isEmpty()) {
     1771        functions.insert(QLatin1String("requires"), T_REQUIRES);
     1772        functions.insert(QLatin1String("greaterThan"), T_GREATERTHAN);
     1773        functions.insert(QLatin1String("lessThan"), T_LESSTHAN);
     1774        functions.insert(QLatin1String("equals"), T_EQUALS);
     1775        functions.insert(QLatin1String("isEqual"), T_EQUALS);
     1776        functions.insert(QLatin1String("exists"), T_EXISTS);
     1777        functions.insert(QLatin1String("export"), T_EXPORT);
     1778        functions.insert(QLatin1String("clear"), T_CLEAR);
     1779        functions.insert(QLatin1String("unset"), T_UNSET);
     1780        functions.insert(QLatin1String("eval"), T_EVAL);
     1781        functions.insert(QLatin1String("CONFIG"), T_CONFIG);
     1782        functions.insert(QLatin1String("if"), T_IF);
     1783        functions.insert(QLatin1String("isActiveConfig"), T_CONFIG);
     1784        functions.insert(QLatin1String("system"), T_SYSTEM);
     1785        functions.insert(QLatin1String("return"), T_RETURN);
     1786        functions.insert(QLatin1String("break"), T_BREAK);
     1787        functions.insert(QLatin1String("next"), T_NEXT);
     1788        functions.insert(QLatin1String("defined"), T_DEFINED);
     1789        functions.insert(QLatin1String("contains"), T_CONTAINS);
     1790        functions.insert(QLatin1String("infile"), T_INFILE);
     1791        functions.insert(QLatin1String("count"), T_COUNT);
     1792        functions.insert(QLatin1String("isEmpty"), T_ISEMPTY);
     1793        functions.insert(QLatin1String("load"), T_LOAD);         //v
     1794        functions.insert(QLatin1String("include"), T_INCLUDE);   //v
     1795        functions.insert(QLatin1String("debug"), T_DEBUG);
     1796        functions.insert(QLatin1String("message"), T_MESSAGE);   //v
     1797        functions.insert(QLatin1String("warning"), T_MESSAGE);   //v
     1798        functions.insert(QLatin1String("error"), T_MESSAGE);     //v
     1799        functions.insert(QLatin1String("for"), T_FOR);     //v
     1800        functions.insert(QLatin1String("defineTest"), T_DEFINE_TEST);        //v
     1801        functions.insert(QLatin1String("defineReplace"), T_DEFINE_REPLACE);  //v
     1802    }
     1803
     1804    TestFunc func_t = (TestFunc)functions.value(function);
    12501805
    12511806    switch (func_t) {
    1252         case CF_CONFIG: {
     1807        case T_DEFINE_TEST:
     1808            m_definingTest = true;
     1809            goto defineFunc;
     1810        case T_DEFINE_REPLACE:
     1811            m_definingTest = false;
     1812          defineFunc:
     1813            if (args.count() != 1) {
     1814                q->logMessage(format("%s(function) requires one argument.").arg(function));
     1815                return ProItem::ReturnFalse;
     1816            }
     1817            m_definingFunc = args.first();
     1818            return ProItem::ReturnTrue;
     1819        case T_DEFINED:
     1820            if (args.count() < 1 || args.count() > 2) {
     1821                q->logMessage(format("defined(function, [\"test\"|\"replace\"])"
     1822                                     " requires one or two arguments."));
     1823                return ProItem::ReturnFalse;
     1824            }
     1825            if (args.count() > 1) {
     1826                if (args[1] == QLatin1String("test"))
     1827                    return returnBool(m_testFunctions.contains(args[0]));
     1828                else if (args[1] == QLatin1String("replace"))
     1829                    return returnBool(m_replaceFunctions.contains(args[0]));
     1830                q->logMessage(format("defined(function, type):"
     1831                                     " unexpected type [%1].\n").arg(args[1]));
     1832                return ProItem::ReturnFalse;
     1833            }
     1834            return returnBool(m_replaceFunctions.contains(args[0])
     1835                              || m_testFunctions.contains(args[0]));
     1836        case T_RETURN:
     1837            m_returnValue = args;
     1838            // It is "safe" to ignore returns - due to qmake brokeness
     1839            // they cannot be used to terminate loops anyway.
     1840            if (m_skipLevel || m_cumulative)
     1841                return ProItem::ReturnTrue;
     1842            if (m_valuemapStack.isEmpty()) {
     1843                q->logMessage(format("unexpected return()."));
     1844                return ProItem::ReturnFalse;
     1845            }
     1846            return ProItem::ReturnReturn;
     1847        case T_EXPORT:
     1848            if (m_skipLevel && !m_cumulative)
     1849                return ProItem::ReturnTrue;
     1850            if (args.count() != 1) {
     1851                q->logMessage(format("export(variable) requires one argument."));
     1852                return ProItem::ReturnFalse;
     1853            }
     1854            for (int i = 0; i < m_valuemapStack.size(); ++i) {
     1855                m_valuemapStack[i][args[0]] = m_valuemap[args[0]];
     1856                m_filevaluemapStack[i][currentProFile()][args[0]] =
     1857                        m_filevaluemap[currentProFile()][args[0]];
     1858            }
     1859            return ProItem::ReturnTrue;
     1860#if 0
     1861        case T_INFILE:
     1862        case T_REQUIRES:
     1863        case T_EVAL:
     1864#endif
     1865        case T_FOR: {
     1866            if (m_cumulative) // This is a no-win situation, so just pretend it's no loop
     1867                return ProItem::ReturnTrue;
     1868            if (m_skipLevel)
     1869                return ProItem::ReturnFalse;
     1870            if (args.count() > 2 || args.count() < 1) {
     1871                q->logMessage(format("for({var, list|var, forever|ever})"
     1872                                     " requires one or two arguments."));
     1873                return ProItem::ReturnFalse;
     1874            }
     1875            ProLoop loop;
     1876            loop.infinite = false;
     1877            loop.index = 0;
     1878            QString it_list;
     1879            if (args.count() == 1) {
     1880                doVariableReplace(&args[0]);
     1881                it_list = args[0];
     1882                if (args[0] != QLatin1String("ever")) {
     1883                    q->logMessage(format("for({var, list|var, forever|ever})"
     1884                                         " requires one or two arguments."));
     1885                    return ProItem::ReturnFalse;
     1886                }
     1887                it_list = QLatin1String("forever");
     1888            } else {
     1889                loop.variable = args[0];
     1890                loop.oldVarVal = m_valuemap.value(loop.variable);
     1891                doVariableReplace(&args[1]);
     1892                it_list = args[1];
     1893            }
     1894            loop.list = m_valuemap[it_list];
     1895            if (loop.list.isEmpty()) {
     1896                if (it_list == QLatin1String("forever")) {
     1897                    loop.infinite = true;
     1898                } else {
     1899                    int dotdot = it_list.indexOf(QLatin1String(".."));
     1900                    if (dotdot != -1) {
     1901                        bool ok;
     1902                        int start = it_list.left(dotdot).toInt(&ok);
     1903                        if (ok) {
     1904                            int end = it_list.mid(dotdot+2).toInt(&ok);
     1905                            if (ok) {
     1906                                if (start < end) {
     1907                                    for (int i = start; i <= end; i++)
     1908                                        loop.list << QString::number(i);
     1909                                } else {
     1910                                    for (int i = start; i >= end; i--)
     1911                                        loop.list << QString::number(i);
     1912                                }
     1913                            }
     1914                        }
     1915                    }
     1916                }
     1917            }
     1918            m_loopStack.push(loop);
     1919            m_sts.condition = true;
     1920            return ProItem::ReturnLoop;
     1921        }
     1922        case T_BREAK:
     1923            if (m_skipLevel)
     1924                return ProItem::ReturnFalse;
     1925            if (!m_loopStack.isEmpty())
     1926                return ProItem::ReturnBreak;
     1927            // ### missing: breaking out of multiline blocks
     1928            q->logMessage(format("unexpected break()."));
     1929            return ProItem::ReturnFalse;
     1930        case T_NEXT:
     1931            if (m_skipLevel)
     1932                return ProItem::ReturnFalse;
     1933            if (!m_loopStack.isEmpty())
     1934                return ProItem::ReturnNext;
     1935            q->logMessage(format("unexpected next()."));
     1936            return ProItem::ReturnFalse;
     1937        case T_IF: {
     1938            if (args.count() != 1) {
     1939                q->logMessage(format("if(condition) requires one argument."));
     1940                return ProItem::ReturnFalse;
     1941            }
     1942            QString cond = args.first();
     1943            bool escaped = false; // This is more than qmake does
     1944            bool quoted = false;
     1945            bool ret = true;
     1946            bool orOp = false;
     1947            bool invert = false;
     1948            bool isFunc = false;
     1949            int parens = 0;
     1950            QString test;
     1951            test.reserve(20);
     1952            QString args;
     1953            args.reserve(50);
     1954            const QChar *d = cond.unicode();
     1955            const QChar *ed = d + cond.length();
     1956            while (d < ed) {
     1957                ushort c = (d++)->unicode();
     1958                if (!escaped) {
     1959                    if (c == '\\') {
     1960                        escaped = true;
     1961                        args += c; // Assume no-one quotes the test name
     1962                        continue;
     1963                    } else if (c == '"') {
     1964                        quoted = !quoted;
     1965                        args += c; // Ditto
     1966                        continue;
     1967                    }
     1968                } else {
     1969                    escaped = false;
     1970                }
     1971                if (quoted) {
     1972                    args += c; // Ditto
     1973                } else {
     1974                    bool isOp = false;
     1975                    if (c == '(') {
     1976                        isFunc = true;
     1977                        if (parens)
     1978                            args += c;
     1979                        ++parens;
     1980                    } else if (c == ')') {
     1981                        --parens;
     1982                        if (parens)
     1983                            args += c;
     1984                    } else if (!parens) {
     1985                        if (c == ':' || c == '|')
     1986                            isOp = true;
     1987                        else if (c == '!')
     1988                            invert = true;
     1989                        else
     1990                            test += c;
     1991                    } else {
     1992                        args += c;
     1993                    }
     1994                    if (!parens && (isOp || d == ed)) {
     1995                        // Yes, qmake doesn't shortcut evaluations here. We can't, either,
     1996                        // as some test functions have side effects.
     1997                        bool success;
     1998                        if (isFunc) {
     1999                            success = evaluateConditionalFunction(test, args);
     2000                        } else {
     2001                            success = isActiveConfig(test, true);
     2002                        }
     2003                        success ^= invert;
     2004                        if (orOp)
     2005                            ret |= success;
     2006                        else
     2007                            ret &= success;
     2008                        orOp = (c == '|');
     2009                        invert = false;
     2010                        isFunc = false;
     2011                        test.clear();
     2012                        args.clear();
     2013                    }
     2014                }
     2015            }
     2016            return returnBool(ret);
     2017        }
     2018        case T_CONFIG: {
    12532019            if (args.count() < 1 || args.count() > 2) {
    12542020                q->logMessage(format("CONFIG(config) requires one or two arguments."));
    1255                 ok = false;
    1256                 break;
     2021                return ProItem::ReturnFalse;
    12572022            }
    12582023            if (args.count() == 1) {
    12592024                //cond = isActiveConfig(args.first()); XXX
    1260                 break;
     2025                return ProItem::ReturnFalse;
    12612026            }
    12622027            const QStringList mutuals = args[1].split(QLatin1Char('|'));
    12632028            const QStringList &configs = valuesDirect(QLatin1String("CONFIG"));
    1264             for (int i = configs.size() - 1 && ok; i >= 0; i--) {
     2029            for (int i = configs.size() - 1; i >= 0; i--) {
    12652030                for (int mut = 0; mut < mutuals.count(); mut++) {
    12662031                    if (configs[i] == mutuals[mut].trimmed()) {
    1267                         cond = (configs[i] == args[0]);
    1268                         goto done_T_CONFIG;
     2032                        return returnBool(configs[i] == args[0]);
    12692033                    }
    12702034                }
    12712035            }
    1272           done_T_CONFIG:
    1273             break;
    1274         }
    1275         case CF_CONTAINS: {
     2036            return ProItem::ReturnFalse;
     2037        }
     2038        case T_CONTAINS: {
    12762039            if (args.count() < 2 || args.count() > 3) {
    12772040                q->logMessage(format("contains(var, val) requires two or three arguments."));
    1278                 ok = false;
    1279                 break;
     2041                return ProItem::ReturnFalse;
    12802042            }
    12812043
     
    12862048                    const QString val = l[i];
    12872049                    if (regx.exactMatch(val) || val == args[1]) {
    1288                         cond = true;
    1289                         break;
     2050                        return ProItem::ReturnTrue;
    12902051                    }
    12912052                }
     
    12962057                    for (int mut = 0; mut < mutuals.count(); mut++) {
    12972058                        if (val == mutuals[mut].trimmed()) {
    1298                             cond = (regx.exactMatch(val) || val == args[1]);
    1299                             goto done_T_CONTAINS;
     2059                            return returnBool(regx.exactMatch(val) || val == args[1]);
    13002060                        }
    13012061                    }
    13022062                }
    13032063            }
    1304           done_T_CONTAINS:
    1305             break;
    1306         }
    1307         case CF_COUNT: {
     2064            return ProItem::ReturnFalse;
     2065        }
     2066        case T_COUNT: {
    13082067            if (args.count() != 2 && args.count() != 3) {
    1309                 q->logMessage(format("count(var, count) requires two or three arguments."));
    1310                 ok = false;
    1311                 break;
     2068                q->logMessage(format("count(var, count, op=\"equals\") requires two or three arguments."));
     2069                return ProItem::ReturnFalse;
    13122070            }
    13132071            if (args.count() == 3) {
    13142072                QString comp = args[2];
    13152073                if (comp == QLatin1String(">") || comp == QLatin1String("greaterThan")) {
    1316                     cond = values(args.first()).count() > args[1].toInt();
     2074                    return returnBool(values(args.first()).count() > args[1].toInt());
    13172075                } else if (comp == QLatin1String(">=")) {
    1318                     cond = values(args.first()).count() >= args[1].toInt();
     2076                    return returnBool(values(args.first()).count() >= args[1].toInt());
    13192077                } else if (comp == QLatin1String("<") || comp == QLatin1String("lessThan")) {
    1320                     cond = values(args.first()).count() < args[1].toInt();
     2078                    return returnBool(values(args.first()).count() < args[1].toInt());
    13212079                } else if (comp == QLatin1String("<=")) {
    1322                     cond = values(args.first()).count() <= args[1].toInt();
    1323                 } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual") || comp == QLatin1String("=") || comp == QLatin1String("==")) {
    1324                     cond = values(args.first()).count() == args[1].toInt();
     2080                    return returnBool(values(args.first()).count() <= args[1].toInt());
     2081                } else if (comp == QLatin1String("equals") || comp == QLatin1String("isEqual")
     2082                           || comp == QLatin1String("=") || comp == QLatin1String("==")) {
     2083                    return returnBool(values(args.first()).count() == args[1].toInt());
    13252084                } else {
    1326                     ok = false;
    13272085                    q->logMessage(format("unexpected modifier to count(%2)").arg(comp));
    1328                 }
    1329                 break;
    1330             }
    1331             cond = values(args.first()).count() == args[1].toInt();
    1332             break;
    1333         }
    1334         case CF_INCLUDE: {
     2086                    return ProItem::ReturnFalse;
     2087                }
     2088            }
     2089            return returnBool(values(args.first()).count() == args[1].toInt());
     2090        }
     2091        case T_GREATERTHAN:
     2092        case T_LESSTHAN: {
     2093            if (args.count() != 2) {
     2094                q->logMessage(format("%1(variable, value) requires two arguments.").arg(function));
     2095                return ProItem::ReturnFalse;
     2096            }
     2097            QString rhs(args[1]), lhs(values(args[0]).join(QString(Option::field_sep)));
     2098            bool ok;
     2099            int rhs_int = rhs.toInt(&ok);
     2100            if (ok) { // do integer compare
     2101                int lhs_int = lhs.toInt(&ok);
     2102                if (ok) {
     2103                    if (func_t == T_GREATERTHAN)
     2104                        return returnBool(lhs_int > rhs_int);
     2105                    return returnBool(lhs_int < rhs_int);
     2106                }
     2107            }
     2108            if (func_t == T_GREATERTHAN)
     2109                return returnBool(lhs > rhs);
     2110            return returnBool(lhs < rhs);
     2111        }
     2112        case T_EQUALS:
     2113            if (args.count() != 2) {
     2114                q->logMessage(format("%1(variable, value) requires two arguments.").arg(function));
     2115                return ProItem::ReturnFalse;
     2116            }
     2117            return returnBool(values(args[0]).join(QString(Option::field_sep)) == args[1]);
     2118        case T_CLEAR: {
     2119            if (m_skipLevel && !m_cumulative)
     2120                return ProItem::ReturnFalse;
     2121            if (args.count() != 1) {
     2122                q->logMessage(format("%1(variable) requires one argument.").arg(function));
     2123                return ProItem::ReturnFalse;
     2124            }
     2125            QHash<QString, QStringList>::Iterator it = m_valuemap.find(args[0]);
     2126            if (it == m_valuemap.end())
     2127                return ProItem::ReturnFalse;
     2128            it->clear();
     2129            return ProItem::ReturnTrue;
     2130        }
     2131        case T_UNSET: {
     2132            if (m_skipLevel && !m_cumulative)
     2133                return ProItem::ReturnFalse;
     2134            if (args.count() != 1) {
     2135                q->logMessage(format("%1(variable) requires one argument.").arg(function));
     2136                return ProItem::ReturnFalse;
     2137            }
     2138            QHash<QString, QStringList>::Iterator it = m_valuemap.find(args[0]);
     2139            if (it == m_valuemap.end())
     2140                return ProItem::ReturnFalse;
     2141            m_valuemap.erase(it);
     2142            return ProItem::ReturnTrue;
     2143        }
     2144        case T_INCLUDE: {
     2145            if (m_skipLevel && !m_cumulative)
     2146                return ProItem::ReturnFalse;
    13352147            QString parseInto;
    1336             if (args.count() == 2) {
     2148            // the third optional argument to include() controls warnings
     2149            //      and is not used here
     2150            if ((args.count() == 2) || (args.count() == 3)) {
    13372151                parseInto = args[1];
    13382152            } else if (args.count() != 1) {
    1339                 q->logMessage(format("include(file) requires one or two arguments."));
    1340                 ok = false;
    1341                 break;
     2153                q->logMessage(format("include(file) requires one, two or three arguments."));
     2154                return ProItem::ReturnFalse;
    13422155            }
    13432156            QString fileName = args.first();
    13442157            // ### this breaks if we have include(c:/reallystupid.pri) but IMHO that's really bad style.
    1345             QDir currentProPath(getcwd());
     2158            QDir currentProPath(currentDirectory());
    13462159            fileName = QDir::cleanPath(currentProPath.absoluteFilePath(fileName));
    1347             ok = evaluateFile(fileName, &ok);
    1348             break;
    1349         }
    1350         case CF_LOAD: {
     2160            State sts = m_sts;
     2161            bool ok = evaluateFile(fileName);
     2162            m_sts = sts;
     2163            return returnBool(ok);
     2164        }
     2165        case T_LOAD: {
     2166            if (m_skipLevel && !m_cumulative)
     2167                return ProItem::ReturnFalse;
    13512168            QString parseInto;
    13522169            bool ignore_error = false;
    13532170            if (args.count() == 2) {
    13542171                QString sarg = args[1];
    1355                 ignore_error = (sarg.toLower() == QLatin1String("true") || sarg.toInt());
     2172                ignore_error = (!sarg.compare(QLatin1String("true"), Qt::CaseInsensitive) || sarg.toInt());
    13562173            } else if (args.count() != 1) {
    13572174                q->logMessage(format("load(feature) requires one or two arguments."));
    1358                 ok = false;
    1359                 break;
    1360             }
    1361             ok = evaluateFeatureFile( args.first(), &cond);
    1362             break;
    1363         }
    1364         case CF_MESSAGE: {
     2175                return ProItem::ReturnFalse;
     2176            }
     2177            // XXX ignore_error unused
     2178            return returnBool(evaluateFeatureFile(args.first()));
     2179        }
     2180        case T_DEBUG:
     2181            // Yup - do nothing. Nothing is going to enable debug output anyway.
     2182            return ProItem::ReturnFalse;
     2183        case T_MESSAGE: {
    13652184            if (args.count() != 1) {
    13662185                q->logMessage(format("%1(message) requires one argument.").arg(function));
    1367                 ok = false;
    1368                 break;
    1369             }
    1370             QString msg = args.first();
    1371             if (function == QLatin1String("error")) {
    1372                 QStringList parents;
    1373                 foreach (ProFile *proFile, m_profileStack)
    1374                     parents.append(proFile->fileName());
    1375                 if (!parents.isEmpty())
    1376                     parents.takeLast();
    1377                 if (parents.isEmpty())
    1378                     q->fileMessage(format("Project ERROR: %1").arg(msg));
    1379                 else
    1380                     q->fileMessage(format("Project ERROR: %1. File was included from: '%2'")
    1381                         .arg(msg).arg(parents.join(QLatin1String("', '"))));
    1382             } else {
    1383                 q->fileMessage(format("Project MESSAGE: %1").arg(msg));
    1384             }
    1385             break;
    1386         }
    1387         case CF_SYSTEM: {
     2186                return ProItem::ReturnFalse;
     2187            }
     2188            QString msg = fixEnvVariables(args.first());
     2189            q->fileMessage(QString::fromLatin1("Project %1: %2").arg(function.toUpper(), msg));
     2190            // ### Consider real termination in non-cumulative mode
     2191            return returnBool(function != QLatin1String("error"));
     2192        }
     2193#if 0 // Way too dangerous to enable.
     2194        case T_SYSTEM: {
    13882195            if (args.count() != 1) {
    13892196                q->logMessage(format("system(exec) requires one argument."));
    1390                 ok = false;
    1391                 break;
    1392             }
    1393             ok = system(args.first().toLatin1().constData()) == 0;
    1394             break;
    1395         }
    1396         case CF_ISEMPTY: {
     2197                ProItem::ReturnFalse;
     2198            }
     2199            return returnBool(system(args.first().toLatin1().constData()) == 0);
     2200        }
     2201#endif
     2202        case T_ISEMPTY: {
    13972203            if (args.count() != 1) {
    13982204                q->logMessage(format("isEmpty(var) requires one argument."));
    1399                 ok = false;
    1400                 break;
     2205                return ProItem::ReturnFalse;
    14012206            }
    14022207            QStringList sl = values(args.first());
    14032208            if (sl.count() == 0) {
    1404                 cond = true;
     2209                return ProItem::ReturnTrue;
    14052210            } else if (sl.count() > 0) {
    14062211                QString var = sl.first();
    1407                 cond = (var.isEmpty());
    1408             }
    1409             break;
    1410         }
    1411         case CF_EXISTS: {
     2212                if (var.isEmpty())
     2213                    return ProItem::ReturnTrue;
     2214            }
     2215            return ProItem::ReturnFalse;
     2216        }
     2217        case T_EXISTS: {
    14122218            if (args.count() != 1) {
    14132219                q->logMessage(format("exists(file) requires one argument."));
    1414                 ok = false;
    1415                 break;
     2220                return ProItem::ReturnFalse;
    14162221            }
    14172222            QString file = args.first();
    1418 
    1419             file = QDir::cleanPath(file);
     2223            file = Option::fixPathToLocalOS(file);
    14202224
    14212225            if (QFile::exists(file)) {
    1422                 cond = true;
    1423                 break;
     2226                return ProItem::ReturnTrue;
    14242227            }
    14252228            //regular expression I guess
    1426             QString dirstr = getcwd();
     2229            QString dirstr = currentDirectory();
    14272230            int slsh = file.lastIndexOf(Option::dir_sep);
    14282231            if (slsh != -1) {
     
    14302233                file = file.right(file.length() - slsh - 1);
    14312234            }
    1432             cond = QDir(dirstr).entryList(QStringList(file)).count();
    1433 
    1434             break;
    1435         }
    1436     }
    1437 
    1438     if (result)
    1439         *result = cond;
    1440 
    1441     return ok;
     2235            if (file.contains(QLatin1Char('*')) || file.contains(QLatin1Char('?')))
     2236                if (!QDir(dirstr).entryList(QStringList(file)).isEmpty())
     2237                    return ProItem::ReturnTrue;
     2238
     2239            return ProItem::ReturnFalse;
     2240        }
     2241        case 0:
     2242            q->logMessage(format("'%1' is not a recognized test function").arg(function));
     2243            return ProItem::ReturnFalse;
     2244        default:
     2245            q->logMessage(format("Function '%1' is not implemented").arg(function));
     2246            return ProItem::ReturnFalse;
     2247    }
     2248}
     2249
     2250QStringList ProFileEvaluator::Private::values(const QString &variableName,
     2251                                              const QHash<QString, QStringList> &place,
     2252                                              const ProFile *pro) const
     2253{
     2254    if (variableName == QLatin1String("LITERAL_WHITESPACE")) //a real space in a token
     2255        return QStringList(QLatin1String("\t"));
     2256    if (variableName == QLatin1String("LITERAL_DOLLAR")) //a real $
     2257        return QStringList(QLatin1String("$"));
     2258    if (variableName == QLatin1String("LITERAL_HASH")) //a real #
     2259        return QStringList(QLatin1String("#"));
     2260    if (variableName == QLatin1String("OUT_PWD")) //the out going dir
     2261        return QStringList(m_outputDir);
     2262    if (variableName == QLatin1String("PWD") ||  //current working dir (of _FILE_)
     2263        variableName == QLatin1String("IN_PWD"))
     2264        return QStringList(currentDirectory());
     2265    if (variableName == QLatin1String("DIR_SEPARATOR"))
     2266        return QStringList(Option::dir_sep);
     2267    if (variableName == QLatin1String("DIRLIST_SEPARATOR"))
     2268        return QStringList(Option::dirlist_sep);
     2269    if (variableName == QLatin1String("_LINE_")) //parser line number
     2270        return QStringList(QString::number(m_lineNo));
     2271    if (variableName == QLatin1String("_FILE_")) //parser file; qmake is a bit weird here
     2272        return QStringList(m_profileStack.size() == 1 ? pro->fileName() : QFileInfo(pro->fileName()).fileName());
     2273    if (variableName == QLatin1String("_DATE_")) //current date/time
     2274        return QStringList(QDateTime::currentDateTime().toString());
     2275    if (variableName == QLatin1String("_PRO_FILE_"))
     2276        return QStringList(m_origfile);
     2277    if (variableName == QLatin1String("_PRO_FILE_PWD_"))
     2278        return  QStringList(QFileInfo(m_origfile).absolutePath());
     2279    if (variableName == QLatin1String("_QMAKE_CACHE_"))
     2280        return QStringList(); // FIXME?
     2281    if (variableName.startsWith(QLatin1String("QMAKE_HOST."))) {
     2282        QString ret, type = variableName.mid(11);
     2283#if defined(Q_OS_WIN32)
     2284        if (type == QLatin1String("os")) {
     2285            ret = QLatin1String("Windows");
     2286        } else if (type == QLatin1String("name")) {
     2287            DWORD name_length = 1024;
     2288            wchar_t name[1024];
     2289            if (GetComputerName(name, &name_length))
     2290                ret = QString::fromWCharArray(name);
     2291        } else if (type == QLatin1String("version") || type == QLatin1String("version_string")) {
     2292            QSysInfo::WinVersion ver = QSysInfo::WindowsVersion;
     2293            if (type == QLatin1String("version"))
     2294                ret = QString::number(ver);
     2295            else if (ver == QSysInfo::WV_Me)
     2296                ret = QLatin1String("WinMe");
     2297            else if (ver == QSysInfo::WV_95)
     2298                ret = QLatin1String("Win95");
     2299            else if (ver == QSysInfo::WV_98)
     2300                ret = QLatin1String("Win98");
     2301            else if (ver == QSysInfo::WV_NT)
     2302                ret = QLatin1String("WinNT");
     2303            else if (ver == QSysInfo::WV_2000)
     2304                ret = QLatin1String("Win2000");
     2305            else if (ver == QSysInfo::WV_2000)
     2306                ret = QLatin1String("Win2003");
     2307            else if (ver == QSysInfo::WV_XP)
     2308                ret = QLatin1String("WinXP");
     2309            else if (ver == QSysInfo::WV_VISTA)
     2310                ret = QLatin1String("WinVista");
     2311            else
     2312                ret = QLatin1String("Unknown");
     2313        } else if (type == QLatin1String("arch")) {
     2314            SYSTEM_INFO info;
     2315            GetSystemInfo(&info);
     2316            switch(info.wProcessorArchitecture) {
     2317#ifdef PROCESSOR_ARCHITECTURE_AMD64
     2318            case PROCESSOR_ARCHITECTURE_AMD64:
     2319                ret = QLatin1String("x86_64");
     2320                break;
     2321#endif
     2322            case PROCESSOR_ARCHITECTURE_INTEL:
     2323                ret = QLatin1String("x86");
     2324                break;
     2325            case PROCESSOR_ARCHITECTURE_IA64:
     2326#ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
     2327            case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
     2328#endif
     2329                ret = QLatin1String("IA64");
     2330                break;
     2331            default:
     2332                ret = QLatin1String("Unknown");
     2333                break;
     2334            }
     2335        }
     2336#elif defined(Q_OS_UNIX)
     2337        struct utsname name;
     2338        if (!uname(&name)) {
     2339            if (type == QLatin1String("os"))
     2340                ret = QString::fromLatin1(name.sysname);
     2341            else if (type == QLatin1String("name"))
     2342                ret = QString::fromLatin1(name.nodename);
     2343            else if (type == QLatin1String("version"))
     2344                ret = QString::fromLatin1(name.release);
     2345            else if (type == QLatin1String("version_string"))
     2346                ret = QString::fromLatin1(name.version);
     2347            else if (type == QLatin1String("arch"))
     2348                ret = QString::fromLatin1(name.machine);
     2349        }
     2350#endif
     2351        return QStringList(ret);
     2352    }
     2353
     2354    QStringList result = place[variableName];
     2355    if (result.isEmpty()) {
     2356        if (variableName == QLatin1String("TARGET")) {
     2357            result.append(QFileInfo(m_origfile).baseName());
     2358        } else if (variableName == QLatin1String("TEMPLATE")) {
     2359            result.append(QLatin1String("app"));
     2360        } else if (variableName == QLatin1String("QMAKE_DIR_SEP")) {
     2361            result.append(Option::dirlist_sep);
     2362        }
     2363    }
     2364    return result;
    14422365}
    14432366
    14442367QStringList ProFileEvaluator::Private::values(const QString &variableName) const
    14452368{
    1446     if (variableName == QLatin1String("TARGET")) {
    1447         QStringList list = m_valuemap.value(variableName);
    1448         if (!m_origfile.isEmpty())
    1449             list.append(QFileInfo(m_origfile).baseName());
    1450         return list;
    1451     }
    1452     if (variableName == QLatin1String("PWD")) {
    1453         return QStringList(getcwd());
    1454     }
    1455     return m_valuemap.value(variableName);
     2369    return values(variableName, m_valuemap, currentProFile());
    14562370}
    14572371
    14582372QStringList ProFileEvaluator::Private::values(const QString &variableName, const ProFile *pro) const
    14592373{
    1460     if (variableName == QLatin1String("TARGET")) {
    1461         QStringList list = m_filevaluemap[pro].value(variableName);
    1462         if (!m_origfile.isEmpty())
    1463             list.append(QFileInfo(m_origfile).baseName());
    1464         return list;
    1465     }
    1466     if (variableName == QLatin1String("PWD")) {
    1467         return QStringList(QFileInfo(pro->fileName()).absoluteFilePath());
    1468     }
    1469     return m_filevaluemap[pro].value(variableName);
     2374    return values(variableName, m_filevaluemap[pro], pro);
    14702375}
    14712376
     
    14742379    QFileInfo fi(fileName);
    14752380    if (fi.exists()) {
    1476         ProFile *pro = new ProFile(fi.absoluteFilePath());
     2381        QString fn = QDir::cleanPath(fi.absoluteFilePath());
     2382        foreach (const ProFile *pf, d->m_profileStack)
     2383            if (pf->fileName() == fn) {
     2384                errorMessage(d->format("circular inclusion of %1").arg(fn));
     2385                return 0;
     2386            }
     2387        ProFile *pro = new ProFile(fn);
    14772388        if (d->read(pro))
    14782389            return pro;
     
    14872398}
    14882399
    1489 bool ProFileEvaluator::Private::evaluateFile(const QString &fileName, bool *result)
    1490 {
    1491     bool ok = true;
     2400bool ProFileEvaluator::Private::evaluateFile(const QString &fileName)
     2401{
    14922402    ProFile *pro = q->parsedProFile(fileName);
    14932403    if (pro) {
    14942404        m_profileStack.push(pro);
    1495         ok = (currentProFile() ? pro->Accept(this) : false);
     2405        bool ok = (pro->Accept(this) == ProItem::ReturnTrue);
    14962406        m_profileStack.pop();
    14972407        q->releaseParsedProFile(pro);
    1498 
    1499         if (result)
    1500             *result = true;
     2408        return ok;
    15012409    } else {
    1502         if (result)
    1503             *result = false;
    1504     }
    1505 /*    if (ok && readFeatures) {
    1506         QStringList configs = values("CONFIG");
    1507         QSet<QString> processed;
    1508         foreach (const QString &fn, configs) {
    1509             if (!processed.contains(fn)) {
    1510                 processed.insert(fn);
    1511                 evaluateFeatureFile(fn, 0);
    1512             }
    1513         }
    1514     } */
    1515 
    1516     return ok;
    1517 }
    1518 
    1519 bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName, bool *result)
     2410        return false;
     2411    }
     2412}
     2413
     2414bool ProFileEvaluator::Private::evaluateFeatureFile(const QString &fileName)
    15202415{
    15212416    QString fn;
     
    15322427        }
    15332428    }
    1534     return fn.isEmpty() ? false : evaluateFile(fn, result);
    1535 }
    1536 
    1537 void ProFileEvaluator::Private::expandPatternHelper(const QString &relName, const QString &absName,
    1538         QStringList &sources_out)
    1539 {
    1540     const QStringList vpaths = values(QLatin1String("VPATH"))
    1541         + values(QLatin1String("QMAKE_ABSOLUTE_SOURCE_PATH"))
    1542         + values(QLatin1String("DEPENDPATH"))
    1543         + values(QLatin1String("VPATH_SOURCES"));
    1544 
    1545     QFileInfo fi(absName);
    1546     bool found = fi.exists();
    1547     // Search in all vpaths
    1548     if (!found) {
    1549         foreach (const QString &vpath, vpaths) {
    1550             fi.setFile(vpath + QDir::separator() + relName);
    1551             if (fi.exists()) {
    1552                 found = true;
    1553                 break;
    1554             }
    1555         }
    1556     }
    1557 
    1558     if (found) {
    1559         sources_out += fi.absoluteFilePath(); // Not resolving symlinks
    1560     } else {
    1561         QString val = relName;
    1562         QString dir;
    1563         QString wildcard = val;
    1564         QString real_dir;
    1565         if (wildcard.lastIndexOf(QLatin1Char('/')) != -1) {
    1566             dir = wildcard.left(wildcard.lastIndexOf(QLatin1Char('/')) + 1);
    1567             real_dir = dir;
    1568             wildcard = wildcard.right(wildcard.length() - dir.length());
    1569         }
    1570 
    1571         if (real_dir.isEmpty() || QFileInfo(real_dir).exists()) {
    1572             QStringList files = QDir(real_dir).entryList(QStringList(wildcard));
    1573             if (files.isEmpty()) {
    1574                 q->logMessage(format("Failure to find %1").arg(val));
    1575             } else {
    1576                 QString a;
    1577                 for (int i = files.count() - 1; i >= 0; --i) {
    1578                     if (files[i] == QLatin1String(".") || files[i] == QLatin1String(".."))
    1579                         continue;
    1580                     a = dir + files[i];
    1581                     sources_out += a;
    1582                 }
    1583             }
    1584         } else {
    1585             q->logMessage(format("Cannot match %1/%2, as %3 does not exist.")
    1586                 .arg(real_dir).arg(wildcard).arg(real_dir));
    1587         }
    1588     }
    1589 }
    1590 
    1591 
    1592 /*
    1593  * Lookup of files are done in this order:
    1594  *  1. look in pwd
    1595  *  2. look in vpaths
    1596  *  3. expand wild card files relative from the profiles folder
    1597  **/
    1598 
    1599 // FIXME: This code supports something that I'd consider a flaw in .pro file syntax
    1600 // which is not even documented. So arguably this can be ditched completely...
    1601 QStringList ProFileEvaluator::Private::expandPattern(const QString& pattern)
    1602 {
    1603     if (!currentProFile())
    1604         return QStringList();
    1605 
    1606     QStringList sources_out;
    1607     const QString absName = QDir::cleanPath(QDir::current().absoluteFilePath(pattern));
    1608 
    1609     expandPatternHelper(pattern, absName, sources_out);
    1610     return sources_out;
     2429    if (fn.isEmpty())
     2430        return false;
     2431    bool cumulative = m_cumulative;
     2432    m_cumulative = false;
     2433    bool ok = evaluateFile(fn);
     2434    m_cumulative = cumulative;
     2435    return ok;
    16112436}
    16122437
     
    16422467}
    16432468
     2469inline QStringList fixEnvVariables(const QStringList &x)
     2470{
     2471    QStringList ret;
     2472    foreach (const QString &str, x)
     2473        ret << Option::fixString(str, Option::FixEnvVars);
     2474    return ret;
     2475}
     2476
     2477
    16442478QStringList ProFileEvaluator::values(const QString &variableName) const
    16452479{
    1646     return d->values(variableName);
     2480    return fixEnvVariables(d->values(variableName));
    16472481}
    16482482
    16492483QStringList ProFileEvaluator::values(const QString &variableName, const ProFile *pro) const
    16502484{
    1651     return d->values(variableName, pro);
     2485    return fixEnvVariables(d->values(variableName, pro));
     2486}
     2487
     2488QStringList ProFileEvaluator::absolutePathValues(
     2489        const QString &variable, const QString &baseDirectory) const
     2490{
     2491    QStringList result;
     2492    foreach (const QString &el, values(variable)) {
     2493        const QFileInfo info = QFileInfo(baseDirectory, el);
     2494        if (info.isDir())
     2495            result << QDir::cleanPath(info.absoluteFilePath());
     2496    }
     2497    return result;
     2498}
     2499
     2500QStringList ProFileEvaluator::absoluteFileValues(
     2501        const QString &variable, const QString &baseDirectory, const QStringList &searchDirs,
     2502        const ProFile *pro) const
     2503{
     2504    QStringList result;
     2505    foreach (const QString &el, pro ? values(variable, pro) : values(variable)) {
     2506        QFileInfo info(el);
     2507        if (info.isAbsolute()) {
     2508            if (info.exists()) {
     2509                result << QDir::cleanPath(el);
     2510                goto next;
     2511            }
     2512        } else {
     2513            foreach (const QString &dir, searchDirs) {
     2514                QFileInfo info(dir, el);
     2515                if (info.isFile()) {
     2516                    result << QDir::cleanPath(info.filePath());
     2517                    goto next;
     2518                }
     2519            }
     2520            if (baseDirectory.isEmpty())
     2521                goto next;
     2522            info = QFileInfo(baseDirectory, el);
     2523        }
     2524        {
     2525            QFileInfo baseInfo(info.absolutePath());
     2526            if (baseInfo.exists()) {
     2527                QString wildcard = info.fileName();
     2528                if (wildcard.contains(QLatin1Char('*')) || wildcard.contains(QLatin1Char('?'))) {
     2529                    QDir theDir(QDir::cleanPath(baseInfo.filePath()));
     2530                    foreach (const QString &fn, theDir.entryList(QStringList(wildcard)))
     2531                        if (fn != QLatin1String(".") && fn != QLatin1String(".."))
     2532                            result << theDir.absoluteFilePath(fn);
     2533                }
     2534            }
     2535        }
     2536      next: ;
     2537    }
     2538    return result;
    16522539}
    16532540
     
    16562543    QStringList templ = values(QLatin1String("TEMPLATE"));
    16572544    if (templ.count() >= 1) {
    1658         QString t = templ.last().toLower();
    1659         if (t == QLatin1String("app"))
     2545        const QString &t = templ.last();
     2546        if (!t.compare(QLatin1String("app"), Qt::CaseInsensitive))
    16602547            return TT_Application;
    1661         if (t == QLatin1String("lib"))
     2548        if (!t.compare(QLatin1String("lib"), Qt::CaseInsensitive))
    16622549            return TT_Library;
    1663         if (t == QLatin1String("subdirs"))
     2550        if (!t.compare(QLatin1String("script"), Qt::CaseInsensitive))
     2551            return TT_Script;
     2552        if (!t.compare(QLatin1String("subdirs"), Qt::CaseInsensitive))
    16642553            return TT_Subdirs;
    16652554    }
     
    17052594void ProFileEvaluator::logMessage(const QString &message)
    17062595{
    1707     if (d->m_verbose)
     2596    if (d->m_verbose && !d->m_skipLevel)
    17082597        qWarning("%s", qPrintable(message));
    17092598}
     
    17112600void ProFileEvaluator::fileMessage(const QString &message)
    17122601{
    1713     qWarning("%s", qPrintable(message));
     2602    if (!d->m_skipLevel)
     2603        qWarning("%s", qPrintable(message));
    17142604}
    17152605
    17162606void ProFileEvaluator::errorMessage(const QString &message)
    17172607{
    1718     qWarning("%s", qPrintable(message));
     2608    if (!d->m_skipLevel)
     2609        qWarning("%s", qPrintable(message));
    17192610}
    17202611
     
    17242615}
    17252616
    1726 void evaluateProFile(const ProFileEvaluator &visitor, QHash<QByteArray, QStringList> *varMap)
    1727 {
    1728     QStringList sourceFiles;
    1729     QString codecForTr;
    1730     QString codecForSource;
    1731     QStringList tsFileNames;
    1732 
    1733     // app/lib template
    1734     sourceFiles += visitor.values(QLatin1String("SOURCES"));
    1735     sourceFiles += visitor.values(QLatin1String("HEADERS"));
    1736     tsFileNames = visitor.values(QLatin1String("TRANSLATIONS"));
    1737 
    1738     QStringList trcodec = visitor.values(QLatin1String("CODEC"))
    1739         + visitor.values(QLatin1String("DEFAULTCODEC"))
    1740         + visitor.values(QLatin1String("CODECFORTR"));
    1741     if (!trcodec.isEmpty())
    1742         codecForTr = trcodec.last();
    1743 
    1744     QStringList srccodec = visitor.values(QLatin1String("CODECFORSRC"));
    1745     if (!srccodec.isEmpty())
    1746         codecForSource = srccodec.last();
    1747 
    1748     QStringList forms = visitor.values(QLatin1String("INTERFACES"))
    1749         + visitor.values(QLatin1String("FORMS"))
    1750         + visitor.values(QLatin1String("FORMS3"));
    1751     sourceFiles << forms;
    1752 
    1753     sourceFiles.sort();
    1754     sourceFiles.removeDuplicates();
    1755     tsFileNames.sort();
    1756     tsFileNames.removeDuplicates();
    1757 
    1758     varMap->insert("SOURCES", sourceFiles);
    1759     varMap->insert("CODECFORTR", QStringList() << codecForTr);
    1760     varMap->insert("CODECFORSRC", QStringList() << codecForSource);
    1761     varMap->insert("TRANSLATIONS", tsFileNames);
    1762 }
    1763 
    1764 bool evaluateProFile(const QString &fileName, bool verbose, QHash<QByteArray, QStringList> *varMap)
    1765 {
    1766     QFileInfo fi(fileName);
    1767     if (!fi.exists())
    1768         return false;
    1769 
    1770     ProFile pro(fi.absoluteFilePath());
    1771 
    1772     ProFileEvaluator visitor;
    1773     visitor.setVerbose(verbose);
    1774 
    1775     if (!visitor.queryProFile(&pro))
    1776         return false;
    1777 
    1778     if (!visitor.accept(&pro))
    1779         return false;
    1780 
    1781     evaluateProFile(visitor, varMap);
    1782 
    1783     return true;
     2617void ProFileEvaluator::setCumulative(bool on)
     2618{
     2619    d->m_cumulative = on;
     2620}
     2621
     2622void ProFileEvaluator::setOutputDir(const QString &dir)
     2623{
     2624    d->m_outputDir = dir;
    17842625}
    17852626
  • trunk/tools/linguist/shared/profileevaluator.h

    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 Qt Linguist 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**
     
    5151#include <QtCore/QStack>
    5252
     53#if (!defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)) && !defined(__SUNPRO_CC)
     54# define HAVE_TEMPLATE_CLASS_FRIENDS
     55#endif
     56
    5357QT_BEGIN_NAMESPACE
    54 
    55 class ProFile;
    56 class ProFileEvaluator;
    57 
    58 void evaluateProFile(const ProFileEvaluator &visitor, QHash<QByteArray, QStringList> *varMap);
    59 bool evaluateProFile(const QString &fileName, bool verbose, QHash<QByteArray, QStringList> *varMap);
    6058
    6159class ProFileEvaluator
    6260{
     61#ifdef HAVE_TEMPLATE_CLASS_FRIENDS
     62private:
     63#else
     64public:
     65#endif
     66    class Private;
     67
    6368public:
    6469    enum TemplateType {
     
    6671        TT_Application,
    6772        TT_Library,
     73        TT_Script,
    6874        TT_Subdirs
    6975    };
     
    7480    ProFileEvaluator::TemplateType templateType();
    7581    virtual bool contains(const QString &variableName) const;
    76     void setVerbose(bool on);
     82    void setVerbose(bool on); // Default is false
     83    void setCumulative(bool on); // Default is true!
     84    void setOutputDir(const QString &dir); // Default is empty
    7785
    7886    bool queryProFile(ProFile *pro);
     
    8391    QStringList values(const QString &variableName) const;
    8492    QStringList values(const QString &variableName, const ProFile *pro) const;
     93    QStringList absolutePathValues(const QString &variable, const QString &baseDirectory) const;
     94    QStringList absoluteFileValues(
     95            const QString &variable, const QString &baseDirectory, const QStringList &searchDirs,
     96            const ProFile *pro) const;
    8597    QString propertyValue(const QString &val) const;
    8698
     
    93105
    94106private:
    95     class Private;
    96107    Private *d;
     108
     109#ifdef HAVE_TEMPLATE_CLASS_FRIENDS
     110    template<typename T> friend class QTypeInfo;
     111#endif
    97112};
    98113
  • trunk/tools/linguist/shared/proitems.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 Qt Linguist 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**
     
    5959
    6060// --------------- ProBlock ----------------
     61
    6162ProBlock::ProBlock(ProBlock *parent)
    6263{
    6364    m_blockKind = 0;
    6465    m_parent = parent;
     66    m_refCount = 1;
    6567}
    6668
    6769ProBlock::~ProBlock()
    6870{
    69     qDeleteAll(m_proitems);
     71    foreach (ProItem *itm, m_proitems)
     72        if (itm->kind() == BlockKind)
     73            static_cast<ProBlock *>(itm)->deref();
     74        else
     75            delete itm;
    7076}
    7177
     
    110116}
    111117
    112 bool ProBlock::Accept(AbstractProItemVisitor *visitor)
    113 {
    114     visitor->visitBeginProBlock(this);
    115     foreach (ProItem *item, m_proitems) {
    116         if (!item->Accept(visitor))
    117             return false;
     118ProItem::ProItemReturn ProBlock::Accept(AbstractProItemVisitor *visitor)
     119{
     120    if (visitor->visitBeginProBlock(this) == ReturnSkip)
     121        return ReturnTrue;
     122    ProItemReturn rt = ReturnTrue;
     123    for (int i = 0; i < m_proitems.count(); ++i) {
     124        rt = m_proitems.at(i)->Accept(visitor);
     125        if (rt != ReturnTrue && rt != ReturnFalse) {
     126            if (rt == ReturnLoop) {
     127                rt = ReturnTrue;
     128                while (visitor->visitProLoopIteration())
     129                    for (int j = i; ++j < m_proitems.count(); ) {
     130                        rt = m_proitems.at(j)->Accept(visitor);
     131                        if (rt != ReturnTrue && rt != ReturnFalse) {
     132                            if (rt == ReturnNext) {
     133                                rt = ReturnTrue;
     134                                break;
     135                            }
     136                            if (rt == ReturnBreak)
     137                                rt = ReturnTrue;
     138                            goto do_break;
     139                        }
     140                    }
     141              do_break:
     142                visitor->visitProLoopCleanup();
     143            }
     144            break;
     145        }
    118146    }
    119     return visitor->visitEndProBlock(this);
     147    visitor->visitEndProBlock(this);
     148    return rt;
    120149}
    121150
     
    149178}
    150179
    151 bool ProVariable::Accept(AbstractProItemVisitor *visitor)
     180ProItem::ProItemReturn ProVariable::Accept(AbstractProItemVisitor *visitor)
    152181{
    153182    visitor->visitBeginProVariable(this);
    154     foreach (ProItem *item, m_proitems) {
    155         if (!item->Accept(visitor))
    156             return false;
    157     }
    158     return visitor->visitEndProVariable(this);
     183    foreach (ProItem *item, m_proitems)
     184        item->Accept(visitor); // cannot fail
     185    visitor->visitEndProVariable(this);
     186    return ReturnTrue;
    159187}
    160188
     
    191219}
    192220
    193 bool ProValue::Accept(AbstractProItemVisitor *visitor)
    194 {
    195     return visitor->visitProValue(this);
     221ProItem::ProItemReturn ProValue::Accept(AbstractProItemVisitor *visitor)
     222{
     223    visitor->visitProValue(this);
     224    return ReturnTrue;
    196225}
    197226
     
    217246}
    218247
    219 bool ProFunction::Accept(AbstractProItemVisitor *visitor)
     248ProItem::ProItemReturn ProFunction::Accept(AbstractProItemVisitor *visitor)
    220249{
    221250    return visitor->visitProFunction(this);
     
    243272}
    244273
    245 bool ProCondition::Accept(AbstractProItemVisitor *visitor)
    246 {
    247     return visitor->visitProCondition(this);
     274ProItem::ProItemReturn ProCondition::Accept(AbstractProItemVisitor *visitor)
     275{
     276    visitor->visitProCondition(this);
     277    return ReturnTrue;
    248278}
    249279
     
    269299}
    270300
    271 bool ProOperator::Accept(AbstractProItemVisitor *visitor)
    272 {
    273     return visitor->visitProOperator(this);
     301ProItem::ProItemReturn ProOperator::Accept(AbstractProItemVisitor *visitor)
     302{
     303    visitor->visitProOperator(this);
     304    return ReturnTrue;
    274305}
    275306
     
    316347}
    317348
    318 bool ProFile::Accept(AbstractProItemVisitor *visitor)
    319 {
    320     visitor->visitBeginProFile(this);
    321     foreach (ProItem *item, m_proitems) {
    322         if (!item->Accept(visitor))
    323             return false;
    324     }
     349ProItem::ProItemReturn ProFile::Accept(AbstractProItemVisitor *visitor)
     350{
     351    ProItemReturn rt;
     352    if ((rt = visitor->visitBeginProFile(this)) != ReturnTrue)
     353        return rt;
     354    ProBlock::Accept(visitor); // cannot fail
    325355    return visitor->visitEndProFile(this);
    326356}
  • trunk/tools/linguist/shared/proitems.h

    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 Qt Linguist of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     24** In addition, as a special exception, Nokia gives you certain additional
     25** rights.  These rights are described in the Nokia Qt LGPL Exception
     26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
     
    4343#define PROITEMS_H
    4444
    45 #include <QtCore/QObject>
    4645#include <QtCore/QString>
    4746#include <QtCore/QList>
     
    6261    };
    6362
     63    enum ProItemReturn {
     64        ReturnFalse,
     65        ReturnTrue,
     66        ReturnBreak,
     67        ReturnNext,
     68        ReturnLoop,
     69        ReturnSkip,
     70        ReturnReturn
     71   };
     72
    6473    ProItem() : m_lineNumber(0) {}
    6574    virtual ~ProItem() {}
     
    7079    QString comment() const;
    7180
    72     virtual bool Accept(AbstractProItemVisitor *visitor) = 0;
     81    virtual ProItemReturn Accept(AbstractProItemVisitor *visitor) = 0;
    7382    int lineNumber() const { return m_lineNumber; }
    7483    void setLineNumber(int lineNumber) { m_lineNumber = lineNumber; }
     
    8897        VariableKind        = 0x04,
    8998        ProFileKind         = 0x08,
    90         SingleLine          = 0x10
     99        FunctionBodyKind    = 0x10,
     100        SingleLine          = 0x80
    91101    };
    92102
     
    104114    ProBlock *parent() const;
    105115
    106     ProItem::ProItemKind kind() const;
    107 
    108     virtual bool Accept(AbstractProItemVisitor *visitor);
     116    void ref() { ++m_refCount; }
     117    void deref() { if (!--m_refCount) delete this; }
     118
     119    ProItem::ProItemKind kind() const;
     120
     121    virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
    109122protected:
    110123    QList<ProItem *> m_proitems;
     
    112125    ProBlock *m_parent;
    113126    int m_blockKind;
     127    int m_refCount;
    114128};
    115129
     
    133147    QString variable() const;
    134148
    135     virtual bool Accept(AbstractProItemVisitor *visitor);
     149    virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
    136150private:
    137151    VariableOperator m_variableKind;
     
    152166    ProItem::ProItemKind kind() const;
    153167
    154     virtual bool Accept(AbstractProItemVisitor *visitor);
     168    virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
    155169private:
    156170    QString m_value;
     
    168182    ProItem::ProItemKind kind() const;
    169183
    170     virtual bool Accept(AbstractProItemVisitor *visitor);
     184    virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
    171185private:
    172186    QString m_text;
     
    183197    ProItem::ProItemKind kind() const;
    184198
    185     virtual bool Accept(AbstractProItemVisitor *visitor);
     199    virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
    186200private:
    187201    QString m_text;
     
    203217    ProItem::ProItemKind kind() const;
    204218
    205     virtual bool Accept(AbstractProItemVisitor *visitor);
     219    virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
    206220private:
    207221    OperatorKind m_operatorKind;
    208222};
    209223
    210 class ProFile : public QObject, public ProBlock
    211 {
    212     Q_OBJECT
    213 
     224class ProFile : public ProBlock
     225{
    214226public:
    215227    explicit ProFile(const QString &fileName);
     
    223235    bool isModified() const;
    224236
    225     virtual bool Accept(AbstractProItemVisitor *visitor);
     237    virtual ProItemReturn Accept(AbstractProItemVisitor *visitor);
    226238
    227239private:
  • trunk/tools/linguist/shared/proparser.pri

    r2 r561  
    33
    44HEADERS += \
     5    $$PWD/proreader.h \
    56    $$PWD/abstractproitemvisitor.h \
    67    $$PWD/proitems.h \
     
    910
    1011SOURCES += \
     12    $$PWD/proreader.cpp \
    1113    $$PWD/proitems.cpp \
    1214    $$PWD/profileevaluator.cpp
  • trunk/tools/linguist/shared/proparserutils.h

    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 Qt Linguist 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**
     
    4444
    4545#include <QtCore/QDir>
     46#ifndef QT_BOOTSTRAPPED
    4647#include <QtCore/QLibraryInfo>
     48#endif
    4749
    4850QT_BEGIN_NAMESPACE
     51
     52#ifdef QT_BOOTSTRAPPED
     53// this is a stripped down version of the one found in QtCore
     54class QLibraryInfo
     55{
     56public:
     57    enum LibraryLocation
     58    {
     59        PrefixPath,
     60        DocumentationPath,
     61        HeadersPath,
     62        LibrariesPath,
     63        BinariesPath,
     64        PluginsPath,
     65        DataPath,
     66        TranslationsPath,
     67        SettingsPath,
     68        DemosPath,
     69        ExamplesPath
     70    };
     71    static QString location(LibraryLocation);
     72};
     73#endif
    4974
    5075// Pre- and postcondition macros
     
    94119        Option::field_sep = QLatin1Char(' ');
    95120    }
     121
     122    enum StringFixFlags {
     123        FixNone                 = 0x00,
     124        FixEnvVars              = 0x01,
     125        FixPathCanonicalize     = 0x02,
     126        FixPathToLocalSeparators  = 0x04,
     127        FixPathToTargetSeparators = 0x08
     128    };
     129    static QString fixString(QString string, uchar flags);
     130
     131    inline static QString fixPathToLocalOS(const QString &in, bool fix_env = true, bool canonical = true)
     132    {
     133        uchar flags = FixPathToLocalSeparators;
     134        if (fix_env)
     135            flags |= FixEnvVars;
     136        if (canonical)
     137            flags |= FixPathCanonicalize;
     138        return fixString(in, flags);
     139    }
    96140};
    97141#if defined(Q_OS_WIN32)
     
    111155
    112156static void insertUnique(QHash<QString, QStringList> *map,
    113     const QString &key, const QStringList &value, bool unique = true)
     157    const QString &key, const QStringList &value)
    114158{
    115159    QStringList &sl = (*map)[key];
    116     if (!unique) {
    117         sl += value;
    118     } else {
    119         for (int i = 0; i < value.count(); ++i) {
    120             if (!sl.contains(value.at(i)))
    121                 sl.append(value.at(i));
    122         }
    123     }
     160    foreach (const QString &str, value)
     161        if (!sl.contains(str))
     162            sl.append(str);
     163}
     164
     165static void removeEach(QHash<QString, QStringList> *map,
     166    const QString &key, const QStringList &value)
     167{
     168    QStringList &sl = (*map)[key];
     169    foreach (const QString &str, value)
     170        sl.removeAll(str);
    124171}
    125172
     
    149196*/
    150197
    151 inline QStringList splitPathList(const QString paths)
     198inline QString fixEnvVariables(const QString &x)
     199{
     200    return Option::fixString(x, Option::FixEnvVars);
     201}
     202
     203inline QStringList splitPathList(const QString &paths)
    152204{
    153205    return paths.split(Option::dirlist_sep);
     
    256308{
    257309    QStringList ret;
    258     const QString concat = QDir::separator() + QString(QLatin1String("mkspecs"));
     310    const QString concat = QDir::separator() + QLatin1String("mkspecs");
    259311    QByteArray qmakepath = qgetenv("QMAKEPATH");
    260312    if (!qmakepath.isEmpty()) {
  • trunk/tools/linguist/shared/qm.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 Qt Linguist 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**
     
    4242#include "translator.h"
    4343
     44#ifndef QT_BOOTSTRAPPED
    4445#include <QtCore/QCoreApplication>
     46#endif
    4547#include <QtCore/QDebug>
    4648#include <QtCore/QDir>
     
    173175    bool save(QIODevice *iod);
    174176
    175     void insert(const TranslatorMessage &msg, bool forceComment);
     177    void insert(const TranslatorMessage &msg, const QStringList &tlns, bool forceComment);
     178    void insertIdBased(const TranslatorMessage &message, const QStringList &tlns);
    176179
    177180    void squeeze(TranslatorSaveMode mode);
     
    186189    QByteArray originalBytes(const QString &str, bool isUtf8) const;
    187190
    188     void insertInternal(const TranslatorMessage &message, bool forceComment, bool isUtf8);
     191    void insertInternal(const TranslatorMessage &message, const QStringList &tlns,
     192                        bool forceComment, bool isUtf8);
    189193
    190194    static Prefix commonPrefix(const ByteTranslatorMessage &m1, const ByteTranslatorMessage &m2);
     
    239243    TranslatorSaveMode mode, Prefix prefix) const
    240244{
    241     for (int i = 0; i < msg.translations().count(); ++i) {
    242         QString str = msg.translations().at(i);
    243         str.replace(QChar(Translator::DefaultVariantSeparator),
    244                     QChar(Translator::InternalVariantSeparator));
    245         stream << quint8(Tag_Translation) << str;
    246     }
     245    for (int i = 0; i < msg.translations().count(); ++i)
     246        stream << quint8(Tag_Translation) << msg.translations().at(i);
    247247
    248248    if (mode == SaveEverything)
    249249        prefix = HashContextSourceTextComment;
    250250
    251     // lrelease produces "wrong" .qm files for QByteArrays that are .isNull().
     251    // lrelease produces "wrong" QM files for QByteArrays that are .isNull().
    252252    switch (prefix) {
    253253    default:
     
    417417}
    418418
    419 void Releaser::insertInternal(const TranslatorMessage &message, bool forceComment, bool isUtf8)
     419void Releaser::insertInternal(const TranslatorMessage &message, const QStringList &tlns,
     420                              bool forceComment, bool isUtf8)
    420421{
    421422    ByteTranslatorMessage bmsg(originalBytes(message.context(), isUtf8),
    422423                               originalBytes(message.sourceText(), isUtf8),
    423424                               originalBytes(message.comment(), isUtf8),
    424                                message.translations());
     425                               tlns);
    425426    if (!forceComment) {
    426427        ByteTranslatorMessage bmsg2(
     
    434435}
    435436
    436 void Releaser::insert(const TranslatorMessage &message, bool forceComment)
    437 {
    438     insertInternal(message, forceComment, message.isUtf8());
     437void Releaser::insert(const TranslatorMessage &message, const QStringList &tlns, bool forceComment)
     438{
     439    insertInternal(message, tlns, forceComment, message.isUtf8());
    439440    if (message.isUtf8() && message.isNonUtf8())
    440         insertInternal(message, forceComment, false);
     441        insertInternal(message, tlns, forceComment, false);
     442}
     443
     444void Releaser::insertIdBased(const TranslatorMessage &message, const QStringList &tlns)
     445{
     446    ByteTranslatorMessage bmsg("", originalBytes(message.id(), false), "", tlns);
     447    m_messages.insert(bmsg, 0);
    441448}
    442449
     
    546553    //qDebug() << "NUMITEMS: " << numItems;
    547554
    548     // FIXME: that's just a guess, the original locale data is lost...
    549     QTextCodec *codec = QTextCodec::codecForLocale();
     555    QTextCodec *codec = QTextCodec::codecForName(
     556        cd.m_codecForSource.isEmpty() ? QByteArray("Latin1") : cd.m_codecForSource);
    550557    QTextCodec *utf8Codec = 0;
    551558    if (codec->name() != "UTF-8")
    552559        utf8Codec = QTextCodec::codecForName("UTF-8");
     560
     561    QString strProN = QLatin1String("%n");
     562    QLocale::Language l;
     563    QLocale::Country c;
     564    Translator::languageAndCountry(translator.languageCode(), &l, &c);
     565    QStringList numerusForms;
     566    bool guessPlurals = true;
     567    if (getNumerusInfo(l, c, 0, &numerusForms))
     568        guessPlurals = (numerusForms.count() == 1);
    553569
    554570    QString context, contextUtf8;
     
    585601                            ((str.at(i).unicode() << 8) & 0xff00));
    586602                }
    587                 str.replace(QChar(Translator::InternalVariantSeparator),
    588                             QChar(Translator::DefaultVariantSeparator));
    589603                translations << str;
    590604                m += len;
     
    636650        TranslatorMessage msg;
    637651        msg.setType(TranslatorMessage::Finished);
     652        if (translations.count() > 1) {
     653            // If guessPlurals is not false here, plural form discard messages
     654            // will be spewn out later.
     655            msg.setPlural(true);
     656        } else if (guessPlurals) {
     657            // This might cause false positives, so it is a fallback only.
     658            if (sourcetext.contains(strProN))
     659                msg.setPlural(true);
     660        }
    638661        msg.setTranslations(translations);
    639662        translations.clear();
     
    650673            if (!(contextIsSystem && sourcetextIsSystem && commentIsSystem)) {
    651674                cd.appendError(QLatin1String(
    652                         "Cannot read file with current system character codec"));
     675                        "Cannot read file with specified input codec"));
    653676                return false;
    654677            }
     
    664687
    665688
     689
     690static bool containsStripped(const Translator &translator, const TranslatorMessage &msg)
     691{
     692    foreach (const TranslatorMessage &tmsg, translator.messages())
     693        if (tmsg.sourceText() == msg.sourceText()
     694            && tmsg.context() == msg.context()
     695            && tmsg.comment().isEmpty())
     696        return true;
     697    return false;
     698}
    666699
    667700static bool saveQM(const Translator &translator, QIODevice &dev, ConversionData &cd)
     
    679712    int unfinished = 0;
    680713    int untranslated = 0;
     714    int missingIds = 0;
     715    int droppedData = 0;
    681716
    682717    for (int i = 0; i != translator.messageCount(); ++i) {
     
    684719        TranslatorMessage::Type typ = msg.type();
    685720        if (typ != TranslatorMessage::Obsolete) {
     721            if (cd.m_idBased && msg.id().isEmpty()) {
     722                ++missingIds;
     723                continue;
     724            }
    686725            if (typ == TranslatorMessage::Unfinished) {
    687                 if (msg.translation().isEmpty()) {
     726                if (!cd.m_idBased && msg.translation().isEmpty()) {
    688727                    ++untranslated;
    689728                    continue;
     
    696735                ++finished;
    697736            }
    698             // Drop the comment in (context, sourceText, comment),
    699             // unless the context is empty,
    700             // unless (context, sourceText, "") already exists or
    701             // unless we already dropped the comment of (context,
    702             // sourceText, comment0).
    703             bool forceComment =
    704                     msg.comment().isEmpty()
    705                     || msg.context().isEmpty()
    706                     || translator.contains(msg.context(), msg.sourceText(), QString());
    707             releaser.insert(msg, forceComment);
    708         }
    709     }
     737            QStringList tlns = msg.translations();
     738            if (msg.type() == TranslatorMessage::Unfinished
     739                && (cd.m_idBased || !cd.m_unTrPrefix.isEmpty()))
     740                for (int j = 0; j < tlns.size(); ++j)
     741                    if (tlns.at(j).isEmpty())
     742                        tlns[j] = cd.m_unTrPrefix + msg.sourceText();
     743            if (cd.m_idBased) {
     744                if (!msg.context().isEmpty() || !msg.comment().isEmpty())
     745                    ++droppedData;
     746                releaser.insertIdBased(msg, tlns);
     747            } else {
     748                // Drop the comment in (context, sourceText, comment),
     749                // unless the context is empty,
     750                // unless (context, sourceText, "") already exists or
     751                // unless we already dropped the comment of (context,
     752                // sourceText, comment0).
     753                bool forceComment =
     754                        msg.comment().isEmpty()
     755                        || msg.context().isEmpty()
     756                        || containsStripped(translator, msg);
     757                releaser.insert(msg, tlns, forceComment);
     758            }
     759        }
     760    }
     761
     762    if (missingIds)
     763        cd.appendError(QCoreApplication::translate("LRelease",
     764            "Dropped %n message(s) which had no ID.", 0,
     765            QCoreApplication::CodecForTr, missingIds));
     766    if (droppedData)
     767        cd.appendError(QCoreApplication::translate("LRelease",
     768            "Excess context/disambiguation dropped from %n message(s).", 0,
     769            QCoreApplication::CodecForTr, droppedData));
    710770
    711771    releaser.squeeze(cd.m_saveMode);
  • trunk/tools/linguist/shared/qph.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 Qt Linguist 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**
     
    5555{
    5656public:
    57     QPHReader(QIODevice &dev, ConversionData &cd)
    58       : QXmlStreamReader(&dev), m_cd(cd)
     57    QPHReader(QIODevice &dev)
     58      : QXmlStreamReader(&dev)
    5959    {}
    6060
     
    6363
    6464private:
    65     bool elementStarts(const QString &str) const
    66     {
    67         return isStartElement() && name() == str;
    68     }
    69 
    7065    bool isWhiteSpace() const
    7166    {
    7267        return isCharacters() && text().toString().trimmed().isEmpty();
    7368    }
    74 
    75     // needed to expand <byte ... />
    76     QString readContents();
    77     // needed to join <lengthvariant>s
    78     QString readTransContents();
    79 
    80     void handleError();
    81 
    82     ConversionData &m_cd;
    8369
    8470    enum DataField { NoField, SourceField, TargetField, DefinitionField };
     
    9682        readNext();
    9783        if (isStartElement()) {
    98             if (name() == QLatin1String("source"))
     84            if (name() == QLatin1String("source")) {
    9985                m_currentField = SourceField;
    100             else if (name() == QLatin1String("target"))
     86            } else if (name() == QLatin1String("target")) {
    10187                m_currentField = TargetField;
    102             else if (name() == QLatin1String("definition"))
     88            } else if (name() == QLatin1String("definition")) {
    10389                m_currentField = DefinitionField;
    104             else
     90            } else {
    10591                m_currentField = NoField;
     92                if (name() == QLatin1String("QPH")) {
     93                    QXmlStreamAttributes atts = attributes();
     94                    translator.setLanguageCode(atts.value(QLatin1String("language")).toString());
     95                    translator.setSourceLanguageCode(atts.value(QLatin1String("sourcelanguage")).toString());
     96                }
     97            }
    10698        } else if (isWhiteSpace()) {
    10799            // ignore these
     
    114106                m_currentDefinition += text();
    115107        } else if (isEndElement() && name() == QLatin1String("phrase")) {
     108            m_currentTarget.replace(QChar(Translator::TextVariantSeparator),
     109                                    QChar(Translator::BinaryVariantSeparator));
    116110            TranslatorMessage msg;
    117111            msg.setSourceText(m_currentSource);
    118112            msg.setTranslation(m_currentTarget);
    119             msg.setTranslatorComment(m_currentDefinition);
     113            msg.setComment(m_currentDefinition);
    120114            translator.append(msg);
    121115            m_currentSource.clear();
     
    127121}
    128122
    129 static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData &cd)
     123static bool loadQPH(Translator &translator, QIODevice &dev, ConversionData &)
    130124{
    131125    translator.setLocationsType(Translator::NoLocations);
    132     QPHReader reader(dev, cd);
     126    QPHReader reader(dev);
    133127    return reader.read(translator);
    134128}
     
    170164    QTextStream t(&dev);
    171165    t.setCodec(QTextCodec::codecForName("UTF-8"));
    172     t << "<!DOCTYPE QPH>\n<QPH>\n";
     166    t << "<!DOCTYPE QPH>\n<QPH";
     167    QString languageCode = translator.languageCode();
     168    if (!languageCode.isEmpty() && languageCode != QLatin1String("C"))
     169        t << " language=\"" << languageCode << "\"";
     170    languageCode = translator.sourceLanguageCode();
     171    if (!languageCode.isEmpty() && languageCode != QLatin1String("C"))
     172        t << " sourcelanguage=\"" << languageCode << "\"";
     173    t << ">\n";
    173174    foreach (const TranslatorMessage &msg, translator.messages()) {
    174175        t << "<phrase>\n";
    175176        t << "    <source>" << protect(msg.sourceText()) << "</source>\n";
    176         t << "    <target>" << protect(msg.translations().join(QLatin1String("@")))
     177        QString str = msg.translations().join(QLatin1String("@"));
     178        str.replace(QChar(Translator::BinaryVariantSeparator),
     179                    QChar(Translator::TextVariantSeparator));
     180        t << "    <target>" << protect(str)
    177181            << "</target>\n";
    178         if (!msg.context().isEmpty() || !msg.comment().isEmpty())
    179             t << "    <definition>" << msg.context() << msg.comment()
    180                 << "</definition>\n";
     182        if (!msg.comment().isEmpty())
     183            t << "    <definition>" << protect(msg.comment()) << "</definition>\n";
    181184        t << "</phrase>\n";
    182185    }
  • trunk/tools/linguist/shared/simtexth.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 Qt Linguist 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**
  • trunk/tools/linguist/shared/simtexth.h

    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 Qt Linguist 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**
  • trunk/tools/linguist/shared/translator.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 Qt Linguist 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**
     
    4646#include <stdio.h>
    4747
    48 #include <QtCore/QCoreApplication>
    4948#include <QtCore/QDebug>
    5049#include <QtCore/QDir>
     
    5857QT_BEGIN_NAMESPACE
    5958
     59#ifdef QT_BOOTSTRAPPED
     60QString QObject::tr(const char *sourceText, const char *, int n)
     61{
     62    QString ret = QString::fromLatin1(sourceText);
     63    if (n >= 0)
     64        ret.replace(QLatin1String("%n"), QString::number(n));
     65    return ret;
     66}
     67#endif
     68
    6069Translator::Translator() :
    61     m_codecName("ISO-8859-1"),
     70    m_codec(QTextCodec::codecForName("ISO-8859-1")),
    6271    m_locationsType(AbsoluteLocations)
    6372{
     
    8291}
    8392
    84 void Translator::replace(const TranslatorMessage &msg)
    85 {
    86     int index = m_messages.indexOf(msg);
    87     if (index == -1)
    88         m_messages.append(msg);
    89     else
    90         m_messages[index] = msg;
    91 }
    92 
    9393void Translator::replaceSorted(const TranslatorMessage &msg)
    9494{
    95     int index = m_messages.indexOf(msg);
     95    int index = find(msg);
    9696    if (index == -1)
    9797        appendSorted(msg);
     
    102102void Translator::extend(const TranslatorMessage &msg)
    103103{
    104     int index = m_messages.indexOf(msg);
     104    int index = find(msg);
    105105    if (index == -1) {
    106106        m_messages.append(msg);
     
    147147    int curIdx = 0;
    148148    foreach (const TranslatorMessage &mit, m_messages) {
    149         bool sameFile = mit.fileName() == msg.fileName();
     149        bool sameFile = mit.fileName() == msg.fileName() && mit.context() == msg.context();
    150150        int curLine;
    151151        if (sameFile && (curLine = mit.lineNumber()) >= prevLine) {
     
    313313}
    314314
    315 bool Translator::contains(const QString &context,
    316     const QString &sourceText, const QString &comment) const
    317 {
    318     return m_messages.contains(TranslatorMessage(context, sourceText, comment,
    319         QString(), QString(), 0));
    320 }
    321 
    322 TranslatorMessage Translator::find(const QString &context,
    323     const QString &sourceText, const QString &comment) const
    324 {
    325     TranslatorMessage needle(context, sourceText, comment, QString(), QString(), 0);
    326     int index = m_messages.indexOf(needle);
    327     return index == -1 ? TranslatorMessage() : m_messages.at(index);
     315int Translator::find(const TranslatorMessage &msg) const
     316{
     317    for (int i = 0; i < m_messages.count(); ++i) {
     318        const TranslatorMessage &tmsg = m_messages.at(i);
     319        if (msg.id().isEmpty() || tmsg.id().isEmpty()) {
     320            if (msg.context() == tmsg.context()
     321                && msg.sourceText() == tmsg.sourceText()
     322                && msg.comment() == tmsg.comment())
     323                return i;
     324        } else {
     325            if (msg.id() == tmsg.id())
     326                return i;
     327        }
     328    }
     329    return -1;
    328330}
    329331
     
    346348{
    347349    foreach (const TranslatorMessage &msg, m_messages)
    348         if (msg.context() == context && msg.sourceText().isEmpty())
     350        if (msg.context() == context && msg.sourceText().isEmpty() && msg.id().isEmpty())
    349351            return true;
    350352    return false;
     
    354356{
    355357    foreach (const TranslatorMessage &msg, m_messages)
    356         if (msg.context() == context && msg.sourceText().isEmpty())
     358        if (msg.context() == context && msg.sourceText().isEmpty() && msg.id().isEmpty())
    357359            return msg;
    358360    return TranslatorMessage();
     
    417419}
    418420
    419 QSet<TranslatorMessagePtr> Translator::resolveDuplicates()
    420 {
    421     QSet<TranslatorMessagePtr> dups;
    422     QHash<TranslatorMessagePtr, int> refs;
     421void Translator::dropUiLines()
     422{
     423    QString uiXt = QLatin1String(".ui");
     424    QString juiXt = QLatin1String(".jui");
     425    for (TMM::Iterator it = m_messages.begin(); it != m_messages.end(); ++it) {
     426        QHash<QString, int> have;
     427        QList<TranslatorMessage::Reference> refs;
     428        foreach (const TranslatorMessage::Reference &itref, it->allReferences()) {
     429            const QString &fn = itref.fileName();
     430            if (fn.endsWith(uiXt) || fn.endsWith(juiXt)) {
     431                if (++have[fn] == 1)
     432                    refs.append(TranslatorMessage::Reference(fn, -1));
     433            } else {
     434                refs.append(itref);
     435            }
     436        }
     437        it->setReferences(refs);
     438    }
     439}
     440
     441struct TranslatorMessageIdPtr {
     442    explicit TranslatorMessageIdPtr(const TranslatorMessage &tm)
     443    {
     444        ptr = &tm;
     445    }
     446
     447    inline const TranslatorMessage *operator->() const
     448    {
     449        return ptr;
     450    }
     451
     452    const TranslatorMessage *ptr;
     453};
     454
     455Q_DECLARE_TYPEINFO(TranslatorMessageIdPtr, Q_MOVABLE_TYPE);
     456
     457inline int qHash(TranslatorMessageIdPtr tmp)
     458{
     459    return qHash(tmp->id());
     460}
     461
     462inline bool operator==(TranslatorMessageIdPtr tmp1, TranslatorMessageIdPtr tmp2)
     463{
     464    return tmp1->id() == tmp2->id();
     465}
     466
     467struct TranslatorMessageContentPtr {
     468    explicit TranslatorMessageContentPtr(const TranslatorMessage &tm)
     469    {
     470        ptr = &tm;
     471    }
     472
     473    inline const TranslatorMessage *operator->() const
     474    {
     475        return ptr;
     476    }
     477
     478    const TranslatorMessage *ptr;
     479};
     480
     481Q_DECLARE_TYPEINFO(TranslatorMessageContentPtr, Q_MOVABLE_TYPE);
     482
     483inline int qHash(TranslatorMessageContentPtr tmp)
     484{
     485    int hash = qHash(tmp->context()) ^ qHash(tmp->sourceText());
     486    if (!tmp->sourceText().isEmpty())
     487        // Special treatment for context comments (empty source).
     488        hash ^= qHash(tmp->comment());
     489    return hash;
     490}
     491
     492inline bool operator==(TranslatorMessageContentPtr tmp1, TranslatorMessageContentPtr tmp2)
     493{
     494    if (tmp1->context() != tmp2->context() || tmp1->sourceText() != tmp2->sourceText())
     495        return false;
     496    // Special treatment for context comments (empty source).
     497    if (tmp1->sourceText().isEmpty())
     498        return true;
     499    return tmp1->comment() == tmp2->comment();
     500}
     501
     502Translator::Duplicates Translator::resolveDuplicates()
     503{
     504    Duplicates dups;
     505    QHash<TranslatorMessageIdPtr, int> idRefs;
     506    QHash<TranslatorMessageContentPtr, int> contentRefs;
    423507    for (int i = 0; i < m_messages.count();) {
    424508        const TranslatorMessage &msg = m_messages.at(i);
    425         QHash<TranslatorMessagePtr, int>::ConstIterator it = refs.constFind(msg);
    426         if (it != refs.constEnd()) {
    427             TranslatorMessage &omsg = m_messages[*it];
    428             if (omsg.isUtf8() != msg.isUtf8() && !omsg.isNonUtf8()) {
    429                 // Dual-encoded message
    430                 omsg.setUtf8(true);
    431                 omsg.setNonUtf8(true);
    432             } else {
    433                 // Duplicate
    434                 dups.insert(omsg);
     509        TranslatorMessage *omsg;
     510        int oi;
     511        QSet<int> *pDup;
     512        if (!msg.id().isEmpty()) {
     513            QHash<TranslatorMessageIdPtr, int>::ConstIterator it =
     514                    idRefs.constFind(TranslatorMessageIdPtr(msg));
     515            if (it != idRefs.constEnd()) {
     516                oi = *it;
     517                omsg = &m_messages[oi];
     518                pDup = &dups.byId;
     519                goto gotDupe;
    435520            }
    436             if (!omsg.isTranslated() && msg.isTranslated())
    437                 omsg.setTranslations(msg.translations());
    438             m_messages.removeAt(i);
     521        }
     522        {
     523            QHash<TranslatorMessageContentPtr, int>::ConstIterator it =
     524                    contentRefs.constFind(TranslatorMessageContentPtr(msg));
     525            if (it != contentRefs.constEnd()) {
     526                oi = *it;
     527                omsg = &m_messages[oi];
     528                if (msg.id().isEmpty() || omsg->id().isEmpty()) {
     529                    if (!msg.id().isEmpty() && omsg->id().isEmpty()) {
     530                        omsg->setId(msg.id());
     531                        idRefs[TranslatorMessageIdPtr(*omsg)] = oi;
     532                    }
     533                    pDup = &dups.byContents;
     534                    goto gotDupe;
     535                }
     536                // This is really a content dupe, but with two distinct IDs.
     537            }
     538        }
     539        if (!msg.id().isEmpty())
     540            idRefs[TranslatorMessageIdPtr(msg)] = i;
     541        contentRefs[TranslatorMessageContentPtr(msg)] = i;
     542        ++i;
     543        continue;
     544      gotDupe:
     545        if (omsg->isUtf8() != msg.isUtf8() && !omsg->isNonUtf8()) {
     546            // Dual-encoded message
     547            omsg->setUtf8(true);
     548            omsg->setNonUtf8(true);
    439549        } else {
    440             refs[msg] = i;
    441             ++i;
    442         }
     550            // Duplicate
     551            pDup->insert(oi);
     552        }
     553        if (!omsg->isTranslated() && msg.isTranslated())
     554            omsg->setTranslations(msg.translations());
     555        m_messages.removeAt(i);
    443556    }
    444557    return dups;
    445558}
    446559
    447 void Translator::reportDuplicates(const QSet<TranslatorMessagePtr> &dupes,
     560void Translator::reportDuplicates(const Duplicates &dupes,
    448561                                  const QString &fileName, bool verbose)
    449562{
    450     if (!dupes.isEmpty()) {
     563    if (!dupes.byId.isEmpty() || !dupes.byContents.isEmpty()) {
    451564        if (!verbose) {
    452565            qWarning("Warning: dropping duplicate messages in '%s'\n(try -verbose for more info).",
     
    454567        } else {
    455568            qWarning("Warning: dropping duplicate messages in '%s':", qPrintable(fileName));
    456             foreach (const TranslatorMessagePtr &msg, dupes) {
     569            foreach (int i, dupes.byId)
     570                qWarning("\n* ID: %s", qPrintable(message(i).id()));
     571            foreach (int j, dupes.byContents) {
     572                const TranslatorMessage &msg = message(j);
    457573                qWarning("\n* Context: %s\n* Source: %s",
    458                         qPrintable(msg->context()),
    459                         qPrintable(msg->sourceText()));
    460                 if (!msg->comment().isEmpty())
    461                     qWarning("* Comment: %s", qPrintable(msg->comment()));
     574                        qPrintable(msg.context()),
     575                        qPrintable(msg.sourceText()));
     576                if (!msg.comment().isEmpty())
     577                    qWarning("* Comment: %s", qPrintable(msg.comment()));
    462578            }
    463579            qWarning();
     
    499615}
    500616
    501 QStringList Translator::normalizedTranslations(const TranslatorMessage &msg,
    502     QLocale::Language language, QLocale::Country country)
     617QStringList Translator::normalizedTranslations(const TranslatorMessage &msg, int numPlurals)
    503618{
    504619    QStringList translations = msg.translations();
    505     int numTranslations = 1;
    506     if (msg.isPlural() && language != QLocale::C) {
    507         QStringList forms;
    508         if (getNumerusInfo(language, country, 0, &forms))
    509             numTranslations = forms.count(); // includes singular
    510     }
     620    int numTranslations = msg.isPlural() ? numPlurals : 1;
    511621
    512622    // make sure that the stringlist always have the size of the
     
    522632}
    523633
    524 QStringList Translator::normalizedTranslations(const TranslatorMessage &msg,
    525     ConversionData &cd, bool *ok) const
    526 {
     634void Translator::normalizeTranslations(ConversionData &cd)
     635{
     636    bool truncated = false;
    527637    QLocale::Language l;
    528638    QLocale::Country c;
    529639    languageAndCountry(languageCode(), &l, &c);
    530     QStringList translns = normalizedTranslations(msg, l, c);
    531     if (msg.translations().size() > translns.size() && ok) {
     640    int numPlurals = 1;
     641    if (l != QLocale::C) {
     642        QStringList forms;
     643        if (getNumerusInfo(l, c, 0, &forms))
     644            numPlurals = forms.count(); // includes singular
     645    }
     646    for (int i = 0; i < m_messages.count(); ++i) {
     647        const TranslatorMessage &msg = m_messages.at(i);
     648        QStringList tlns = msg.translations();
     649        int ccnt = msg.isPlural() ? numPlurals : 1;
     650        if (tlns.count() != ccnt) {
     651            while (tlns.count() < ccnt)
     652                tlns.append(QString());
     653            while (tlns.count() > ccnt) {
     654                tlns.removeLast();
     655                truncated = true;
     656            }
     657            TranslatorMessage msg2(msg);
     658            msg2.setTranslations(tlns);
     659            m_messages[i] = msg2;
     660        }
     661    }
     662    if (truncated)
    532663        cd.appendError(QLatin1String(
    533664            "Removed plural forms as the target language has less "
    534665            "forms.\nIf this sounds wrong, possibly the target language is "
    535666            "not set or recognized.\n"));
    536         *ok = false;
    537     }
    538     return translns;
    539667}
    540668
     
    586714        if (!name.isEmpty())
    587715            qWarning("No QTextCodec for %s available. Using Latin1\n", name.constData());
    588         m_codecName = "ISO-8859-1";
     716        m_codec = QTextCodec::codecForName("ISO-8859-1");
    589717    } else {
    590         m_codecName = codec->name();
    591     }
     718        m_codec = codec;
     719    }
     720}
     721
     722QByteArray Translator::codecName() const
     723{
     724    return m_codec->name();
    592725}
    593726
  • trunk/tools/linguist/shared/translator.h

    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 Qt Linguist 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**
     
    4848#include <QList>
    4949#include <QLocale>
     50#include <QMultiHash>
    5051#include <QString>
     52#include <QSet>
    5153
    5254
    5355QT_BEGIN_NAMESPACE
     56
     57#ifdef QT_BOOTSTRAPPED
     58class QObject {
     59public:
     60    static QString tr(const char *sourceText, const char * = 0, int n = -1);
     61};
     62class QCoreApplication : public QObject {
     63public:
     64    enum Encoding { CodecForTr };
     65    static QString translate(const char *, const char *sourceText, const char * = 0,
     66                             Encoding = CodecForTr, int n = -1)
     67        { return tr(sourceText, 0, n); }
     68};
     69#endif
    5470
    5571class QIODevice;
     
    6480        m_sortContexts(false),
    6581        m_noUiLines(false),
     82        m_idBased(false),
    6683        m_saveMode(SaveEverything)
    6784    {}
     
    8299public:
    83100    QString m_defaultContext;
    84     QByteArray m_codecForSource; // CPP specific
     101    QByteArray m_codecForSource; // CPP, PO & QM specific
     102    QByteArray m_outputCodec; // CPP & PO specific
     103    QString m_unTrPrefix; // QM specific
    85104    QString m_sourceFileName;
    86105    QString m_targetFileName;
    87106    QDir m_sourceDir;
    88     QDir m_targetDir; // FIXME: TS spefic
     107    QDir m_targetDir; // FIXME: TS specific
     108    QSet<QString> m_projectRoots;
     109    QMultiHash<QString, QString> m_allCSources;
     110    QStringList m_includePath;
    89111    QStringList m_dropTags;  // tags to be dropped
    90112    QStringList m_errors;
     
    93115    bool m_sortContexts;
    94116    bool m_noUiLines;
     117    bool m_idBased;
    95118    TranslatorSaveMode m_saveMode;
    96119};
     
    105128    bool release(QFile *iod, ConversionData &cd) const;
    106129
    107     bool contains(const QString &context, const QString &sourceText,
    108         const QString &comment) const;
    109     TranslatorMessage find(const QString &context,
    110         const QString &sourceText, const QString &comment) const;
    111 
     130    int find(const TranslatorMessage &msg) const;
    112131    TranslatorMessage find(const QString &context,
    113132        const QString &comment, const TranslatorMessage::References &refs) const;
     
    116135    TranslatorMessage find(const QString &context) const;
    117136
    118     void replace(const TranslatorMessage &msg);
    119137    void replaceSorted(const TranslatorMessage &msg);
    120138    void extend(const TranslatorMessage &msg); // Only for single-location messages
     
    128146    void stripIdenticalSourceTranslations();
    129147    void dropTranslations();
     148    void dropUiLines();
    130149    void makeFileNamesAbsolute(const QDir &originalPath);
    131     QSet<TranslatorMessagePtr> resolveDuplicates();
    132     static void reportDuplicates(const QSet<TranslatorMessagePtr> &dupes,
    133                                  const QString &fileName, bool verbose);
     150
     151    struct Duplicates { QSet<int> byId, byContents; };
     152    Duplicates resolveDuplicates();
     153    void reportDuplicates(const Duplicates &dupes, const QString &fileName, bool verbose);
    134154
    135155    void setCodecName(const QByteArray &name);
    136     QByteArray codecName() const { return m_codecName; }
     156    QByteArray codecName() const;
     157    QTextCodec *codec() const { return m_codec; }
    137158
    138159    QString languageCode() const { return m_language; }
    139160    QString sourceLanguageCode() const { return m_sourceLanguage; }
    140161
    141     enum LocationsType { NoLocations, RelativeLocations, AbsoluteLocations };
     162    enum LocationsType { DefaultLocations, NoLocations, RelativeLocations, AbsoluteLocations };
    142163    void setLocationsType(LocationsType lt) { m_locationsType = lt; }
    143164    LocationsType locationsType() const { return m_locationsType; }
     
    151172    QList<TranslatorMessage> messages() const;
    152173    QList<TranslatorMessage> translatedMessages() const;
    153     static QStringList normalizedTranslations(const TranslatorMessage &m,
    154         QLocale::Language lang, QLocale::Country country);
     174    static QStringList normalizedTranslations(const TranslatorMessage &m, int numPlurals);
     175    void normalizeTranslations(ConversionData &cd);
    155176    QStringList normalizedTranslations(const TranslatorMessage &m, ConversionData &cd, bool *ok) const;
    156177
     
    179200        LoadFunction loader;
    180201        SaveFunction saver;
    181         enum FileType { SourceCode, TranslationSource, TranslationBinary } fileType;
     202        enum FileType { TranslationSource, TranslationBinary } fileType;
    182203        int priority; // 0 = highest, -1 = invisible
    183204    };
     
    185206    static QList<FileFormat> &registeredFileFormats();
    186207
    187     enum VariantSeparators {
    188         DefaultVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D
    189         InternalVariantSeparator = 0x9c // unicode "STRING TERMINATOR"
     208    enum {
     209        TextVariantSeparator = 0x2762, // some weird character nobody ever heard of :-D
     210        BinaryVariantSeparator = 0x9c // unicode "STRING TERMINATOR"
    190211    };
    191212
     
    194215
    195216    TMM m_messages;
    196     QByteArray m_codecName;
     217    QTextCodec *m_codec;
    197218    LocationsType m_locationsType;
    198219
  • trunk/tools/linguist/shared/translatormessage.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 Qt Linguist 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**
     
    144144
    145145
    146 bool TranslatorMessage::operator==(const TranslatorMessage& m) const
    147 {
    148     static QString msgIdPlural = QLatin1String("po-msgid_plural");
    149 
    150     // Special treatment for context comments (empty source).
    151     return (m_context == m.m_context)
    152         && m_sourcetext == m.m_sourcetext
    153         && m_extra[msgIdPlural] == m.m_extra[msgIdPlural]
    154         && (m_sourcetext.isEmpty() || m_comment == m.m_comment);
    155 }
    156 
    157 
    158 bool TranslatorMessage::operator<(const TranslatorMessage& m) const
    159 {
    160     if (m_context != m.m_context)
    161         return m_context < m.m_context;
    162     if (m_sourcetext != m.m_sourcetext)
    163         return m_sourcetext < m.m_sourcetext;
    164     return m_comment < m.m_comment;
    165 }
    166 
    167 int qHash(const TranslatorMessage &msg)
    168 {
    169     return
    170         qHash(msg.context()) ^
    171         qHash(msg.sourceText()) ^
    172         qHash(msg.extra(QLatin1String("po-msgid_plural"))) ^
    173         qHash(msg.comment());
    174 }
    175 
    176146bool TranslatorMessage::hasExtra(const QString &key) const
    177147{
  • trunk/tools/linguist/shared/translatormessage.h

    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 Qt Linguist 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**
     
    110110    }
    111111
    112     bool operator==(const TranslatorMessage& m) const;
    113     bool operator<(const TranslatorMessage& m) const;
    114 
    115112    QString fileName() const { return m_fileName; }
    116113    void setFileName(const QString &fileName) { m_fileName = fileName; }
     
    178175Q_DECLARE_TYPEINFO(TranslatorMessage, Q_MOVABLE_TYPE);
    179176
    180 int qHash(const TranslatorMessage &msg);
    181 
    182 struct TranslatorMessagePtr {
    183     TranslatorMessagePtr(const TranslatorMessage &tm)
    184     {
    185         ptr = &tm;
    186     }
    187 
    188     inline const TranslatorMessage *operator->() const
    189     {
    190         return ptr;
    191     }
    192 
    193     const TranslatorMessage *ptr;
    194 };
    195 
    196 Q_DECLARE_TYPEINFO(TranslatorMessagePtr, Q_MOVABLE_TYPE);
    197 
    198 inline int qHash(TranslatorMessagePtr tmp)
    199 {
    200     return qHash(*tmp.ptr);
    201 }
    202 
    203 inline bool operator==(TranslatorMessagePtr tmp1, TranslatorMessagePtr tmp2)
    204 {
    205     return *tmp1.ptr == *tmp2.ptr;
    206 }
    207 
    208177QT_END_NAMESPACE
    209178
  • trunk/tools/linguist/shared/ts.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 Qt Linguist 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**
     
    198198            } else if (elementStarts(strlengthvariant)) {
    199199                if (!result.isEmpty())
    200                     result += QChar(Translator::DefaultVariantSeparator);
     200                    result += QChar(Translator::BinaryVariantSeparator);
    201201                result += readContents();
    202202            } else {
     
    515515{
    516516    int offset;
    517     if ((offset = input.indexOf(QChar(Translator::DefaultVariantSeparator))) >= 0) {
     517    if ((offset = input.indexOf(QChar(Translator::BinaryVariantSeparator))) >= 0) {
    518518        t << " variants=\"yes\">";
    519519        int start = 0;
     
    525525                break;
    526526            start = offset + 1;
    527             offset = input.indexOf(QChar(Translator::DefaultVariantSeparator), start);
     527            offset = input.indexOf(QChar(Translator::BinaryVariantSeparator), start);
    528528            if (offset < 0)
    529529                offset = input.length();
     
    694694                if (msg.isPlural()) {
    695695                    t << ">";
    696                     QStringList translns = translator.normalizedTranslations(msg, cd, &result);
    697                     for (int j = 0; j < qMax(1, translns.count()); ++j) {
     696                    const QStringList &translns = msg.translations();
     697                    for (int j = 0; j < translns.count(); ++j) {
    698698                        t << "\n            <numerusform";
    699699                        writeVariants(t, "            ", translns[j]);
  • trunk/tools/linguist/shared/ts.dtd

    r2 r561  
    3535          sourcelanguage CDATA #IMPLIED
    3636          language CDATA #IMPLIED>
    37 <!-- The encoding to use in the .qm file by default. Default is ISO-8859-1. -->
     37<!-- The encoding to use in the QM file by default. Default is ISO-8859-1. -->
    3838<!ELEMENT defaultcodec (#PCDATA) >
    3939<!ELEMENT context (name?, comment?, (context|message)+) >
     
    5555<!--
    5656 ! If utf8 is true, the defaultcodec is overridden and the message is encoded
    57  ! in UTF-8 in the .qm file.
     57 ! in UTF-8 in the QM file.
    5858  -->
    5959<!ATTLIST message
     
    7171 ! "current" is the filename used for the 1st location of the previous message.
    7272 ! For subsequent locations, it is the filename used for the previous location.
    73  ! A single .ts file has either all absolute or all relative locations.
     73 ! A single TS file has either all absolute or all relative locations.
    7474  -->
    7575<!ATTLIST location
     
    107107 ! The translation variants have a priority between 1 ("highest") and 9 ("lowest")
    108108 ! Typically longer translations get a higher priority.
    109  ! If omitted, the order of appearance of the variants in the .ts files is used.
     109 ! If omitted, the order of appearance of the variants in the TS files is used.
    110110  -->
    111111<!ATTLIST lengthvariant
  • trunk/tools/linguist/shared/xliff.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 Qt Linguist 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**
     
    244244}
    245245
    246 static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent,
    247                             const Translator &translator, ConversionData &cd, bool *ok)
     246static void writeTransUnits(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent)
    248247{
    249248    static int msgid;
    250249    QString msgidstr = !msg.id().isEmpty() ? msg.id() : QString::fromAscii("_msg%1").arg(++msgid);
    251250
    252     QStringList translns = translator.normalizedTranslations(msg, cd, ok);
     251    QStringList translns = msg.translations();
    253252    QHash<QString, QString>::const_iterator it;
    254253    QString pluralStr;
     
    304303        if (transit != transend) {
    305304            translation = *transit;
     305            translation.replace(QChar(Translator::BinaryVariantSeparator),
     306                                QChar(Translator::TextVariantSeparator));
    306307            ++transit;
    307308            puttrans = true;
     
    348349}
    349350
    350 static void writeMessage(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent,
    351                          const Translator &translator, ConversionData &cd, bool *ok)
     351static void writeMessage(QTextStream &ts, const TranslatorMessage &msg, const QRegExp &drops, int indent)
    352352{
    353353    if (msg.isPlural()) {
     
    363363        writeComment(ts, msg, drops, indent);
    364364
    365         writeTransUnits(ts, msg, drops, indent, translator, cd, ok);
     365        writeTransUnits(ts, msg, drops, indent);
    366366        --indent;
    367367        writeIndent(ts, indent);
    368368        ts << "</group>\n";
    369369    } else {
    370         writeTransUnits(ts, msg, drops, indent, translator, cd, ok);
     370        writeTransUnits(ts, msg, drops, indent);
    371371    }
    372372}
     
    501501        m_fileName = atts.value(QLatin1String("original"));
    502502        m_language = atts.value(QLatin1String("target-language"));
     503        m_language.replace(QLatin1Char('-'), QLatin1Char('_'));
    503504        m_sourceLanguage = atts.value(QLatin1String("source-language"));
     505        m_sourceLanguage.replace(QLatin1Char('-'), QLatin1Char('_'));
    504506    } else if (localName == QLatin1String("group")) {
    505507        if (atts.value(QLatin1String("restype")) == QLatin1String(restypeContext)) {
     
    599601        }
    600602    } else if (localName == QLatin1String("target")) {
    601         if (popContext(XC_restype_translation))
     603        if (popContext(XC_restype_translation)) {
     604            accum.replace(QChar(Translator::TextVariantSeparator),
     605                          QChar(Translator::BinaryVariantSeparator));
    602606            m_translations.append(accum);
     607        }
    603608    } else if (localName == QLatin1String("context-group")) {
    604609        if (popContext(XC_context_group)) {
     
    771776    ++indent;
    772777    writeExtras(ts, indent, translator.extras(), drops);
     778    QString sourceLanguageCode = translator.sourceLanguageCode();
     779    if (sourceLanguageCode.isEmpty() || sourceLanguageCode == QLatin1String("C"))
     780        sourceLanguageCode = QLatin1String("en");
     781    else
     782        sourceLanguageCode.replace(QLatin1Char('_'), QLatin1Char('-'));
     783    QString languageCode = translator.languageCode();
     784    languageCode.replace(QLatin1Char('_'), QLatin1Char('-'));
    773785    foreach (const QString &fn, fileOrder) {
    774786        writeIndent(ts, indent);
    775787        ts << "<file original=\"" << fn << "\""
    776788            << " datatype=\"" << dataType(messageOrder[fn].begin()->first()) << "\""
    777             << " source-language=\""
    778                 << (translator.sourceLanguageCode().isEmpty() ?
    779                     QByteArray("en") : translator.sourceLanguageCode().toLatin1()) << "\""
    780             << " target-language=\"" << translator.languageCode() << "\""
     789            << " source-language=\"" << sourceLanguageCode.toLatin1() << "\""
     790            << " target-language=\"" << languageCode.toLatin1() << "\""
    781791            << "><body>\n";
    782792        ++indent;
     
    791801
    792802            foreach (const TranslatorMessage &msg, messageOrder[fn][ctx])
    793                 writeMessage(ts, msg, drops, indent, translator, cd, &ok);
     803                writeMessage(ts, msg, drops, indent);
    794804
    795805            if (!ctx.isEmpty()) {
Note: See TracChangeset for help on using the changeset viewer.