diff --git a/src/libneochat/chatkeyhelper.cpp b/src/libneochat/chatkeyhelper.cpp index 3d68d34fd..49c26cd16 100644 --- a/src/libneochat/chatkeyhelper.cpp +++ b/src/libneochat/chatkeyhelper.cpp @@ -22,6 +22,10 @@ bool ChatKeyHelper::handleKey(Qt::Key key, Qt::KeyboardModifiers modifiers) return up(modifiers); case Qt::Key_Down: return down(); + case Qt::Key_Left: + return left(); + case Qt::Key_Right: + return right(); case Qt::Key_Tab: return tab(); case Qt::Key_Delete: @@ -104,6 +108,30 @@ bool ChatKeyHelper::down() return false; } +bool ChatKeyHelper::left() +{ + if (!textItem) { + return false; + } + QTextCursor cursor = textItem->textCursor(); + if (cursor.isNull()) { + return false; + } + return selectLink(cursor, true); +} + +bool ChatKeyHelper::right() +{ + if (!textItem) { + return false; + } + QTextCursor cursor = textItem->textCursor(); + if (cursor.isNull()) { + return false; + } + return selectLink(cursor, false); +} + bool ChatKeyHelper::tab() { if (!textItem) { @@ -139,7 +167,7 @@ bool ChatKeyHelper::deleteChar() Q_EMIT unhandledDelete(); return true; } - return false; + return selectLink(cursor, false); } bool ChatKeyHelper::backspace() @@ -160,7 +188,7 @@ bool ChatKeyHelper::backspace() Q_EMIT unhandledBackspace(); return true; } - return false; + return selectLink(cursor, true); } bool ChatKeyHelper::insertReturn(Qt::KeyboardModifiers modifiers) @@ -227,4 +255,60 @@ bool ChatKeyHelper::pasteImage() return false; } +bool ChatKeyHelper::selectLink(QTextCursor &cursor, bool back) +{ + if (cursor.hasSelection() || (!cursor.charFormat().isAnchor() && back) || (!back && cursor.atBlockEnd())) { + return false; + } + + // If we are on the very right and going right we need to exit. + if (!back) { + const auto startPos = cursor.position(); + cursor.movePosition(QTextCursor::NextCharacter); + if (cursor.charFormat().isAnchor()) { + cursor.setPosition(startPos); + } else { + return false; + } + } + + // Figure out if we're on the left side of a link. + // note a cusor on the leftmost of a link will not have the anchor set in char format. + bool onLeft = false; + if (!cursor.charFormat().isAnchor() && !back) { + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); + if (cursor.charFormat().isAnchor()) { + onLeft = true; + } else { + return false; + } + } + + const auto hRef = cursor.charFormat().anchorHref(); + auto currentCharFormat = cursor.charFormat(); + + // If not on the left figure out where it is. + if (!onLeft) { + const auto startPos = cursor.position(); + while (currentCharFormat.isAnchor() && currentCharFormat.anchorHref() == hRef && cursor.position() > 0) { + cursor.movePosition(QTextCursor::PreviousCharacter); + currentCharFormat = cursor.charFormat(); + } + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, startPos - cursor.position()); + } + // Then select everything to right. + // We do it this way so it works when you start in the middle. + currentCharFormat = cursor.charFormat(); + while (currentCharFormat.isAnchor() && currentCharFormat.anchorHref() == hRef && cursor.position() < cursor.block().length() - 1) { + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor); + currentCharFormat = cursor.charFormat(); + } + if (!currentCharFormat.isAnchor()) { + cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); + } + + textItem->setSelection(cursor); + return true; +} + #include "moc_chatkeyhelper.cpp" diff --git a/src/libneochat/chatkeyhelper.h b/src/libneochat/chatkeyhelper.h index 8a3e30a17..5b8e80325 100644 --- a/src/libneochat/chatkeyhelper.h +++ b/src/libneochat/chatkeyhelper.h @@ -6,6 +6,8 @@ #include #include +class QTextCursor; + class ChatTextItemHelper; /** @@ -119,6 +121,10 @@ private: bool down(); + bool left(); + + bool right(); + bool tab(); bool deleteChar(); @@ -130,4 +136,6 @@ private: bool cancel(); bool pasteImage(); + + bool selectLink(QTextCursor &cursor, bool back); }; diff --git a/src/libneochat/chattextitemhelper.cpp b/src/libneochat/chattextitemhelper.cpp index 069928a15..ceaeb0760 100644 --- a/src/libneochat/chattextitemhelper.cpp +++ b/src/libneochat/chattextitemhelper.cpp @@ -387,6 +387,14 @@ void ChatTextItemHelper::setCursorPosition(int pos) m_textItem->setProperty("cursorPosition", pos); } +void ChatTextItemHelper::setSelection(const QTextCursor &cursor) +{ + if (!m_textItem) { + return; + } + metaObject()->invokeMethod(m_textItem, "select", Qt::DirectConnection, cursor.selectionStart(), cursor.selectionEnd()); +} + void ChatTextItemHelper::setCursorVisible(bool visible) { if (!m_textItem) { diff --git a/src/libneochat/chattextitemhelper.h b/src/libneochat/chattextitemhelper.h index 3595dbf1e..12a25870f 100644 --- a/src/libneochat/chattextitemhelper.h +++ b/src/libneochat/chattextitemhelper.h @@ -187,6 +187,11 @@ public: */ void setCursorPosition(int pos); + /** + * @brief Set the selection of the underlying text item to the given cursor. + */ + void setSelection(const QTextCursor &cursor); + /** * @brief Set the cursor visibility of the underlying text item to the given value. */