Restore missing functionality
This commit is contained in:
@@ -205,7 +205,7 @@ Q_SIGNALS:
|
||||
void relationIdChanged(const QString &oldEventId, const QString &newEventId);
|
||||
void threadIdChanged(const QString &oldThreadId, const QString &newThreadId);
|
||||
void attachmentPathChanged();
|
||||
void mentionAdded(const QString &mention);
|
||||
void mentionAdded(const QString &text, const QString &hRef);
|
||||
void relationAuthorIsPresentChanged();
|
||||
|
||||
private:
|
||||
|
||||
@@ -3,120 +3,191 @@
|
||||
|
||||
#include "chatkeyhelper.h"
|
||||
|
||||
#include "chattextitemhelper.h"
|
||||
#include "clipboard.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
ChatKeyHelper::ChatKeyHelper(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ChatTextItemHelper *ChatKeyHelper::textItem() const
|
||||
bool ChatKeyHelper::handleKey(Qt::Key key, Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
return m_textItem;
|
||||
switch (key) {
|
||||
case Qt::Key_V:
|
||||
return vKey(modifiers);
|
||||
case Qt::Key_Up:
|
||||
return up(modifiers);
|
||||
case Qt::Key_Down:
|
||||
return down();
|
||||
case Qt::Key_Tab:
|
||||
return tab();
|
||||
case Qt::Key_Delete:
|
||||
return deleteChar();
|
||||
case Qt::Key_Backspace:
|
||||
return backspace();
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
return insertReturn();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ChatKeyHelper::setTextItem(ChatTextItemHelper *textItem)
|
||||
bool ChatKeyHelper::vKey(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (textItem == m_textItem) {
|
||||
return;
|
||||
if (!textItem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_textItem) {
|
||||
m_textItem->disconnect(this);
|
||||
if (modifiers.testFlag(Qt::ControlModifier)) {
|
||||
return pasteImage();
|
||||
}
|
||||
|
||||
m_textItem = textItem;
|
||||
|
||||
if (m_textItem) {
|
||||
connect(m_textItem, &ChatTextItemHelper::textItemChanged, this, &ChatKeyHelper::textItemChanged);
|
||||
}
|
||||
|
||||
Q_EMIT textItemChanged();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatKeyHelper::up()
|
||||
bool ChatKeyHelper::up(Qt::KeyboardModifiers modifiers)
|
||||
{
|
||||
if (!m_textItem) {
|
||||
return;
|
||||
if (!textItem) {
|
||||
return false;
|
||||
}
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
|
||||
if (modifiers.testFlag(Qt::ControlModifier)) {
|
||||
room->replyLastMessage();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (textItem->isEmpty()) {
|
||||
room->editLastMessage();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (textItem->isCompleting) {
|
||||
Q_EMIT unhandledUp(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (cursor.blockNumber() == 0 && cursor.block().layout()->lineForTextPosition(cursor.positionInBlock()).lineNumber() == 0) {
|
||||
Q_EMIT unhandledUp();
|
||||
return;
|
||||
Q_EMIT unhandledUp(false);
|
||||
return true;
|
||||
}
|
||||
cursor.movePosition(QTextCursor::Up);
|
||||
m_textItem->setCursorPosition(cursor.position());
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatKeyHelper::down()
|
||||
bool ChatKeyHelper::down()
|
||||
{
|
||||
if (!m_textItem) {
|
||||
return;
|
||||
if (!textItem) {
|
||||
return false;
|
||||
}
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (textItem->isCompleting) {
|
||||
Q_EMIT unhandledDown(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (cursor.blockNumber() == cursor.document()->blockCount() - 1
|
||||
&& cursor.block().layout()->lineForTextPosition(cursor.positionInBlock()).lineNumber() == (cursor.block().layout()->lineCount() - 1)) {
|
||||
Q_EMIT unhandledDown();
|
||||
return;
|
||||
Q_EMIT unhandledDown(false);
|
||||
return true;
|
||||
}
|
||||
cursor.movePosition(QTextCursor::Down);
|
||||
m_textItem->setCursorPosition(cursor.position());
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatKeyHelper::tab()
|
||||
bool ChatKeyHelper::tab()
|
||||
{
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (!textItem) {
|
||||
return false;
|
||||
}
|
||||
if (textItem->isCompleting) {
|
||||
Q_EMIT unhandledTab(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (cursor.currentList() && m_textItem->canIndentListMoreAtCursor()) {
|
||||
m_textItem->indentListMoreAtCursor();
|
||||
return;
|
||||
if (cursor.currentList() && textItem->canIndentListMoreAtCursor()) {
|
||||
textItem->indentListMoreAtCursor();
|
||||
return true;
|
||||
}
|
||||
cursor.insertText(u" "_s);
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatKeyHelper::deleteChar()
|
||||
bool ChatKeyHelper::deleteChar()
|
||||
{
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
if (!textItem) {
|
||||
return false;
|
||||
}
|
||||
if (cursor.position() >= m_textItem->document()->characterCount() - m_textItem->fixedEndChars().length() - 1) {
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return false;
|
||||
}
|
||||
if (cursor.position() >= textItem->document()->characterCount() - textItem->fixedEndChars().length() - 1) {
|
||||
Q_EMIT unhandledDelete();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
cursor.deleteChar();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatKeyHelper::backspace()
|
||||
bool ChatKeyHelper::backspace()
|
||||
{
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
if (!textItem) {
|
||||
return false;
|
||||
}
|
||||
if (cursor.position() <= m_textItem->fixedStartChars().length()) {
|
||||
if (cursor.currentList() && m_textItem->canIndentListLessAtCursor()) {
|
||||
m_textItem->indentListLessAtCursor();
|
||||
return;
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return false;
|
||||
}
|
||||
if (cursor.position() <= textItem->fixedStartChars().length()) {
|
||||
if (cursor.currentList() && textItem->canIndentListLessAtCursor()) {
|
||||
textItem->indentListLessAtCursor();
|
||||
return true;
|
||||
}
|
||||
Q_EMIT unhandledBackspace();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
cursor.deletePreviousChar();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatKeyHelper::insertReturn()
|
||||
bool ChatKeyHelper::insertReturn()
|
||||
{
|
||||
QTextCursor cursor = m_textItem->textCursor();
|
||||
if (!textItem) {
|
||||
return false;
|
||||
}
|
||||
if (textItem->isCompleting) {
|
||||
Q_EMIT unhandledReturn(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
QTextCursor cursor = textItem->textCursor();
|
||||
if (cursor.isNull()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
cursor.insertBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChatKeyHelper::pasteImage()
|
||||
{
|
||||
if (!textItem) {
|
||||
return false;
|
||||
}
|
||||
const auto savePath = Clipboard().saveImage();
|
||||
if (!savePath.isEmpty()) {
|
||||
Q_EMIT imagePasted(savePath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "moc_chatkeyhelper.cpp"
|
||||
|
||||
@@ -6,8 +6,18 @@
|
||||
#include <QObject>
|
||||
#include <QQmlEngine>
|
||||
|
||||
#include "chattextitemhelper.h"
|
||||
class NeoChatRoom;
|
||||
class ChatTextItemHelper;
|
||||
|
||||
/**
|
||||
* @class ChatKeyHelper
|
||||
*
|
||||
* A class to handle some key presses on behalf of a ChatTextItemHelper.
|
||||
*
|
||||
* This is used to manage complex rich text interactions.
|
||||
*
|
||||
* @sa ChatTextItemHelper
|
||||
*/
|
||||
class ChatKeyHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -16,72 +26,94 @@ class ChatKeyHelper : public QObject
|
||||
public:
|
||||
explicit ChatKeyHelper(QObject *parent = nullptr);
|
||||
|
||||
ChatTextItemHelper *textItem() const;
|
||||
void setTextItem(ChatTextItemHelper *textItem);
|
||||
/**
|
||||
* @brief The ChatTextItemHelper that ChatKeyHelper is handling key presses for.
|
||||
*
|
||||
* @sa ChatTextItemHelper
|
||||
*/
|
||||
QPointer<NeoChatRoom> room;
|
||||
|
||||
/**
|
||||
* @brief Handle up key at current cursor location.
|
||||
* @brief The ChatTextItemHelper that ChatKeyHelper is handling key presses for.
|
||||
*
|
||||
* @sa ChatTextItemHelper
|
||||
*/
|
||||
Q_INVOKABLE void up();
|
||||
QPointer<ChatTextItemHelper> textItem;
|
||||
|
||||
/**
|
||||
* @brief Handle down key at current cursor location.
|
||||
*/
|
||||
Q_INVOKABLE void down();
|
||||
|
||||
/**
|
||||
* @brief Handle tab key at current cursor location.
|
||||
*/
|
||||
Q_INVOKABLE void tab();
|
||||
|
||||
/**
|
||||
* @brief Handle delete key at current cursor location.
|
||||
*/
|
||||
Q_INVOKABLE void deleteChar();
|
||||
|
||||
/**
|
||||
* @brief Handle backspace key at current cursor location.
|
||||
*/
|
||||
Q_INVOKABLE void backspace();
|
||||
|
||||
/**
|
||||
* @brief Handle return key at current cursor location.
|
||||
*/
|
||||
Q_INVOKABLE void insertReturn();
|
||||
Q_INVOKABLE bool handleKey(Qt::Key key, Qt::KeyboardModifiers modifiers);
|
||||
|
||||
Q_SIGNALS:
|
||||
void textItemChanged();
|
||||
|
||||
/**
|
||||
* @brief There is an unhandled up key press.
|
||||
*
|
||||
* i.e. up is pressed on the first line of the first block of the text item.
|
||||
* Current trigger conditions:
|
||||
* - Up is pressed on the first line of the first block of the text item.
|
||||
* - Return clicked when a completion has been started.
|
||||
*/
|
||||
void unhandledUp();
|
||||
void unhandledUp(bool isCompleting);
|
||||
|
||||
/**
|
||||
* @brief There is an unhandled down key press.
|
||||
*
|
||||
* i.e. down is pressed on the last line of the last block of the text item.
|
||||
* Current trigger conditions:
|
||||
* - Down is pressed on the last line of the last block of the text item.
|
||||
* - Return clicked when a completion has been started.
|
||||
*/
|
||||
void unhandledDown();
|
||||
void unhandledDown(bool isCompleting);
|
||||
|
||||
/**
|
||||
* @brief There is an unhandled tab key press.
|
||||
*
|
||||
* Current trigger conditions:
|
||||
* - Tab clicked when a completion has been started.
|
||||
*/
|
||||
void unhandledTab(bool isCompleting);
|
||||
|
||||
/**
|
||||
* @brief There is an unhandled delete key press.
|
||||
*
|
||||
* i.e. delete is pressed at the end of the last line of the last block of the
|
||||
* text item.
|
||||
* Current trigger conditions:
|
||||
* - Delete is pressed at the end of the last line of the last block of the
|
||||
* text item.
|
||||
*/
|
||||
void unhandledDelete();
|
||||
|
||||
/**
|
||||
* @brief There is an unhandled backspace key press.
|
||||
*
|
||||
* i.e. backspace is pressed at the beginning of the first line of the first
|
||||
* block of the text item.
|
||||
* Current trigger conditions:
|
||||
* - Backspace is pressed at the beginning of the first line of the first
|
||||
* block of the text item.
|
||||
*/
|
||||
void unhandledBackspace();
|
||||
|
||||
/**
|
||||
* @brief There is an unhandled return key press.
|
||||
*
|
||||
* Current trigger conditions:
|
||||
* - Return clicked when a completion has been started.
|
||||
*/
|
||||
void unhandledReturn(bool isCompleting);
|
||||
|
||||
/**
|
||||
* @brief An image has been pasted.
|
||||
*/
|
||||
void imagePasted(const QString &filePath);
|
||||
|
||||
private:
|
||||
QPointer<ChatTextItemHelper> m_textItem;
|
||||
bool vKey(Qt::KeyboardModifiers modifiers);
|
||||
|
||||
bool up(Qt::KeyboardModifiers modifiers);
|
||||
|
||||
bool down();
|
||||
|
||||
bool tab();
|
||||
|
||||
bool deleteChar();
|
||||
|
||||
bool backspace();
|
||||
|
||||
bool insertReturn();
|
||||
|
||||
bool pasteImage();
|
||||
};
|
||||
|
||||
@@ -64,6 +64,11 @@ public:
|
||||
QQuickItem *textItem() const;
|
||||
void setTextItem(QQuickItem *textItem);
|
||||
|
||||
/**
|
||||
* @brief Whether a completion has started based on recent text entry.
|
||||
*/
|
||||
bool isCompleting = false;
|
||||
|
||||
/**
|
||||
* @brief The fixed characters that will always be at the beginning of the text item.
|
||||
*/
|
||||
@@ -98,6 +103,13 @@ public:
|
||||
*/
|
||||
QTextDocument *document() const;
|
||||
|
||||
/**
|
||||
* @brief Whetehr the underlying QTextDocument is empty.
|
||||
*
|
||||
* @sa QTextDocument
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
/**
|
||||
* @brief The line count of the text item.
|
||||
*/
|
||||
@@ -238,7 +250,6 @@ private:
|
||||
void initializeChars();
|
||||
bool m_initializingChars = false;
|
||||
|
||||
bool isEmpty() const;
|
||||
std::optional<int> lineLength(int lineNumber) const;
|
||||
|
||||
int selectionStart() const;
|
||||
|
||||
@@ -240,6 +240,8 @@ void CompletionModel::updateCompletion()
|
||||
}
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
|
||||
m_textItem->isCompleting = rowCount() > 0;
|
||||
}
|
||||
|
||||
CompletionModel::AutoCompletionType CompletionModel::autoCompletionType() const
|
||||
|
||||
@@ -55,6 +55,10 @@ QString QmlUtils::nameForPowerLevelValue(const int value)
|
||||
|
||||
bool Utils::isEmoji(const QString &text)
|
||||
{
|
||||
if (text.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ICU
|
||||
QTextBoundaryFinder finder(QTextBoundaryFinder::Grapheme, text);
|
||||
int from = 0;
|
||||
|
||||
Reference in New Issue
Block a user