// SPDX-FileCopyrightText: 2025 James Graham // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL #pragma once #include #include #include #include #include #include "chattextitemhelper.h" class ChatTextItemHelperTestHelper : public QObject { Q_OBJECT QML_ELEMENT /** * @brief The QML text Item the TextItemHelper is handling. */ Q_PROPERTY(ChatTextItemHelper *textItem READ textItem WRITE setTextItem NOTIFY textItemChanged) public: explicit ChatTextItemHelperTestHelper(QObject *parent = nullptr) : QObject(parent) { } ChatTextItemHelper *textItem() const { return m_textItem; } void setTextItem(ChatTextItemHelper *textItem) { if (textItem == m_textItem) { return; } m_textItem = textItem; Q_EMIT textItemChanged(); } Q_INVOKABLE void setFixedChars(const QString &startChars, const QString &endChars) { if (!m_textItem) { return; } m_textItem->setFixedChars(startChars, endChars); } Q_INVOKABLE bool compareDocuments(QQuickTextDocument *document) { if (!m_textItem) { return false; } return document->textDocument() == m_textItem->document(); } Q_INVOKABLE int lineCount() { if (!m_textItem) { return -1; } return m_textItem->lineCount(); } Q_INVOKABLE QString firstBlockText() { if (!m_textItem) { return {}; } return m_textItem->takeFirstBlock().toPlainText(); } Q_INVOKABLE bool checkFragments(const QString &before, const QString &mid, const QString &after) { if (!m_textItem) { return false; } bool hasBefore = false; QTextDocumentFragment midFragment; std::optional afterFragment = std::nullopt; m_textItem->fillFragments(hasBefore, midFragment, afterFragment); return hasBefore && m_textItem->document()->toPlainText() == before && midFragment.toPlainText() == mid && after.isEmpty() ? !afterFragment : afterFragment->toPlainText() == after; } Q_INVOKABLE void insertFragment(const QString &text, ChatTextItemHelper::InsertPosition position = ChatTextItemHelper::Cursor, bool keepPosition = false) { if (!m_textItem) { return; } const auto fragment = QTextDocumentFragment::fromPlainText(text); m_textItem->insertFragment(fragment, position, keepPosition); } Q_INVOKABLE bool compareCursor(int cursorPosition, int selectionStart, int selectionEnd) { if (!m_textItem) { return false; } const auto cursor = m_textItem->textCursor(); if (cursor.isNull()) { return false; } const auto posSame = cursor.position() == cursorPosition; const auto startSame = cursor.selectionStart() == selectionStart; const auto endSame = cursor.selectionEnd() == selectionEnd; return posSame && startSame && endSame; } Q_INVOKABLE int cursorPosition() const { if (!m_textItem) { return -1; } return *m_textItem->cursorPosition(); } Q_INVOKABLE void setCursorPosition(int pos) { if (!m_textItem) { return; } m_textItem->setCursorPosition(pos); } Q_INVOKABLE void setCursorVisible(bool visible) { if (!m_textItem) { return; } m_textItem->setCursorVisible(visible); } Q_INVOKABLE void setCursorFromTextItem(QQuickItem *item, bool infront, int cursorPos) { if (!m_textItem) { return; } const auto textItem = new ChatTextItemHelper(this); textItem->setTextItem(item); textItem->setCursorPosition(cursorPos); m_textItem->setCursorFromTextItem(textItem, infront); textItem->deleteLater(); } Q_INVOKABLE void mergeFormatOnCursor(RichFormat::Format format) { if (!m_textItem) { return; } m_textItem->mergeFormatOnCursor(format); } Q_INVOKABLE bool checkFormatsAtCursor(QList formats) { const auto cursor = m_textItem->textCursor(); if (cursor.isNull()) { return false; } return RichFormat::formatsAtCursor(cursor) == formats; } Q_INVOKABLE bool canIndentListMoreAtCursor() const { if (!m_textItem) { return false; } return m_textItem->canIndentListMoreAtCursor(); } Q_INVOKABLE bool canIndentListLessAtCursor() const { if (!m_textItem) { return false; } return m_textItem->canIndentListLessAtCursor(); } Q_INVOKABLE void indentListMoreAtCursor() { if (!m_textItem) { return; } m_textItem->indentListMoreAtCursor(); } Q_INVOKABLE void indentListLessAtCursor() { if (!m_textItem) { return; } m_textItem->indentListLessAtCursor(); } Q_INVOKABLE void forceActiveFocus() const { if (!m_textItem) { return; } m_textItem->forceActiveFocus(); } Q_INVOKABLE QString markdownText() const { if (!m_textItem) { return {}; } return m_textItem->markdownText(); } Q_SIGNALS: void textItemChanged(); private: QPointer m_textItem; };