Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++ #include <translator.h>
++ #include "xmlparser.h"
++
++ #include <QtCore/QCoreApplication>
++ #include <QtCore/QDebug>
++ #include <QtCore/QFile>
++ #include <QtCore/QString>
++ #include <QtCore/QXmlStreamReader>
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace Qt::StringLiterals;
++
++ class UiReader : public XmlParser
++ {
++ public:
++ UiReader(Translator &translator, ConversionData &cd, QXmlStreamReader &reader)
++ : XmlParser(reader),
++ m_translator(translator),
++ m_cd(cd),
++ m_lineNumber(-1),
++ m_isTrString(false),
++ m_insideStringList(false)
++ {
++ }
++ ~UiReader() override = default;
++
++ private:
++ bool startElement(QStringView namespaceURI, QStringView localName,
++ QStringView qName, const QXmlStreamAttributes &atts) override;
++ bool endElement(QStringView namespaceURI, QStringView localName,
++ QStringView qName) override;
++ bool characters(QStringView ch) override;
++ bool fatalError(qint64 line, qint64 column, const QString &message) override;
++
++ void flush();
++ void readTranslationAttributes(const QXmlStreamAttributes &atts);
++
++ Translator &m_translator;
++ ConversionData &m_cd;
++ QString m_context;
++ QString m_source;
++ QString m_comment;
++ QString m_extracomment;
++ QString m_id;
++ QString m_label;
++
++ QString m_accum;
++ int m_lineNumber;
++ bool m_isTrString;
++ bool m_insideStringList;
++ };
++
++ bool UiReader::startElement(QStringView namespaceURI, QStringView localName,
++ QStringView qName, const QXmlStreamAttributes &atts)
++ {
++ Q_UNUSED(namespaceURI);
++ Q_UNUSED(localName);
++
++ if (qName == "string"_L1) {
++ flush();
++ if (!m_insideStringList)
++ readTranslationAttributes(atts);
++ } else if (qName == "stringlist"_L1) {
++ flush();
++ m_insideStringList = true;
++ readTranslationAttributes(atts);
++ } else if (qName == "ui"_L1) {
++ m_label = QString(atts.value("label"));
++ }
++ m_accum.clear();
++ return true;
++ }
++
++ bool UiReader::endElement(QStringView namespaceURI, QStringView localName,
++ QStringView qName)
++ {
++ Q_UNUSED(namespaceURI);
++ Q_UNUSED(localName);
++
++ m_accum.replace("\r\n"_L1, "\n"_L1);
++
++ if (qName == "class"_L1) { // UI "header"
++ if (m_context.isEmpty())
++ m_context = m_accum;
++ } else if (qName == "string"_L1 && m_isTrString) {
++ m_source = m_accum;
++ } else if (qName == "comment"_L1) { // FIXME: what's that?
++ m_comment = m_accum;
++ flush();
++ } else if (qName == "stringlist"_L1) {
++ m_insideStringList = false;
++ } else {
++ flush();
++ }
++ return true;
++ }
++
++ bool UiReader::characters(QStringView ch)
++ {
++ m_accum += ch.toString();
++ return true;
++ }
++
++ bool UiReader::fatalError(qint64 line, qint64 column, const QString &message)
++ {
++ QString msg = QStringLiteral("XML error: Parse error at line %1, column %2 (%3).")
++ .arg(line)
++ .arg(column)
++ .arg(message);
++ m_cd.appendError(msg);
++ return false;
++ }
++
++ void UiReader::flush()
++ {
++ if ((!m_context.isEmpty() || !m_id.isEmpty()) && !m_source.isEmpty()) {
++ TranslatorMessage msg(m_context, m_source,
++ m_comment, QString(), m_cd.m_sourceFileName,
++ m_lineNumber, QStringList());
++ msg.setExtraComment(m_extracomment);
++ msg.setLabel(m_label);
++ msg.setId(m_id);
++ if (!m_id.isEmpty())
++ msg.setContext({});
++ m_translator.extend(msg, m_cd);
++ }
++ m_source.clear();
++ if (!m_insideStringList) {
++ m_comment.clear();
++ m_extracomment.clear();
++ m_id.clear();
++ }
++ }
++
++ void UiReader::readTranslationAttributes(const QXmlStreamAttributes &atts)
++ {
++ const auto notr = atts.value(QStringLiteral("notr"));
++ if (notr.isEmpty() || notr != QStringLiteral("true")) {
++ m_isTrString = true;
++ m_comment = atts.value(QStringLiteral("comment")).toString();
++ m_extracomment = atts.value(QStringLiteral("extracomment")).toString();
++ m_id = atts.value(QStringLiteral("id")).toString();
++ if (m_id.isEmpty())
++ m_label.clear();
++ if (!m_cd.m_noUiLines)
++ m_lineNumber = static_cast<int>(reader.lineNumber());
++ } else {
++ m_isTrString = false;
++ }
++ }
++
++ bool loadUI(Translator &translator, const QString &filename, ConversionData &cd)
++ {
++ cd.m_sourceFileName = filename;
++ QFile file(filename);
++ if (!file.open(QIODevice::ReadOnly)) {
++ cd.appendError("Cannot open %1: %2"_L1.arg(filename, file.errorString()));
++ return false;
++ }
++
++ QXmlStreamReader reader(&file);
++ reader.setNamespaceProcessing(false);
++
++ UiReader uiReader(translator, cd, reader);
++ bool result = uiReader.parse();
++ if (!result)
++ cd.appendError(u"Parse error in UI file"_s);
++ return result;
++ }
++
++ QT_END_NAMESPACE