Решаю сейчас в своем WYSIWYG-редакторе следующую задачу:
При вставке текста, взятого из окна браузера, текст может содержать различные теги форматирования. В программе предусмотрена кнопка для сброса форматирования текста к стандартному, заданному в настройках редактора.
Задача:
Написать функцию (метод), очищающий форматирование выделенного текста в виджете-наследнике QTextEdit.
https://github.com/xintrea/mytetra_dev/issues/5То есть, нужно изменить только начертание символов. Ссылки должны остаться ссылками. Картинки должны остаться картинками. Таблицы должны остаться таблицами. Изменяется только начертание.
При кажущейся простоте, подводных камней у этой задачи много. Сейчас я почти достиг цели - написал жуткий magick-код, который берет HTML-код выделенного фрагмета текста, обрабатывает его (убирает лишнее, подменяет теги, компенсирует многочисленные закидоны Qt-овского HTML-движка), и вставляет его обратно.
Такая методика наконец-таки заработала чисто, за одним маленьким исключением: при вставке HTML-кода через метод insertHtml(), съедаются ведущие пробелы в тексте. То есть, если в тексте встретится кусок исходного кода, то indentation у него слетит.
Вот пример HTML-кода до вставки и что реально вставилось:
Вставляли:
<p style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;"><span style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;"> QMessageBox msgBox;</span></p>
<p style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;"><span style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;"> msgBox.setText(welcomeText);</span></p>
<p style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;"><span style="margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;"> msgBox.setInformativeText(infoText);</span></p>
Получили:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
p, li { white-space: pre-wrap; }
</style></head><body>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><!--StartFragment-->QMessageBox msgBox;</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">msgBox.setText(welcomeText);</p>
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">msgBox.setInformativeText(infoText);<!--EndFragment--></p></body></html>
Видно, что ведущие четыре пробела в каждой строчке исчезли.
Код, который это делает:
...
qDebug() << htmlCode;
// Вставка очищенного фрагмента
textArea->textCursor().insertHtml(htmlCode);
// Выделение только что вставленного фрагмента (это тоже магия)
cursor.movePosition(QTextCursor::End);
int afterClearLen=cursor.position();
int calculateEndCursorPos=startCursorPos + (afterClearLen - afterRemoveSelectionLen);
cursor.setPosition(startCursorPos, QTextCursor::MoveAnchor);
cursor.setPosition(calculateEndCursorPos, QTextCursor::KeepAnchor);
textArea->setTextCursor(cursor);
qDebug() << textArea->textCursor().selection().toHtml();
...
Вопрос: как можно обойти эту особенность Qt, чтобы в данном случае все пробелы сохранялись?
Я уже готов выбрать редко используемый UTF-8 символ (какой-нибудь иероглиф), заменить им все пробелы во вставляемом HTML, а потом заменить в документе эти символы на пробелы. Или не иероглиф, а нигде-никогда-не-встречаемую-строку. Но это же все неправильно (вдруг иероглиф кто-то использует, или так получится, что уникальная строка таки встретится). А хотелось бы правильно.
А как правильно?
Последний актуальный коммит:
https://github.com/xintrea/mytetra_dev/commit/11bde04320971b28420f1fba217ad0ed438d43da