Migrate from QRegExp to more modern QRegularExpression

7220-lua-add-a-general-purpose-lexical-parser
Andrei Kortunov 2 years ago
parent 7c078883d5
commit 307a60e87c

@ -205,11 +205,12 @@ void Launcher::GraphicsPage::saveSettings()
int cHeight = 0;
if (standardRadioButton->isChecked())
{
QRegExp resolutionRe(QString("(\\d+) x (\\d+).*"));
if (resolutionRe.exactMatch(resolutionComboBox->currentText().simplified()))
QRegularExpression resolutionRe(QRegularExpression::anchoredPattern(QString("(\\d+) x (\\d+).*")));
QRegularExpressionMatch match = resolutionRe.match(resolutionComboBox->currentText().simplified());
if (match.hasMatch())
{
cWidth = resolutionRe.cap(1).toInt();
cHeight = resolutionRe.cap(2).toInt();
cWidth = match.captured(1).toInt();
cHeight = match.captured(2).toInt();
}
}
else

@ -20,7 +20,8 @@ Launcher::TextInputDialog::TextInputDialog(const QString& title, const QString&
label->setText(text);
// Line edit
QValidator* validator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
QValidator* validator
= new QRegularExpressionValidator(QRegularExpression("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
mLineEdit = new LineEdit(this);
mLineEdit->setValidator(validator);
mLineEdit->setCompleter(nullptr);

@ -4,6 +4,7 @@
#include <QLocalServer>
#include <QLocalSocket>
#include <QMessageBox>
#include <QRegularExpression>
#include <boost/program_options.hpp>
@ -362,7 +363,7 @@ bool CS::Editor::makeIPCServer()
mServer->listen("dummy");
QString fullPath = mServer->fullServerName();
mServer->close();
fullPath.remove(QRegExp("dummy$"));
fullPath.remove(QRegularExpression("dummy$"));
fullPath += mIpcServerName;
const auto path = Files::pathFromQString(fullPath);
if (exists(path))

@ -5,7 +5,7 @@
#include <stdexcept>
#include <utility>
#include <QRegExp>
#include <QRegularExpression>
#include "../world/columns.hpp"
#include "../world/idtablebase.hpp"
@ -57,9 +57,11 @@ bool CSMFilter::TextNode::test(const CSMWorld::IdTableBase& table, int row, cons
return false;
/// \todo make pattern syntax configurable
QRegExp regExp(QString::fromUtf8(mText.c_str()), Qt::CaseInsensitive);
QRegularExpression regExp(QRegularExpression::anchoredPattern(QString::fromUtf8(mText.c_str())),
QRegularExpression::CaseInsensitiveOption);
QRegularExpressionMatch match = regExp.match(string);
return regExp.exactMatch(string);
return match.hasMatch();
}
std::vector<int> CSMFilter::TextNode::getReferencedColumns() const

@ -1,7 +1,7 @@
#include "search.hpp"
#include <QModelIndex>
#include <QRegExp>
#include <QRegularExpression>
#include <QString>
#include <memory>
@ -49,10 +49,12 @@ void CSMTools::Search::searchRegExCell(const CSMWorld::IdTableBase* model, const
QString text = model->data(index).toString();
int pos = 0;
QRegularExpressionMatch match;
while ((pos = mRegExp.indexIn(text, pos)) != -1)
while ((match = mRegExp.match(text, pos)).hasMatch())
{
int length = mRegExp.matchedLength();
pos = match.capturedStart();
int length = match.capturedLength();
std::ostringstream hint;
hint << (writable ? 'R' : 'r') << ": " << model->getColumnId(index.column()) << " " << pos << " " << length;
@ -138,7 +140,7 @@ CSMTools::Search::Search(Type type, bool caseSensitive, const std::string& value
throw std::logic_error("Invalid search parameter (string)");
}
CSMTools::Search::Search(Type type, bool caseSensitive, const QRegExp& value)
CSMTools::Search::Search(Type type, bool caseSensitive, const QRegularExpression& value)
: mType(type)
, mRegExp(value)
, mValue(0)
@ -148,7 +150,7 @@ CSMTools::Search::Search(Type type, bool caseSensitive, const QRegExp& value)
, mPaddingBefore(10)
, mPaddingAfter(10)
{
mRegExp.setCaseSensitivity(mCase ? Qt::CaseSensitive : Qt::CaseInsensitive);
mRegExp.setPatternOptions(mCase ? QRegularExpression::NoPatternOption : QRegularExpression::CaseInsensitiveOption);
if (type != Type_TextRegEx && type != Type_IdRegEx)
throw std::logic_error("Invalid search parameter (RegExp)");
}

@ -5,7 +5,7 @@
#include <string>
#include <QMetaType>
#include <QRegExp>
#include <QRegularExpression>
class QModelIndex;
@ -39,7 +39,7 @@ namespace CSMTools
private:
Type mType;
std::string mText;
QRegExp mRegExp;
QRegularExpression mRegExp;
int mValue;
bool mCase;
std::set<int> mColumns;
@ -66,7 +66,7 @@ namespace CSMTools
Search(Type type, bool caseSensitive, const std::string& value);
Search(Type type, bool caseSensitive, const QRegExp& value);
Search(Type type, bool caseSensitive, const QRegularExpression& value);
Search(Type type, bool caseSensitive, int value);

@ -3,8 +3,6 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QRegExp>
#include <QRegExpValidator>
QString CSVDoc::FileWidget::getExtension() const
{

@ -6,6 +6,7 @@
#include <QApplication>
#include <QContextMenuEvent>
#include <QMenu>
#include <QRegularExpression>
#include <QString>
#include <apps/opencs/model/filter/parser.hpp>
@ -136,8 +137,9 @@ void CSVFilter::EditWidget::createFilterRequest(
}
if (oldContent.isEmpty()
|| !oldContent.contains(QRegExp("^!.*$",
Qt::CaseInsensitive))) // if line edit is empty or it does not contain one shot filter go into replace mode
|| !oldContent.contains(QRegularExpression("^!.*$",
QRegularExpression::CaseInsensitiveOption))) // if line edit is empty or it does not contain one shot filter
// go into replace mode
{
replaceMode = true;
}

@ -112,7 +112,8 @@ CSMTools::Search CSVTools::SearchBox::getSearch() const
case CSMTools::Search::Type_TextRegEx:
case CSMTools::Search::Type_IdRegEx:
return CSMTools::Search(type, caseSensitive, QRegExp(mText.text().toUtf8().data(), Qt::CaseInsensitive));
return CSMTools::Search(type, caseSensitive,
QRegularExpression(mText.text().toUtf8().data(), QRegularExpression::CaseInsensitiveOption));
case CSMTools::Search::Type_RecordState:

@ -55,7 +55,7 @@ CSVWorld::ScriptEdit::ScriptEdit(const CSMDoc::Document& document, ScriptHighlig
, mTabCharCount(4)
, mMarkOccurrences(true)
, mDocument(document)
, mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive)
, mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", QRegularExpression::CaseInsensitiveOption)
{
wrapLines(false);
setTabWidth();
@ -186,7 +186,7 @@ void CSVWorld::ScriptEdit::dropEvent(QDropEvent* event)
bool CSVWorld::ScriptEdit::stringNeedsQuote(const std::string& id) const
{
const QString string(QString::fromUtf8(id.c_str())); //<regex> is only for c++11, so let's use qregexp for now.
const QString string(QString::fromUtf8(id.c_str()));
// I'm not quite sure when do we need to put quotes. To be safe we will use quotes for anything other than…
return !(string.contains(mWhiteListQoutes));
}

@ -3,7 +3,7 @@
#include <QFont>
#include <QPlainTextEdit>
#include <QRegExp>
#include <QRegularExpression>
#include <QTimer>
#include <QVector>
#include <QWidget>
@ -95,7 +95,7 @@ namespace CSVWorld
private:
QVector<CSMWorld::UniversalId::Type> mAllowedTypes;
const CSMDoc::Document& mDocument;
const QRegExp mWhiteListQoutes;
const QRegularExpression mWhiteListQoutes;
void dragEnterEvent(QDragEnterEvent* event) override;

@ -2,7 +2,7 @@
#include <QDebug>
#include <QFile>
#include <QRegExp>
#include <QRegularExpression>
#include <QString>
#include <QStringList>
#include <QTextStream>
@ -30,12 +30,12 @@ bool Wizard::IniSettings::readFile(QTextStream& stream)
// Look for a square bracket, "'\\["
// that has one or more "not nothing" in it, "([^]]+)"
// and is closed with a square bracket, "\\]"
QRegExp sectionRe(QLatin1String("^\\[([^]]+)\\]"));
QRegularExpression sectionRe(QRegularExpression::anchoredPattern("^\\[([^]]+)\\]"));
// Find any character(s) that is/are not equal sign(s), "[^=]+"
// followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
// and one or more periods, "(.+)"
QRegExp keyRe(QLatin1String("^([^=]+)\\s*=\\s*(.+)$"));
QRegularExpression keyRe(QLatin1String("^([^=]+)\\s*=\\s*(.+)$"));
QString currentSection;
@ -46,14 +46,18 @@ bool Wizard::IniSettings::readFile(QTextStream& stream)
if (line.isEmpty() || line.startsWith(QLatin1Char(';')))
continue;
if (sectionRe.exactMatch(line))
QRegularExpressionMatch sectionMatch = sectionRe.match(line);
if (sectionMatch.hasMatch())
{
currentSection = sectionRe.cap(1);
currentSection = sectionMatch.captured(1);
continue;
}
else if (keyRe.indexIn(line) != -1)
QRegularExpressionMatch match = keyRe.match(line);
if (match.hasMatch())
{
QString key = keyRe.cap(1).trimmed();
QString value = keyRe.cap(2).trimmed();
QString key = match.captured(1).trimmed();
QString value = match.captured(2).trimmed();
// Append the section, but only if there is one
if (!currentSection.isEmpty())
@ -71,12 +75,12 @@ bool Wizard::IniSettings::writeFile(const QString& path, QTextStream& stream)
// Look for a square bracket, "'\\["
// that has one or more "not nothing" in it, "([^]]+)"
// and is closed with a square bracket, "\\]"
QRegExp sectionRe(QLatin1String("^\\[([^]]+)\\]"));
QRegularExpression sectionRe(QRegularExpression::anchoredPattern("^\\[([^]]+)\\]"));
// Find any character(s) that is/are not equal sign(s), "[^=]+"
// followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
// and one or more periods, "(.+)"
QRegExp keyRe(QLatin1String("^([^=]+)\\s*=\\s*(.+)$"));
QRegularExpression keyRe(QLatin1String("^([^=]+)\\s*=\\s*(.+)$"));
const QStringList keys(mSettings.keys());
@ -85,7 +89,6 @@ bool Wizard::IniSettings::writeFile(const QString& path, QTextStream& stream)
while (!stream.atEnd())
{
const QString line(stream.readLine());
if (line.isEmpty() || line.startsWith(QLatin1Char(';')))
@ -94,14 +97,18 @@ bool Wizard::IniSettings::writeFile(const QString& path, QTextStream& stream)
continue;
}
if (sectionRe.exactMatch(line))
QRegularExpressionMatch sectionMatch = sectionRe.match(line);
if (sectionMatch.hasMatch())
{
buffer.append(line + QLatin1String("\n"));
currentSection = sectionRe.cap(1);
currentSection = sectionMatch.captured(1);
continue;
}
else if (keyRe.indexIn(line) != -1)
QRegularExpressionMatch match = keyRe.match(line);
if (match.hasMatch())
{
QString key(keyRe.cap(1).trimmed());
QString key(match.captured(1).trimmed());
QString lookupKey(key);
// Append the section, but only if there is one

@ -2,7 +2,7 @@
#include "launchersettings.hpp"
#include <QDir>
#include <QRegExp>
#include <QRegularExpression>
#include <QTextCodec>
#include <components/files/configurationmanager.hpp>
@ -90,7 +90,7 @@ bool Config::GameSettings::readUserFile(QTextStream& stream, bool ignoreContent)
bool Config::GameSettings::readFile(QTextStream& stream, QMultiMap<QString, QString>& settings, bool ignoreContent)
{
QMultiMap<QString, QString> cache;
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
QRegularExpression keyRe("^([^=]+)\\s*=\\s*(.+)$");
while (!stream.atEnd())
{
@ -99,11 +99,11 @@ bool Config::GameSettings::readFile(QTextStream& stream, QMultiMap<QString, QStr
if (line.isEmpty() || line.startsWith("#"))
continue;
if (keyRe.indexIn(line) != -1)
QRegularExpressionMatch match = keyRe.match(line);
if (match.hasMatch())
{
QString key = keyRe.cap(1).trimmed();
QString value = keyRe.cap(2).trimmed();
QString key = match.captured(1).trimmed();
QString value = match.captured(2).trimmed();
// Don't remove composing entries
if (key != QLatin1String("data") && key != QLatin1String("fallback-archive")
@ -206,10 +206,13 @@ bool Config::GameSettings::writeFile(QTextStream& stream)
bool Config::GameSettings::isOrderedLine(const QString& line)
{
return line.contains(QRegExp("^\\s*fallback-archive\\s*=")) || line.contains(QRegExp("^\\s*fallback\\s*="))
|| line.contains(QRegExp("^\\s*data\\s*=")) || line.contains(QRegExp("^\\s*data-local\\s*="))
|| line.contains(QRegExp("^\\s*resources\\s*=")) || line.contains(QRegExp("^\\s*groundcover\\s*="))
|| line.contains(QRegExp("^\\s*content\\s*="));
return line.contains(QRegularExpression("^\\s*fallback-archive\\s*="))
|| line.contains(QRegularExpression("^\\s*fallback\\s*="))
|| line.contains(QRegularExpression("^\\s*data\\s*="))
|| line.contains(QRegularExpression("^\\s*data-local\\s*="))
|| line.contains(QRegularExpression("^\\s*resources\\s*="))
|| line.contains(QRegularExpression("^\\s*groundcover\\s*="))
|| line.contains(QRegularExpression("^\\s*content\\s*="));
}
// Policy:
@ -268,7 +271,7 @@ bool Config::GameSettings::writeFileWithComments(QFile& file)
// +----------------------------------------------------------+
//
//
QRegExp settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$");
QRegularExpression settingRegex("^([^=]+)\\s*=\\s*([^,]+)(.*)$");
std::vector<QString> comments;
auto commentStart = fileCopy.end();
std::map<QString, std::vector<QString>> commentsMap;
@ -279,9 +282,10 @@ bool Config::GameSettings::writeFileWithComments(QFile& file)
// save in a separate map of comments keyed by "ordered" line
if (!comments.empty())
{
if (settingRegex.indexIn(*iter) != -1)
QRegularExpressionMatch match = settingRegex.match(*iter);
if (match.hasMatch())
{
commentsMap[settingRegex.cap(1) + "=" + settingRegex.cap(2)] = comments;
commentsMap[match.captured(1) + "=" + match.captured(2)] = comments;
comments.clear();
commentStart = fileCopy.end();
}
@ -290,14 +294,14 @@ bool Config::GameSettings::writeFileWithComments(QFile& file)
*iter = QString(); // "ordered" lines to be removed later
}
else if ((*iter).isEmpty() || (*iter).contains(QRegExp("^\\s*#")))
else if ((*iter).isEmpty() || (*iter).contains(QRegularExpression("^\\s*#")))
{
// comment line, save in temp buffer
if (comments.empty())
commentStart = iter;
// special removed content processing
if ((*iter).contains(QRegExp("^##content\\s*=")))
if ((*iter).contains(QRegularExpression("^##content\\s*=")))
{
if (!comments.empty())
{
@ -313,11 +317,11 @@ bool Config::GameSettings::writeFileWithComments(QFile& file)
}
else
{
int index = settingRegex.indexIn(*iter);
QRegularExpressionMatch match = settingRegex.match(*iter);
// blank or non-"ordered" line, write saved comments
if (!comments.empty() && index != -1 && settingRegex.captureCount() >= 2
&& mUserSettings.find(settingRegex.cap(1)) != mUserSettings.end())
if (!comments.empty() && match.hasMatch() && settingRegex.captureCount() >= 2
&& mUserSettings.find(match.captured(1)) != mUserSettings.end())
{
if (commentStart == fileCopy.end())
throw std::runtime_error(
@ -335,10 +339,10 @@ bool Config::GameSettings::writeFileWithComments(QFile& file)
// keep blank lines and non-"ordered" lines other than comments
// look for a key in the line
if (index == -1 || settingRegex.captureCount() < 2)
if (!match.hasMatch() || settingRegex.captureCount() < 2)
{
// no key or first part of value found in line, replace with a null string which
// will be remved later
// will be removed later
*iter = QString();
comments.clear();
commentStart = fileCopy.end();
@ -347,15 +351,16 @@ bool Config::GameSettings::writeFileWithComments(QFile& file)
// look for a matching key in user settings
*iter = QString(); // assume no match
QString key = settingRegex.cap(1);
QString keyVal = settingRegex.cap(1) + "=" + settingRegex.cap(2);
QString key = match.captured(1);
QString keyVal = match.captured(1) + "=" + match.captured(2);
QMultiMap<QString, QString>::const_iterator i = mUserSettings.find(key);
while (i != mUserSettings.end() && i.key() == key)
{
QString settingLine = i.key() + "=" + i.value();
if (settingRegex.indexIn(settingLine) != -1)
QRegularExpressionMatch keyMatch = settingRegex.match(settingLine);
if (keyMatch.hasMatch())
{
if ((settingRegex.cap(1) + "=" + settingRegex.cap(2)) == keyVal)
if ((keyMatch.captured(1) + "=" + keyMatch.captured(2)) == keyVal)
{
*iter = settingLine;
break;
@ -374,7 +379,7 @@ bool Config::GameSettings::writeFileWithComments(QFile& file)
// Below is based on readFile() code, if that changes corresponding change may be
// required (for example duplicates may be inserted if the rules don't match)
if (/*(*iter).isEmpty() ||*/ iter.contains(QRegExp("^\\s*#")))
if (/*(*iter).isEmpty() ||*/ iter.contains(QRegularExpression("^\\s*#")))
{
stream << iter << "\n";
continue;
@ -413,13 +418,14 @@ bool Config::GameSettings::writeFileWithComments(QFile& file)
else
settingLine = it.key() + "=" + it.value();
if (settingRegex.indexIn(settingLine) != -1)
QRegularExpressionMatch match = settingRegex.match(settingLine);
if (match.hasMatch())
{
auto i = commentsMap.find(settingRegex.cap(1) + "=" + settingRegex.cap(2));
auto i = commentsMap.find(match.captured(1) + "=" + match.captured(2));
// check if previous removed content item with comments
if (i == commentsMap.end())
i = commentsMap.find("##" + settingRegex.cap(1) + "=" + settingRegex.cap(2));
i = commentsMap.find("##" + match.captured(1) + "=" + match.captured(2));
if (i != commentsMap.end())
{
@ -440,7 +446,7 @@ bool Config::GameSettings::writeFileWithComments(QFile& file)
auto i = commentsMap.begin();
for (; i != commentsMap.end(); ++i)
{
if (i->first.contains(QRegExp("^\\s*content\\s*=")))
if (i->first.contains(QRegularExpression("^\\s*content\\s*=")))
{
std::vector<QString> cLines = i->second;
for (const auto& cLine : cLines)

@ -1,12 +1,11 @@
#include "launchersettings.hpp"
#include <QDebug>
#include <QMultiMap>
#include <QRegExp>
#include <QRegularExpression>
#include <QString>
#include <QTextStream>
#include <QDebug>
#include <components/files/qtconversion.hpp>
const char Config::LauncherSettings::sCurrentContentListKey[] = "Profiles/currentprofile";
@ -21,16 +20,16 @@ QStringList Config::LauncherSettings::subKeys(const QString& key)
QMultiMap<QString, QString> settings = SettingsBase::getSettings();
QStringList keys = settings.uniqueKeys();
QRegExp keyRe("(.+)/");
QRegularExpression keyRe("(.+)/");
QStringList result;
for (const QString& currentKey : keys)
{
if (keyRe.indexIn(currentKey) != -1)
QRegularExpressionMatch match = keyRe.match(currentKey);
if (match.hasMatch())
{
QString prefixedKey = keyRe.cap(1);
QString prefixedKey = match.captured(1);
if (prefixedKey.startsWith(key))
{
@ -48,7 +47,7 @@ QStringList Config::LauncherSettings::subKeys(const QString& key)
bool Config::LauncherSettings::writeFile(QTextStream& stream)
{
QString sectionPrefix;
QRegExp sectionRe("([^/]+)/(.+)$");
QRegularExpression sectionRe(QRegularExpression::anchoredPattern("([^/]+)/(.+)$"));
QMultiMap<QString, QString> settings = SettingsBase::getSettings();
QMapIterator<QString, QString> i(settings);
@ -61,10 +60,11 @@ bool Config::LauncherSettings::writeFile(QTextStream& stream)
QString prefix;
QString key;
if (sectionRe.exactMatch(i.key()))
QRegularExpressionMatch match = sectionRe.match(i.key());
if (match.hasMatch())
{
prefix = sectionRe.cap(1);
key = sectionRe.cap(2);
prefix = match.captured(1);
key = match.captured(2);
}
// Get rid of legacy settings

@ -1,7 +1,7 @@
#ifndef SETTINGSBASE_HPP
#define SETTINGSBASE_HPP
#include <QRegExp>
#include <QRegularExpression>
#include <QString>
#include <QStringList>
#include <QTextStream>
@ -42,8 +42,8 @@ namespace Config
QString sectionPrefix;
QRegExp sectionRe("^\\[([^]]+)\\]");
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
QRegularExpression sectionRe(QRegularExpression::anchoredPattern("^\\[([^]]+)\\]"));
QRegularExpression keyRe("^([^=]+)\\s*=\\s*(.+)$");
while (!stream.atEnd())
{
@ -52,18 +52,19 @@ namespace Config
if (line.isEmpty() || line.startsWith("#"))
continue;
if (sectionRe.exactMatch(line))
QRegularExpressionMatch sectionMatch = sectionRe.match(line);
if (sectionMatch.hasMatch())
{
sectionPrefix = sectionRe.cap(1);
sectionPrefix = sectionMatch.captured(1);
sectionPrefix.append("/");
continue;
}
if (keyRe.indexIn(line) != -1)
QRegularExpressionMatch match = keyRe.match(line);
if (match.hasMatch())
{
QString key = keyRe.cap(1).trimmed();
QString value = keyRe.cap(2).trimmed();
QString key = match.captured(1).trimmed();
QString value = match.captured(2).trimmed();
if (!sectionPrefix.isEmpty())
key.prepend(sectionPrefix);

@ -8,7 +8,8 @@
ContentSelectorView::ComboBox::ComboBox(QWidget* parent)
: QComboBox(parent)
{
mValidator = new QRegExpValidator(QRegExp("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
mValidator
= new QRegularExpressionValidator(QRegularExpression("^[a-zA-Z0-9_]*$"), this); // Alpha-numeric + underscore
setValidator(mValidator);
setEditable(true);
setCompleter(nullptr);

@ -4,7 +4,7 @@
#include <QComboBox>
class QString;
class QRegExpValidator;
class QRegularExpressionValidator;
namespace ContentSelectorView
{
@ -22,7 +22,7 @@ namespace ContentSelectorView
protected:
void paintEvent(QPaintEvent*) override;
QRegExpValidator* mValidator;
QRegularExpressionValidator* mValidator;
};
}

@ -59,7 +59,7 @@ void ContentSelectorView::ContentSelector::buildAddonView()
ui.addonView->setVisible(true);
mAddonProxyModel = new AddOnProxyModel(this);
mAddonProxyModel->setFilterRegExp(searchFilter()->text());
mAddonProxyModel->setFilterRegularExpression(searchFilter()->text());
mAddonProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
mAddonProxyModel->setDynamicSortFilter(true);
mAddonProxyModel->setSourceModel(mContentModel);

Loading…
Cancel
Save