fix: Throwing focus and hotkeys to QtCreator

This commit is contained in:
Petr Mironychev
2026-05-15 21:27:45 +02:00
parent cc2d42f6d7
commit b1ca6823b8
11 changed files with 129 additions and 26 deletions

View File

@@ -1,5 +1,10 @@
cmake_minimum_required(VERSION 3.16)
# list(APPEND CMAKE_PREFIX_PATH "/Users/palm1r/Qt/Qt Creator 20.0.0-beta1.app/Contents/Resources")
list(APPEND CMAKE_PREFIX_PATH "/Users/palm1r/Qt/Qt Creator 20.0.0-beta1.sdk/lib/cmake/QtCreator")
# list(APPEND CMAKE_PREFIX_PATH "/Users/palm1r/Qt/Qt Creator 20.0.0-beta1.sdk")
# list(APPEND CMAKE_PREFIX_PATH "/Users/palm1r/Qt/Qt Creator 20.0.0-beta1.app/Contents/Resources")
project(QodeAssist)
set(CMAKE_AUTOMOC ON)

View File

@@ -94,5 +94,5 @@ target_link_libraries(QodeAssistChatView
)
target_include_directories(QodeAssistChatView
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_SOURCE_DIR}
)

View File

@@ -6,12 +6,16 @@
#include <QQmlComponent>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickItem>
#include <QSettings>
#include <QVariantMap>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <logger/Logger.hpp>
#include "QodeAssistConstants.hpp"
namespace {
constexpr Qt::WindowFlags baseFlags = Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint
| Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint
@@ -39,20 +43,31 @@ ChatView::ChatView(QQmlEngine* engine)
setMinimumSize({400, 300});
setFlags(baseFlags);
if (auto action = Core::ActionManager::command("QodeAssist.CloseChatView")) {
m_closeShortcut = new QShortcut(action->keySequence(), this);
connect(m_closeShortcut, &QShortcut::activated, this, &QQuickView::close);
connect(action, &Core::Command::keySequenceChanged, this, [action, this]() {
if (m_closeShortcut) {
m_closeShortcut->setKey(action->keySequence());
}
});
}
bindCommandShortcut("QodeAssist.CloseChatView", [this] { close(); });
bindCommandShortcut(Constants::QODE_ASSIST_CHAT_SEND_MESSAGE, [this] {
QMetaObject::invokeMethod(rootObject(), "sendChatMessage");
});
bindCommandShortcut(Constants::QODE_ASSIST_CHAT_CLEAR_SESSION, [this] {
QMetaObject::invokeMethod(rootObject(), "clearChat");
});
restoreSettings();
}
void ChatView::bindCommandShortcut(Utils::Id commandId,
const std::function<void()> &onActivated)
{
auto command = Core::ActionManager::command(commandId);
if (!command)
return;
auto shortcut = new QShortcut(command->keySequence(), this);
connect(shortcut, &QShortcut::activated, this, onActivated);
connect(command, &Core::Command::keySequenceChanged, shortcut, [command, shortcut]() {
shortcut->setKey(command->keySequence());
});
}
void ChatView::closeEvent(QCloseEvent *event)
{
saveSettings();

View File

@@ -3,6 +3,10 @@
#pragma once
#include <functional>
#include <utils/id.h>
#include <QQuickView>
#include <QShortcut>
@@ -27,9 +31,9 @@ protected:
private:
void saveSettings();
void restoreSettings();
void bindCommandShortcut(Utils::Id commandId, const std::function<void()> &onActivated);
bool m_isPin;
QShortcut *m_closeShortcut;
};
} // namespace QodeAssist::Chat

View File

@@ -3,8 +3,15 @@
#include "ChatWidget.hpp"
#include <QApplication>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickItem>
#include <coreplugin/icontext.h>
#include <coreplugin/icore.h>
#include "QodeAssistConstants.hpp"
namespace QodeAssist::Chat {
@@ -20,6 +27,12 @@ ChatWidget::ChatWidget(QQmlEngine* engine, QWidget *parent)
setContent(component->url(), component, rootItem);
}
setResizeMode(QQuickWidget::SizeRootObjectToView);
setFocusPolicy(Qt::StrongFocus);
auto ideContext = new Core::IContext{this};
ideContext->setWidget(this);
ideContext->setContext(Core::Context{Constants::QODE_ASSIST_CHAT_CONTEXT});
Core::ICore::addContextObject(ideContext);
}
void ChatWidget::clear()
@@ -31,4 +44,35 @@ void ChatWidget::scrollToBottom()
{
QMetaObject::invokeMethod(rootObject(), "scrollToBottom");
}
void ChatWidget::focusInput()
{
setFocus(Qt::OtherFocusReason);
QMetaObject::invokeMethod(rootObject(), "focusInput");
}
bool ChatWidget::isChatFocused() const
{
return hasFocus() || (rootObject() && rootObject()->hasActiveFocus());
}
void ChatWidget::sendMessage()
{
QMetaObject::invokeMethod(rootObject(), "sendChatMessage");
}
void ChatWidget::clearSession()
{
QMetaObject::invokeMethod(rootObject(), "clearChat");
}
ChatWidget *ChatWidget::focusedInstance()
{
for (QWidget *widget = QApplication::focusWidget(); widget;
widget = widget->parentWidget()) {
if (auto chatWidget = qobject_cast<ChatWidget *>(widget))
return chatWidget;
}
return nullptr;
}
} // namespace QodeAssist::Chat

View File

@@ -17,6 +17,14 @@ public:
Q_INVOKABLE void clear();
Q_INVOKABLE void scrollToBottom();
Q_INVOKABLE void focusInput();
void sendMessage();
void clearSession();
bool isChatFocused() const;
static ChatWidget *focusedInstance();
signals:
void clearPressed();

View File

@@ -526,15 +526,6 @@ ChatRootView {
}
}
Shortcut {
id: sendMessageShortcut
sequences: ["Ctrl+Return", "Ctrl+Enter"]
context: Qt.WindowShortcut
enabled: messageInput.activeFocus && !Qt.inputMethod.visible && !fileMentionPopup.visible
onActivated: root.sendChatMessage()
}
function clearChat() {
root.clearMessages()
root.clearAttachmentFiles()
@@ -545,6 +536,10 @@ ChatRootView {
Qt.callLater(chatListView.positionViewAtEnd)
}
function focusInput() {
messageInput.forceActiveFocus()
}
function applyMentionSelection() {
var result = fileMentionPopup.applyCurrentSelection(
messageInput.text, messageInput.cursorPosition, root.useTools)
@@ -654,6 +649,6 @@ ChatRootView {
}
Component.onCompleted: {
messageInput.forceActiveFocus()
focusInput()
}
}

View File

@@ -10,4 +10,11 @@ const char MENU_ID[] = "QodeAssist.Menu";
const char QODE_ASSIST_REQUEST_SUGGESTION[] = "QodeAssist.RequestSuggestion";
const char QODE_ASSIST_CHAT_CONTEXT[] = "QodeAssist.ChatContext";
const char QODE_ASSIST_CHAT_NAV_ID[] = "QodeAssistChat";
const char QODE_ASSIST_CHAT_SEND_MESSAGE[] = "QodeAssist.Chat.SendMessage";
const char QODE_ASSIST_CHAT_CLEAR_SESSION[] = "QodeAssist.Chat.ClearSession";
const char QODE_ASSIST_CHAT_SHOW_IN_RIGHT[] = "QodeAssist.Chat.ShowInRightSidebar";
} // namespace QodeAssist::Constants

View File

@@ -38,18 +38,20 @@ void ChatOutputPane::clearContents()
void ChatOutputPane::visibilityChanged(bool visible)
{
if (visible)
if (visible) {
m_chatWidget->scrollToBottom();
m_chatWidget->focusInput();
}
}
void ChatOutputPane::setFocus()
{
m_chatWidget->setFocus();
m_chatWidget->focusInput();
}
bool ChatOutputPane::hasFocus() const
{
return m_chatWidget->hasFocus();
return m_chatWidget->isChatFocused();
}
bool ChatOutputPane::canFocus() const

View File

@@ -4,6 +4,7 @@
#include "NavigationPanel.hpp"
#include "ChatView/ChatWidget.hpp"
#include "QodeAssistConstants.hpp"
namespace QodeAssist::Chat {
@@ -12,7 +13,7 @@ NavigationPanel::NavigationPanel(QQmlEngine* engine)
{
setDisplayName(tr("QodeAssist Chat"));
setPriority(500);
setId("QodeAssistChat");
setId(Constants::QODE_ASSIST_CHAT_NAV_ID);
setActivationSequence(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_C));
}

View File

@@ -14,6 +14,7 @@
#include <coreplugin/icore.h>
#include <coreplugin/messagemanager.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/navigationwidget.h>
#include <coreplugin/statusbarmanager.h>
#include <extensionsystem/iplugin.h>
#include <languageclient/languageclientmanager.h>
@@ -50,6 +51,7 @@
#include "widgets/QuickRefactorDialog.hpp"
#include <ChatView/ChatView.hpp>
#include <ChatView/ChatFileManager.hpp>
#include <ChatView/ChatWidget.hpp>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <texteditor/textdocument.h>
@@ -230,6 +232,26 @@ public:
}
});
ActionBuilder sendMessageAction(this, Constants::QODE_ASSIST_CHAT_SEND_MESSAGE);
sendMessageAction.setContext(Core::Context(Constants::QODE_ASSIST_CHAT_CONTEXT));
sendMessageAction.setText(Tr::tr("Send QodeAssist Chat Message"));
sendMessageAction.setToolTip(Tr::tr("Send the current message to the LLM"));
sendMessageAction.setDefaultKeySequence(QKeySequence(Qt::CTRL | Qt::Key_Return));
sendMessageAction.addOnTriggered(this, [] {
if (auto chatWidget = Chat::ChatWidget::focusedInstance())
chatWidget->sendMessage();
});
ActionBuilder clearSessionAction(this, Constants::QODE_ASSIST_CHAT_CLEAR_SESSION);
clearSessionAction.setContext(Core::Context(Constants::QODE_ASSIST_CHAT_CONTEXT));
clearSessionAction.setText(Tr::tr("Clear QodeAssist Chat Session"));
clearSessionAction.setToolTip(Tr::tr("Clear the current chat session"));
clearSessionAction.setDefaultKeySequence(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_L));
clearSessionAction.addOnTriggered(this, [] {
if (auto chatWidget = Chat::ChatWidget::focusedInstance())
chatWidget->clearSession();
});
Core::ActionContainer *editorContextMenu = Core::ActionManager::actionContainer(
TextEditor::Constants::M_STANDARDCONTEXTMENU);
if (editorContextMenu) {