<NME> ctextviewerwindow.cpp
<BEF> #include "ctextviewerwindow.h"
#include "ctextencodingdetector.h"
#include "widgets/cpersistentwindow.h"
#include "assert/advanced_assert.h"

DISABLE_COMPILER_WARNINGS
#include <QActionGroup>
#include <QFileDialog>
#include <QLabel>
#include <QMimeDatabase>
#include <QMessageBox>
#include <QRegularExpression>
#include <QShortcut>
#include <QStringBuilder>
#include <QTextCodec>
RESTORE_COMPILER_WARNINGS
{
	ui->setupUi(this);

	connect(ui->actionOpen, &QAction::triggered, [this](){
		const QString fileName = QFileDialog::getOpenFileName(this);
		if (!fileName.isEmpty())
			loadTextFile(fileName);
	});
	connect(ui->actionReload, &QAction::triggered, [this](){
		loadTextFile(_sourceFilePath);
	});
	connect(ui->actionClose, SIGNAL(triggered()), SLOT(close()));

	connect(ui->actionFind, &QAction::triggered, [this](){
		_findDialog.exec();
	});
	connect(ui->actionFind_next, SIGNAL(triggered()), SLOT(findNext()));
	installEventFilter(new CPersistenceEnabler("Plugins/TextViewer/Window", this));

	setCentralWidget(&_textBrowser);
	_textBrowser.setReadOnly(true);
	_textBrowser.setUndoRedoEnabled(false);
	_textBrowser.setWordWrapMode(QTextOption::NoWrap);
	_textBrowser.setTabStopDistance(static_cast<qreal>(4 * _textBrowser.fontMetrics().horizontalAdvance(' ')));

	assert_r(connect(actionOpen, &QAction::triggered, [this]() {
		const QString fileName = QFileDialog::getOpenFileName(this);
		if (!fileName.isEmpty())
			loadTextFile(fileName);
	}));

	assert_r(connect(actionReload, &QAction::triggered, [this]() {
		loadTextFile(_sourceFilePath);
	}));
	assert_r(connect(actionClose, &QAction::triggered, this, &QDialog::close));

	assert_r(connect(actionFind, &QAction::triggered, [this]() {
		_findDialog.exec();
	}));
	assert_r(connect(actionFind_next, &QAction::triggered, this, &CTextViewerWindow::findNext));

	assert_r(connect(actionAuto_detect_encoding, &QAction::triggered, this, &CTextViewerWindow::asDetectedAutomatically));
	assert_r(connect(actionASCII_Windows_1252, &QAction::triggered, this, &CTextViewerWindow::asAscii));
	assert_r(connect(actionSystemLocale, &QAction::triggered, this, &CTextViewerWindow::asSystemDefault));
	assert_r(connect(actionUTF_8, &QAction::triggered, this, &CTextViewerWindow::asUtf8));
	assert_r(connect(actionUTF_16, &QAction::triggered, this, &CTextViewerWindow::asUtf16));
	assert_r(connect(actionHTML_RTF, &QAction::triggered, this, &CTextViewerWindow::asRichText));

	QActionGroup * group = new QActionGroup(this);
	group->addAction(actionASCII_Windows_1252);
	group->addAction(actionSystemLocale);
	group->addAction(actionUTF_8);
	group->addAction(actionUTF_16);
	group->addAction(actionHTML_RTF);

	assert_r(connect(&_findDialog, &CFindDialog::find, this, &CTextViewerWindow::find));
	assert_r(connect(&_findDialog, &CFindDialog::findNext, this, &CTextViewerWindow::findNext));

	auto escScut = new QShortcut(QKeySequence("Esc"), this, SLOT(close()));
	assert_r(connect(this, &QObject::destroyed, escScut, &QShortcut::deleteLater));

	_encodingLabel = new QLabel(this);
	QMainWindow::statusBar()->addWidget(_encodingLabel);
}

bool CTextViewerWindow::loadTextFile(const QString& file)
{
	setWindowTitle(file);
	_sourceFilePath = file;

	const QString fileType = QMimeDatabase().mimeTypeForFile(_sourceFilePath, QMimeDatabase::MatchContent).name();

	try
	{
		if (_sourceFilePath.endsWith(".htm", Qt::CaseInsensitive) || _sourceFilePath.endsWith(".html", Qt::CaseInsensitive) || _sourceFilePath.endsWith(".rtf", Qt::CaseInsensitive))
			return asRichText();
		else if (fileType.contains("text") || fileType.isEmpty())
			return asDetectedAutomatically();
		else
			return asAscii();
	}
	catch (const std::bad_alloc&)
	{
		QMessageBox::warning(this, "File is too large", "The text is too large to display");
		return false;
	}
}

bool CTextViewerWindow::asDetectedAutomatically()
{
	QTextCodec::ConverterState state;
	QTextCodec *codec = QTextCodec::codecForName("UTF-8");
	if (!codec)
		return false;

	QByteArray textData;
	if (!readSource(textData))
	{
		QMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\n\n%1\n\nIt is inaccessible or doesn't exist.").arg(_sourceFilePath));
		return false;
	}

	QString text(codec->toUnicode(textData.constData(), static_cast<int>(textData.size()), &state));
	if (state.invalidChars > 0)
	{
		const auto result = CTextEncodingDetector::decode(textData);
		text = result.text;
		if (!text.isEmpty())
		{
			encodingChanged(result.encoding, result.language);
			_textBrowser.setPlainText(text);
		}
		else
			return asSystemDefault();
	}
	else
	{
		encodingChanged("UTF-8");
		actionUTF_8->setChecked(true);
		_textBrowser.setPlainText(text);
	}

	return true;
}

bool CTextViewerWindow::asSystemDefault()
{
	QTextCodec * codec = QTextCodec::codecForLocale();
	if (!codec)
		return false;

	QByteArray textData;
	if (!readSource(textData))
	{
		QMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\n\n%1\n\nIt is inaccessible or doesn't exist.").arg(_sourceFilePath));
		return false;
	}

	_textBrowser.setPlainText(codec->toUnicode(textData));
	encodingChanged(codec->name());
	actionSystemLocale->setChecked(true);

	return true;
}

bool CTextViewerWindow::asAscii()
{
	QTextCodec* codec = QTextCodec::codecForName("Windows-1252");
	if (!codec)
		return false;

	QByteArray textData;
	if (!readSource(textData))
	{
		QMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\n\n%1\n\nIt is inaccessible or doesn't exist.").arg(_sourceFilePath));
		return false;
	}

	_textBrowser.setPlainText(codec->toUnicode(textData));
	encodingChanged(codec->name());
	actionASCII_Windows_1252->setChecked(true);

	return true;
}

bool CTextViewerWindow::asUtf8()
{
	QByteArray textData;
	if (!readSource(textData))
	{
		QMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\n\n%1\n\nIt is inaccessible or doesn't exist.").arg(_sourceFilePath));
		return false;
	}

	encodingChanged("UTF-8");
	_textBrowser.setPlainText(QString::fromUtf8(textData));
	actionUTF_8->setChecked(true);

	return true;
}

bool CTextViewerWindow::asUtf16()
{
	QByteArray textData;
	if (!readSource(textData))
	{
		QMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\n\n%1\n\nIt is inaccessible or doesn't exist.").arg(_sourceFilePath));
		return false;
	}

	encodingChanged("UTF-16");
	static_assert (std::is_trivially_copyable_v<QChar>);
	QString text;
	text.resize(textData.size() / 2 + 1, QChar{'\0'});
	memcpy(text.data(), textData.constData(), static_cast<size_t>(textData.size()));
	_textBrowser.setPlainText(std::move(text));
	actionUTF_16->setChecked(true);

	return true;
}

bool CTextViewerWindow::asRichText()
{
	// TODO: add RTF support
	return asDetectedAutomatically();
}

void CTextViewerWindow::find()
{
	_textBrowser.moveCursor(_findDialog.searchBackwards() ? QTextCursor::End : QTextCursor::Start);
	findNext();
}

void CTextViewerWindow::findNext()
{
	const QString expression = _findDialog.searchExpression();
	if (expression.isEmpty())
		return;

	QTextDocument::FindFlags flags {};
	if (_findDialog.caseSensitive())
		flags |= QTextDocument::FindCaseSensitively;
	if (_findDialog.searchBackwards())
		flags |= QTextDocument::FindBackward;
	if (_findDialog.wholeWords())
		flags |= QTextDocument::FindWholeWords;

	const QTextCursor startCursor = _textBrowser.textCursor();
	bool found = false;
	if (_findDialog.regex())
		found = _textBrowser.find(QRegularExpression(_findDialog.searchExpression()), flags);
	else
		found = _textBrowser.find(_findDialog.searchExpression(), flags);

	if(!found && (startCursor.isNull() || startCursor.position() == 0))
		QMessageBox::information(this, tr("Not found"), tr("Expression \"%1\" not found").arg(expression));
	else if (!found && startCursor.position() > 0)
	{
		if (QMessageBox::question(this, tr("Not found"), _findDialog.searchBackwards() ? tr("Beginning of file reached, do you want to restart search from the end?") : tr("End of file reached, do you want to restart search from the top?")) == QMessageBox::Yes)
			find();
	}
}

bool CTextViewerWindow::readSource(QByteArray& textData) const
{
	QFile file(_sourceFilePath);
	if (file.exists() && file.open(QIODevice::ReadOnly))
	{
		textData = file.readAll();
		return textData.size() > 0 || file.size() == 0;
	}
	else
		return false;
}

void CTextViewerWindow::encodingChanged(const QString& encoding, const QString& language)
{
	QString message;
	if (!encoding.isEmpty())
		message = tr("Text encoding: ") % encoding;
	if (!language.isEmpty())
		message = message % ", " % tr("language: ") % language;

	_encodingLabel->setText(message);
}

<MSG> Text viewer: "Find" dialog usability improvements

<DFF> @@ -17,17 +17,17 @@ CTextViewerWindow::CTextViewerWindow(QWidget *parent) :
 {
 	ui->setupUi(this);
 
-	connect(ui->actionOpen, &QAction::triggered, [this](){
+	connect(ui->actionOpen, &QAction::triggered, [this]() {
 		const QString fileName = QFileDialog::getOpenFileName(this);
 		if (!fileName.isEmpty())
 			loadTextFile(fileName);
 	});
-	connect(ui->actionReload, &QAction::triggered, [this](){
+	connect(ui->actionReload, &QAction::triggered, [this]() {
 		loadTextFile(_sourceFilePath);
 	});
 	connect(ui->actionClose, SIGNAL(triggered()), SLOT(close()));
 
-	connect(ui->actionFind, &QAction::triggered, [this](){
+	connect(ui->actionFind, &QAction::triggered, [this]() {
 		_findDialog.exec();
 	});
 	connect(ui->actionFind_next, SIGNAL(triggered()), SLOT(findNext()));

{'commit': "diff --git a/file-commander.smproj b/file-commander.smproj\nindex 34cd5b6..d87e1a5 100644\nBinary files a/file-commander.smproj and b/file-commander.smproj differ\ndiff --git a/plugins/viewer/textviewer/src/cfinddialog.cpp b/plugins/viewer/textviewer/src/cfinddialog.cpp\nindex 885d193..6548f41 100644\n--- a/plugins/viewer/textviewer/src/cfinddialog.cpp\n+++ b/plugins/viewer/textviewer/src/cfinddialog.cpp\n@@ -69,6 +69,22 @@ void CFindDialog::accept()\n \tsaveSearchSettings();\r\n }\r\n \r\n+void CFindDialog::showEvent(QShowEvent * e)\r\n+{\r\n+\tui->_searchText->selectAll();\r\n+\tui->_searchText->setFocus();\r\n+\r\n+\t// TODO: when a dialog is accepted, the next it's shown offset down and to the right of the previous position, as if the previous one is still on screen. Qt bug?..\r\n+\t// This is a fix for it\r\n+\r\n+\tQRect dialogGeometry = geometry();\r\n+\tconst QRect parentGeometry = dynamic_cast<QWidget*>(parent()) ? dynamic_cast<QWidget*>(parent())->geometry() : QRect();\r\n+\tdialogGeometry.moveTo(QPoint(parentGeometry.center().x() - dialogGeometry.width() / 2, parentGeometry.center().y() - dialogGeometry.height() / 2));\r\n+\tsetGeometry(dialogGeometry);\r\n+\r\n+\tQDialog::showEvent(e);\r\n+}\r\n+\r\n void CFindDialog::saveSearchSettings() const\r\n {\r\n \tCSettings s;\r\ndiff --git a/plugins/viewer/textviewer/src/cfinddialog.h b/plugins/viewer/textviewer/src/cfinddialog.h\nindex ea9af6b..6de96e1 100644\n--- a/plugins/viewer/textviewer/src/cfinddialog.h\n+++ b/plugins/viewer/textviewer/src/cfinddialog.h\n@@ -28,6 +28,9 @@ signals:\n public slots:\r\n \tvoid accept() override;\r\n \r\n+protected:\r\n+\tvoid showEvent(QShowEvent * e) override;\r\n+\r\n private:\r\n \tvoid saveSearchSettings() const;\r\n \r\ndiff --git a/plugins/viewer/textviewer/src/ctextviewerwindow.cpp b/plugins/viewer/textviewer/src/ctextviewerwindow.cpp\nindex 76896ab..2bddb53 100644\n--- a/plugins/viewer/textviewer/src/ctextviewerwindow.cpp\n+++ b/plugins/viewer/textviewer/src/ctextviewerwindow.cpp\n@@ -17,17 +17,17 @@ CTextViewerWindow::CTextViewerWindow(QWidget *parent) :\n {\r\n \tui->setupUi(this);\r\n \r\n-\tconnect(ui->actionOpen, &QAction::triggered, [this](){\r\n+\tconnect(ui->actionOpen, &QAction::triggered, [this]() {\r\n \t\tconst QString fileName = QFileDialog::getOpenFileName(this);\r\n \t\tif (!fileName.isEmpty())\r\n \t\t\tloadTextFile(fileName);\r\n \t});\r\n-\tconnect(ui->actionReload, &QAction::triggered, [this](){\r\n+\tconnect(ui->actionReload, &QAction::triggered, [this]() {\r\n \t\tloadTextFile(_sourceFilePath);\r\n \t});\r\n \tconnect(ui->actionClose, SIGNAL(triggered()), SLOT(close()));\r\n \r\n-\tconnect(ui->actionFind, &QAction::triggered, [this](){\r\n+\tconnect(ui->actionFind, &QAction::triggered, [this]() {\r\n \t\t_findDialog.exec();\r\n \t});\r\n \tconnect(ui->actionFind_next, SIGNAL(triggered()), SLOT(findNext()));\r\n", 'commit_subject': 'Text viewer: "Find" dialog usability improvements', 'repo_name': 'VioletGiraffe/file-commander', 'committer': {'name': 'VioletGiraffe', 'email': 'fc426b54f51508ef2c7645a399a0ae94b49c8d05@users.noreply.github.com', 'time_sec': '1435413205', 'tz_offset': '180', 'date': {'seconds': '1435413205'}}, 'commit_tree': '13858997474583706c85414116fbbd10c8040ab8', 'commit_message': 'Text viewer: "Find" dialog usability improvements\n', 'language_name': 'C', 'license': 'apache-2.0', 'hunks': '@@ -17,17 +17,17 @@ CTextViewerWindow::CTextViewerWindow(QWidget *parent) :\n {\r\n \tui->setupUi(this);\r\n \r\n-\tconnect(ui->actionOpen, &QAction::triggered, [this](){\r\n+\tconnect(ui->actionOpen, &QAction::triggered, [this]() {\r\n \t\tconst QString fileName = QFileDialog::getOpenFileName(this);\r\n \t\tif (!fileName.isEmpty())\r\n \t\t\tloadTextFile(fileName);\r\n \t});\r\n-\tconnect(ui->actionReload, &QAction::triggered, [this](){\r\n+\tconnect(ui->actionReload, &QAction::triggered, [this]() {\r\n \t\tloadTextFile(_sourceFilePath);\r\n \t});\r\n \tconnect(ui->actionClose, SIGNAL(triggered()), SLOT(close()));\r\n \r\n-\tconnect(ui->actionFind, &QAction::triggered, [this](){\r\n+\tconnect(ui->actionFind, &QAction::triggered, [this]() {\r\n \t\t_findDialog.exec();\r\n \t});\r\n \tconnect(ui->actionFind_next, SIGNAL(triggered()), SLOT(findNext()));\r\n', 'addition_count': 3, 'deletion_count': 3, 'src_file': 'a/plugins/viewer/textviewer/src/ctextviewerwindow.cpp', 'tgt_file': 'b/plugins/viewer/textviewer/src/ctextviewerwindow.cpp', 'file_extension': '.cpp', 'before_file': '#include "ctextviewerwindow.h"\n#include "ctextencodingdetector.h"\n#include "widgets/cpersistentwindow.h"\n#include "assert/advanced_assert.h"\n\nDISABLE_COMPILER_WARNINGS\n#include <QActionGroup>\n#include <QFileDialog>\n#include <QLabel>\n#include <QMimeDatabase>\n#include <QMessageBox>\n#include <QRegularExpression>\n#include <QShortcut>\n#include <QStringBuilder>\n#include <QTextCodec>\nRESTORE_COMPILER_WARNINGS\n{\r\n\tui->setupUi(this);\r\n\r\n\tconnect(ui->actionOpen, &QAction::triggered, [this](){\r\n\t\tconst QString fileName = QFileDialog::getOpenFileName(this);\r\n\t\tif (!fileName.isEmpty())\r\n\t\t\tloadTextFile(fileName);\r\n\t});\r\n\tconnect(ui->actionReload, &QAction::triggered, [this](){\r\n\t\tloadTextFile(_sourceFilePath);\r\n\t});\r\n\tconnect(ui->actionClose, SIGNAL(triggered()), SLOT(close()));\r\n\r\n\tconnect(ui->actionFind, &QAction::triggered, [this](){\r\n\t\t_findDialog.exec();\r\n\t});\r\n\tconnect(ui->actionFind_next, SIGNAL(triggered()), SLOT(findNext()));\r\n\tinstallEventFilter(new CPersistenceEnabler("Plugins/TextViewer/Window", this));\n\n\tsetCentralWidget(&_textBrowser);\n\t_textBrowser.setReadOnly(true);\n\t_textBrowser.setUndoRedoEnabled(false);\n\t_textBrowser.setWordWrapMode(QTextOption::NoWrap);\n\t_textBrowser.setTabStopDistance(static_cast<qreal>(4 * _textBrowser.fontMetrics().horizontalAdvance(\' \')));\n\n\tassert_r(connect(actionOpen, &QAction::triggered, [this]() {\n\t\tconst QString fileName = QFileDialog::getOpenFileName(this);\n\t\tif (!fileName.isEmpty())\n\t\t\tloadTextFile(fileName);\n\t}));\n\n\tassert_r(connect(actionReload, &QAction::triggered, [this]() {\n\t\tloadTextFile(_sourceFilePath);\n\t}));\n\tassert_r(connect(actionClose, &QAction::triggered, this, &QDialog::close));\n\n\tassert_r(connect(actionFind, &QAction::triggered, [this]() {\n\t\t_findDialog.exec();\n\t}));\n\tassert_r(connect(actionFind_next, &QAction::triggered, this, &CTextViewerWindow::findNext));\n\n\tassert_r(connect(actionAuto_detect_encoding, &QAction::triggered, this, &CTextViewerWindow::asDetectedAutomatically));\n\tassert_r(connect(actionASCII_Windows_1252, &QAction::triggered, this, &CTextViewerWindow::asAscii));\n\tassert_r(connect(actionSystemLocale, &QAction::triggered, this, &CTextViewerWindow::asSystemDefault));\n\tassert_r(connect(actionUTF_8, &QAction::triggered, this, &CTextViewerWindow::asUtf8));\n\tassert_r(connect(actionUTF_16, &QAction::triggered, this, &CTextViewerWindow::asUtf16));\n\tassert_r(connect(actionHTML_RTF, &QAction::triggered, this, &CTextViewerWindow::asRichText));\n\n\tQActionGroup * group = new QActionGroup(this);\n\tgroup->addAction(actionASCII_Windows_1252);\n\tgroup->addAction(actionSystemLocale);\n\tgroup->addAction(actionUTF_8);\n\tgroup->addAction(actionUTF_16);\n\tgroup->addAction(actionHTML_RTF);\n\n\tassert_r(connect(&_findDialog, &CFindDialog::find, this, &CTextViewerWindow::find));\n\tassert_r(connect(&_findDialog, &CFindDialog::findNext, this, &CTextViewerWindow::findNext));\n\n\tauto escScut = new QShortcut(QKeySequence("Esc"), this, SLOT(close()));\n\tassert_r(connect(this, &QObject::destroyed, escScut, &QShortcut::deleteLater));\n\n\t_encodingLabel = new QLabel(this);\n\tQMainWindow::statusBar()->addWidget(_encodingLabel);\n}\n\nbool CTextViewerWindow::loadTextFile(const QString& file)\n{\n\tsetWindowTitle(file);\n\t_sourceFilePath = file;\n\n\tconst QString fileType = QMimeDatabase().mimeTypeForFile(_sourceFilePath, QMimeDatabase::MatchContent).name();\n\n\ttry\n\t{\n\t\tif (_sourceFilePath.endsWith(".htm", Qt::CaseInsensitive) || _sourceFilePath.endsWith(".html", Qt::CaseInsensitive) || _sourceFilePath.endsWith(".rtf", Qt::CaseInsensitive))\n\t\t\treturn asRichText();\n\t\telse if (fileType.contains("text") || fileType.isEmpty())\n\t\t\treturn asDetectedAutomatically();\n\t\telse\n\t\t\treturn asAscii();\n\t}\n\tcatch (const std::bad_alloc&)\n\t{\n\t\tQMessageBox::warning(this, "File is too large", "The text is too large to display");\n\t\treturn false;\n\t}\n}\n\nbool CTextViewerWindow::asDetectedAutomatically()\n{\n\tQTextCodec::ConverterState state;\n\tQTextCodec *codec = QTextCodec::codecForName("UTF-8");\n\tif (!codec)\n\t\treturn false;\n\n\tQByteArray textData;\n\tif (!readSource(textData))\n\t{\n\t\tQMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\\n\\n%1\\n\\nIt is inaccessible or doesn\'t exist.").arg(_sourceFilePath));\n\t\treturn false;\n\t}\n\n\tQString text(codec->toUnicode(textData.constData(), static_cast<int>(textData.size()), &state));\n\tif (state.invalidChars > 0)\n\t{\n\t\tconst auto result = CTextEncodingDetector::decode(textData);\n\t\ttext = result.text;\n\t\tif (!text.isEmpty())\n\t\t{\n\t\t\tencodingChanged(result.encoding, result.language);\n\t\t\t_textBrowser.setPlainText(text);\n\t\t}\n\t\telse\n\t\t\treturn asSystemDefault();\n\t}\n\telse\n\t{\n\t\tencodingChanged("UTF-8");\n\t\tactionUTF_8->setChecked(true);\n\t\t_textBrowser.setPlainText(text);\n\t}\n\n\treturn true;\n}\n\nbool CTextViewerWindow::asSystemDefault()\n{\n\tQTextCodec * codec = QTextCodec::codecForLocale();\n\tif (!codec)\n\t\treturn false;\n\n\tQByteArray textData;\n\tif (!readSource(textData))\n\t{\n\t\tQMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\\n\\n%1\\n\\nIt is inaccessible or doesn\'t exist.").arg(_sourceFilePath));\n\t\treturn false;\n\t}\n\n\t_textBrowser.setPlainText(codec->toUnicode(textData));\n\tencodingChanged(codec->name());\n\tactionSystemLocale->setChecked(true);\n\n\treturn true;\n}\n\nbool CTextViewerWindow::asAscii()\n{\n\tQTextCodec* codec = QTextCodec::codecForName("Windows-1252");\n\tif (!codec)\n\t\treturn false;\n\n\tQByteArray textData;\n\tif (!readSource(textData))\n\t{\n\t\tQMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\\n\\n%1\\n\\nIt is inaccessible or doesn\'t exist.").arg(_sourceFilePath));\n\t\treturn false;\n\t}\n\n\t_textBrowser.setPlainText(codec->toUnicode(textData));\n\tencodingChanged(codec->name());\n\tactionASCII_Windows_1252->setChecked(true);\n\n\treturn true;\n}\n\nbool CTextViewerWindow::asUtf8()\n{\n\tQByteArray textData;\n\tif (!readSource(textData))\n\t{\n\t\tQMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\\n\\n%1\\n\\nIt is inaccessible or doesn\'t exist.").arg(_sourceFilePath));\n\t\treturn false;\n\t}\n\n\tencodingChanged("UTF-8");\n\t_textBrowser.setPlainText(QString::fromUtf8(textData));\n\tactionUTF_8->setChecked(true);\n\n\treturn true;\n}\n\nbool CTextViewerWindow::asUtf16()\n{\n\tQByteArray textData;\n\tif (!readSource(textData))\n\t{\n\t\tQMessageBox::warning(parentWidget(), tr("Failed to read the file"), tr("Failed to load the file\\n\\n%1\\n\\nIt is inaccessible or doesn\'t exist.").arg(_sourceFilePath));\n\t\treturn false;\n\t}\n\n\tencodingChanged("UTF-16");\n\tstatic_assert (std::is_trivially_copyable_v<QChar>);\n\tQString text;\n\ttext.resize(textData.size() / 2 + 1, QChar{\'\\0\'});\n\tmemcpy(text.data(), textData.constData(), static_cast<size_t>(textData.size()));\n\t_textBrowser.setPlainText(std::move(text));\n\tactionUTF_16->setChecked(true);\n\n\treturn true;\n}\n\nbool CTextViewerWindow::asRichText()\n{\n\t// TODO: add RTF support\n\treturn asDetectedAutomatically();\n}\n\nvoid CTextViewerWindow::find()\n{\n\t_textBrowser.moveCursor(_findDialog.searchBackwards() ? QTextCursor::End : QTextCursor::Start);\n\tfindNext();\n}\n\nvoid CTextViewerWindow::findNext()\n{\n\tconst QString expression = _findDialog.searchExpression();\n\tif (expression.isEmpty())\n\t\treturn;\n\n\tQTextDocument::FindFlags flags {};\n\tif (_findDialog.caseSensitive())\n\t\tflags |= QTextDocument::FindCaseSensitively;\n\tif (_findDialog.searchBackwards())\n\t\tflags |= QTextDocument::FindBackward;\n\tif (_findDialog.wholeWords())\n\t\tflags |= QTextDocument::FindWholeWords;\n\n\tconst QTextCursor startCursor = _textBrowser.textCursor();\n\tbool found = false;\n\tif (_findDialog.regex())\n\t\tfound = _textBrowser.find(QRegularExpression(_findDialog.searchExpression()), flags);\n\telse\n\t\tfound = _textBrowser.find(_findDialog.searchExpression(), flags);\n\n\tif(!found && (startCursor.isNull() || startCursor.position() == 0))\n\t\tQMessageBox::information(this, tr("Not found"), tr("Expression \\"%1\\" not found").arg(expression));\n\telse if (!found && startCursor.position() > 0)\n\t{\n\t\tif (QMessageBox::question(this, tr("Not found"), _findDialog.searchBackwards() ? tr("Beginning of file reached, do you want to restart search from the end?") : tr("End of file reached, do you want to restart search from the top?")) == QMessageBox::Yes)\n\t\t\tfind();\n\t}\n}\n\nbool CTextViewerWindow::readSource(QByteArray& textData) const\n{\n\tQFile file(_sourceFilePath);\n\tif (file.exists() && file.open(QIODevice::ReadOnly))\n\t{\n\t\ttextData = file.readAll();\n\t\treturn textData.size() > 0 || file.size() == 0;\n\t}\n\telse\n\t\treturn false;\n}\n\nvoid CTextViewerWindow::encodingChanged(const QString& encoding, const QString& language)\n{\n\tQString message;\n\tif (!encoding.isEmpty())\n\t\tmessage = tr("Text encoding: ") % encoding;\n\tif (!language.isEmpty())\n\t\tmessage = message % ", " % tr("language: ") % language;\n\n\t_encodingLabel->setText(message);\n}\n', 'message': 'Text viewer: "Find" dialog usability improvements\n', 'author_name': 'VioletGiraffe', 'lang': 'cpp'}