File indexing completed on 2024-05-12 16:16:00

0001 /*
0002    SPDX-FileCopyrightText: 2022-2023 Laurent Montel <montel@kde.org>
0003 
0004    SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "grammarresultutil.h"
0008 #include "textgrammarcheck_debug.h"
0009 
0010 #include <KLocalizedString>
0011 #include <QTextBlock>
0012 #include <QTextDocument>
0013 using namespace TextGrammarCheck;
0014 
0015 void GrammarResultUtil::applyGrammarResult(const QVector<TextGrammarCheck::GrammarError> &infos, QTextDocument *document, const QColor &negativeTextColor)
0016 {
0017     for (const TextGrammarCheck::GrammarError &info : infos) {
0018         int blockNumberId = info.blockId();
0019         int startSelectionIndex = info.start();
0020         // Block id based on 1 not 0 as QTextDocument (perhaps remove -1 when loading ?)
0021         if (blockNumberId == -1) { // Languagetool adapt grammar error We need to generate info. By default languagetool uses 1 paragraph info.
0022             const QTextBlock firstBlock = document->findBlockByNumber(0);
0023             if (firstBlock.isValid()) {
0024                 QTextCursor cur(document);
0025 
0026                 cur.setPosition(info.start());
0027                 blockNumberId = cur.blockNumber();
0028                 for (int i = 0; i < blockNumberId; ++i) {
0029                     const QTextBlock block = document->findBlockByNumber(i);
0030                     if (block.isValid()) {
0031                         if (block.text() != QLatin1Char('\n')) {
0032                             startSelectionIndex -= block.length();
0033                         }
0034                     }
0035                 }
0036             }
0037         } else {
0038             blockNumberId = info.blockId() - 1;
0039         }
0040         QTextBlock block = document->findBlockByNumber(blockNumberId);
0041         if (block.isValid()) {
0042             QTextCursor cur(block);
0043             QTextCharFormat format;
0044             // Verify color
0045             format.setBackground(info.color().isValid() ? info.color() : negativeTextColor);
0046             QString toolTip = info.error();
0047             // TODO generate new tooltip!
0048             if (!info.url().isEmpty()) {
0049                 toolTip += QLatin1Char('\n') + i18n("See on: %1", info.url());
0050             }
0051             format.setToolTip(toolTip);
0052             TextGrammarCheck::GrammarAction act;
0053             act.setLength(info.length());
0054             act.setStart(startSelectionIndex);
0055             act.setSuggestions(info.suggestions());
0056             act.setBlockId(blockNumberId + 1);
0057             if (!info.url().isEmpty()) {
0058                 act.setInfoUrls({info.url()});
0059             }
0060             format.setProperty(ReplaceFormatInfo, QVariant::fromValue(act));
0061             const int position = cur.position() + startSelectionIndex;
0062             cur.setPosition(position);
0063             cur.setPosition(position + info.length(), QTextCursor::KeepAnchor);
0064             cur.mergeCharFormat(format);
0065         } else {
0066             qCWarning(TEXTGRAMMARCHECK_LOG) << "Unable to find block Id" << (info.blockId() - 1);
0067         }
0068     }
0069 }
0070 
0071 void GrammarResultUtil::replaceWord(const TextGrammarCheck::GrammarAction &act, const QString &replacementWord, QTextDocument *document)
0072 {
0073     QTextBlock block = document->findBlockByNumber(act.blockId() - 1);
0074     if (block.isValid()) {
0075         QTextCursor cur(block);
0076         const int initialCurrentPosition = cur.position();
0077         qCDebug(TEXTGRAMMARCHECK_LOG) << " cur.position()" << cur.position();
0078         const int position = cur.position() + act.start();
0079         cur.setPosition(position);
0080         cur.setPosition(position + act.length(), QTextCursor::KeepAnchor);
0081         QTextCharFormat format;
0082         cur.insertText(replacementWord, format);
0083         const int diff = replacementWord.length() - act.length();
0084         qCDebug(TEXTGRAMMARCHECK_LOG) << " diff " << diff;
0085         if (diff != 0) {
0086             const int blockLength = block.length();
0087             qCDebug(TEXTGRAMMARCHECK_LOG) << "current blockLength " << blockLength << " position " << position << "";
0088             for (int i = position + replacementWord.length() + 1; i < blockLength + initialCurrentPosition; ++i) {
0089                 cur.setPosition(i);
0090                 qCDebug(TEXTGRAMMARCHECK_LOG) << " Position  " << i;
0091                 QTextCharFormat currentCharFormat = cur.charFormat();
0092                 if (currentCharFormat.hasProperty(GrammarResultUtil::TextInfo::ReplaceFormatInfo)) {
0093                     auto act = cur.charFormat().property(GrammarResultUtil::TextInfo::ReplaceFormatInfo).value<TextGrammarCheck::GrammarAction>();
0094                     qCDebug(TEXTGRAMMARCHECK_LOG) << "BEFORE Update GrammarResultUtil::TextInfo::ReplaceFormatInfo " << act;
0095                     act.setStart(act.start() + diff);
0096                     qCDebug(TEXTGRAMMARCHECK_LOG) << "AFTER Update GrammarResultUtil::TextInfo::ReplaceFormatInfo " << act.start();
0097                     currentCharFormat.setProperty(GrammarResultUtil::TextInfo::ReplaceFormatInfo, QVariant::fromValue(act));
0098 
0099                     const int newPosition = i - 1;
0100                     qCDebug(TEXTGRAMMARCHECK_LOG) << " newPosition " << newPosition;
0101                     qCDebug(TEXTGRAMMARCHECK_LOG) << "BEFORE Update GrammarResultUtil::TextInfo::ReplaceFormatInfo newPosition " << newPosition;
0102                     cur.setPosition(newPosition);
0103                     cur.setPosition(newPosition + act.length(), QTextCursor::KeepAnchor);
0104                     qCDebug(TEXTGRAMMARCHECK_LOG) << "AFTER Update GrammarResultUtil::TextInfo::ReplaceFormatInfo newPosition " << newPosition + act.length();
0105                     cur.setCharFormat(currentCharFormat);
0106 
0107                     i += act.length();
0108                 }
0109             }
0110         }
0111     }
0112 }