diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0c1810f..0ce868b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -105,6 +105,7 @@ add_qtc_plugin(QodeAssist
widgets/ProgressWidget.hpp widgets/ProgressWidget.cpp
widgets/EditorChatButton.hpp widgets/EditorChatButton.cpp
widgets/EditorChatButtonHandler.hpp widgets/EditorChatButtonHandler.cpp
+ widgets/QuickRefactorDialog.hpp widgets/QuickRefactorDialog.cpp
QuickRefactorHandler.hpp QuickRefactorHandler.cpp
)
diff --git a/QodeAssist.qrc b/QodeAssist.qrc
index 35c2108..fe0d593 100644
--- a/QodeAssist.qrc
+++ b/QodeAssist.qrc
@@ -2,5 +2,11 @@
resources/images/qoderassist-icon@2x.png
resources/images/qoderassist-icon.png
+ resources/images/repeat-last-instruct-icon@2x.png
+ resources/images/repeat-last-instruct-icon.png
+ resources/images/improve-current-code-icon@2x.png
+ resources/images/improve-current-code-icon.png
+ resources/images/suggest-new-icon.png
+ resources/images/suggest-new-icon@2x.png
diff --git a/QodeAssistClient.cpp b/QodeAssistClient.cpp
index a5e2422..bcb1110 100644
--- a/QodeAssistClient.cpp
+++ b/QodeAssistClient.cpp
@@ -352,7 +352,6 @@ void QodeAssistClient::cleanupConnections()
void QodeAssistClient::handleRefactoringResult(const RefactorResult &result)
{
- m_progressHandler.hideProgress();
if (!result.success) {
LOG_MESSAGE(QString("Refactoring failed: %1").arg(result.errorMessage));
return;
@@ -377,5 +376,6 @@ void QodeAssistClient::handleRefactoringResult(const RefactorResult &result)
cursor.insertText(result.newText);
cursor.endEditBlock();
+ m_progressHandler.hideProgress();
}
} // namespace QodeAssist
diff --git a/qodeassist.cpp b/qodeassist.cpp
index 8b6da81..8f459f3 100644
--- a/qodeassist.cpp
+++ b/qodeassist.cpp
@@ -56,6 +56,7 @@
#include "settings/ProjectSettingsPanel.hpp"
#include "settings/SettingsConstants.hpp"
#include "templates/Templates.hpp"
+#include "widgets/QuickRefactorDialog.hpp"
#include
#include
#include
@@ -148,17 +149,17 @@ public:
quickRefactorAction.setIcon(QCODEASSIST_ICON.icon());
quickRefactorAction.addOnTriggered(this, [this] {
if (auto editor = TextEditor::TextEditorWidget::currentTextEditorWidget()) {
- bool ok;
if (m_qodeAssistClient && m_qodeAssistClient->reachable()) {
- QString instructions = QInputDialog::getText(
- Core::ICore::dialogParent(),
- Tr::tr("Quick Refactor"),
- Tr::tr("Enter refactoring instructions:"),
- QLineEdit::Normal,
- QString(),
- &ok);
- if (ok)
- m_qodeAssistClient->requestQuickRefactor(editor, instructions);
+ QuickRefactorDialog
+ dialog(Core::ICore::dialogParent(), m_lastRefactorInstructions);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ QString instructions = dialog.instructions();
+ if (!instructions.isEmpty()) {
+ m_lastRefactorInstructions = instructions;
+ m_qodeAssistClient->requestQuickRefactor(editor, instructions);
+ }
+ }
} else {
qWarning() << "The QodeAssist is not ready. Please check your connection and "
"settings.";
@@ -235,6 +236,7 @@ private:
QPointer m_navigationPanel;
QPointer m_updater;
UpdateStatusWidget *m_statusWidget{nullptr};
+ QString m_lastRefactorInstructions;
};
} // namespace QodeAssist::Internal
diff --git a/resources/images/improve-current-code-icon.png b/resources/images/improve-current-code-icon.png
new file mode 100644
index 0000000..2108d98
Binary files /dev/null and b/resources/images/improve-current-code-icon.png differ
diff --git a/resources/images/improve-current-code-icon@2x.png b/resources/images/improve-current-code-icon@2x.png
new file mode 100644
index 0000000..ec9262c
Binary files /dev/null and b/resources/images/improve-current-code-icon@2x.png differ
diff --git a/resources/images/repeat-last-instruct-icon.png b/resources/images/repeat-last-instruct-icon.png
new file mode 100644
index 0000000..7a5e66e
Binary files /dev/null and b/resources/images/repeat-last-instruct-icon.png differ
diff --git a/resources/images/repeat-last-instruct-icon@2x.png b/resources/images/repeat-last-instruct-icon@2x.png
new file mode 100644
index 0000000..32314c0
Binary files /dev/null and b/resources/images/repeat-last-instruct-icon@2x.png differ
diff --git a/resources/images/suggest-new-icon.png b/resources/images/suggest-new-icon.png
new file mode 100644
index 0000000..297da26
Binary files /dev/null and b/resources/images/suggest-new-icon.png differ
diff --git a/resources/images/suggest-new-icon@2x.png b/resources/images/suggest-new-icon@2x.png
new file mode 100644
index 0000000..7bd568e
Binary files /dev/null and b/resources/images/suggest-new-icon@2x.png differ
diff --git a/widgets/QuickRefactorDialog.cpp b/widgets/QuickRefactorDialog.cpp
new file mode 100644
index 0000000..e53a6ef
--- /dev/null
+++ b/widgets/QuickRefactorDialog.cpp
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2025 Petr Mironychev
+ *
+ * This file is part of QodeAssist.
+ *
+ * QodeAssist is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QodeAssist is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QodeAssist. If not, see .
+ */
+
+#include "QuickRefactorDialog.hpp"
+#include "QodeAssisttr.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+namespace QodeAssist {
+
+QuickRefactorDialog::QuickRefactorDialog(QWidget *parent, const QString &lastInstructions)
+ : QDialog(parent)
+ , m_lastInstructions(lastInstructions)
+{
+ setWindowTitle(Tr::tr("Quick Refactor"));
+ setupUi();
+
+ QTimer::singleShot(0, this, &QuickRefactorDialog::updateDialogSize);
+ m_textEdit->installEventFilter(this);
+ updateDialogSize();
+}
+
+void QuickRefactorDialog::setupUi()
+{
+ QVBoxLayout *mainLayout = new QVBoxLayout(this);
+ mainLayout->setContentsMargins(10, 10, 10, 10);
+ mainLayout->setSpacing(8);
+
+ QHBoxLayout *actionsLayout = new QHBoxLayout();
+ actionsLayout->setSpacing(4);
+ createActionButtons();
+ actionsLayout->addWidget(m_repeatButton);
+ actionsLayout->addWidget(m_improveButton);
+ actionsLayout->addWidget(m_alternativeButton);
+ actionsLayout->addStretch();
+ mainLayout->addLayout(actionsLayout);
+
+ m_instructionsLabel = new QLabel(Tr::tr("Enter refactoring instructions:"), this);
+ mainLayout->addWidget(m_instructionsLabel);
+
+ m_textEdit = new QPlainTextEdit(this);
+ m_textEdit->setMinimumHeight(100);
+ m_textEdit->setPlaceholderText(Tr::tr("Type your refactoring instructions here..."));
+
+ connect(m_textEdit, &QPlainTextEdit::textChanged, this, &QuickRefactorDialog::updateDialogSize);
+
+ mainLayout->addWidget(m_textEdit);
+
+ QDialogButtonBox *buttonBox
+ = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ mainLayout->addWidget(buttonBox);
+}
+
+void QuickRefactorDialog::createActionButtons()
+{
+ Utils::Icon REPEAT_ICON(
+ {{":/resources/images/repeat-last-instruct-icon.png", Utils::Theme::IconsBaseColor}});
+ Utils::Icon IMPROVE_ICON(
+ {{":/resources/images/improve-current-code-icon.png", Utils::Theme::IconsBaseColor}});
+ Utils::Icon ALTER_ICON(
+ {{":/resources/images/suggest-new-icon.png", Utils::Theme::IconsBaseColor}});
+ m_repeatButton = new QToolButton(this);
+ m_repeatButton->setIcon(REPEAT_ICON.icon());
+ m_repeatButton->setToolTip(Tr::tr("Repeat Last Instructions"));
+ m_repeatButton->setEnabled(!m_lastInstructions.isEmpty());
+ connect(m_repeatButton, &QToolButton::clicked, this, &QuickRefactorDialog::useLastInstructions);
+
+ m_improveButton = new QToolButton(this);
+ m_improveButton->setIcon(IMPROVE_ICON.icon());
+ m_improveButton->setToolTip(Tr::tr("Improve Current Code"));
+ connect(
+ m_improveButton, &QToolButton::clicked, this, &QuickRefactorDialog::useImproveCodeTemplate);
+
+ m_alternativeButton = new QToolButton(this);
+ m_alternativeButton->setIcon(ALTER_ICON.icon());
+ m_alternativeButton->setToolTip(Tr::tr("Suggest Alternative Solution"));
+ connect(
+ m_alternativeButton,
+ &QToolButton::clicked,
+ this,
+ &QuickRefactorDialog::useAlternativeSolutionTemplate);
+}
+
+QString QuickRefactorDialog::instructions() const
+{
+ return m_textEdit->toPlainText();
+}
+
+void QuickRefactorDialog::setInstructions(const QString &instructions)
+{
+ m_textEdit->setPlainText(instructions);
+}
+
+QuickRefactorDialog::Action QuickRefactorDialog::selectedAction() const
+{
+ return m_selectedAction;
+}
+
+bool QuickRefactorDialog::eventFilter(QObject *watched, QEvent *event)
+{
+ if (watched == m_textEdit && event->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast(event);
+ if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
+ if (keyEvent->modifiers() & Qt::ShiftModifier) {
+ return false;
+ }
+
+ accept();
+ return true;
+ }
+ }
+ return QDialog::eventFilter(watched, event);
+}
+
+void QuickRefactorDialog::useLastInstructions()
+{
+ if (!m_lastInstructions.isEmpty()) {
+ m_textEdit->setPlainText(m_lastInstructions);
+ m_selectedAction = Action::RepeatLast;
+ }
+ accept();
+}
+
+void QuickRefactorDialog::useImproveCodeTemplate()
+{
+ m_textEdit->setPlainText(Tr::tr(
+ "Improve the selected code by enhancing readability, efficiency, and maintainability. "
+ "Follow best practices for C++/Qt and fix any potential issues."));
+ m_selectedAction = Action::ImproveCode;
+ accept();
+}
+
+void QuickRefactorDialog::useAlternativeSolutionTemplate()
+{
+ m_textEdit->setPlainText(
+ Tr::tr("Suggest an alternative implementation approach for the selected code. "
+ "Provide a different solution that might be cleaner, more efficient, "
+ "or uses different Qt/C++ patterns or idioms."));
+ m_selectedAction = Action::AlternativeSolution;
+ accept();
+}
+
+void QuickRefactorDialog::updateDialogSize()
+{
+ QString text = m_textEdit->toPlainText();
+
+ QFontMetrics fm(m_textEdit->font());
+
+ QStringList lines = text.split('\n');
+ int lineCount = lines.size();
+
+ if (lineCount <= 1) {
+ int singleLineHeight = fm.height() + 10;
+ m_textEdit->setMinimumHeight(singleLineHeight);
+ m_textEdit->setMaximumHeight(singleLineHeight);
+ } else {
+ m_textEdit->setMaximumHeight(QWIDGETSIZE_MAX);
+
+ int lineHeight = fm.height() + 2;
+
+ int textEditHeight = qMin(qMax(lineCount, 2) * lineHeight, 20 * lineHeight);
+ m_textEdit->setMinimumHeight(textEditHeight);
+ }
+
+ int maxWidth = 500;
+ for (const QString &line : lines) {
+ int lineWidth = fm.horizontalAdvance(line) + 30;
+ maxWidth = qMax(maxWidth, qMin(lineWidth, 800));
+ }
+
+ QScreen *screen = QApplication::primaryScreen();
+ QRect screenGeometry = screen->availableGeometry();
+
+ int newWidth = qMin(maxWidth + 40, screenGeometry.width() * 3 / 4);
+
+ int newHeight;
+ if (lineCount <= 1) {
+ newHeight = 150;
+ } else {
+ newHeight = m_textEdit->minimumHeight() + 150;
+ }
+ newHeight = qMin(newHeight, screenGeometry.height() * 3 / 4);
+
+ resize(newWidth, newHeight);
+}
+
+} // namespace QodeAssist
diff --git a/widgets/QuickRefactorDialog.hpp b/widgets/QuickRefactorDialog.hpp
new file mode 100644
index 0000000..0f5b7e8
--- /dev/null
+++ b/widgets/QuickRefactorDialog.hpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2025 Petr Mironychev
+ *
+ * This file is part of QodeAssist.
+ *
+ * QodeAssist is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * QodeAssist is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with QodeAssist. If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+
+class QPlainTextEdit;
+class QToolButton;
+class QLabel;
+
+namespace QodeAssist {
+
+class QuickRefactorDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ enum class Action { Custom, RepeatLast, ImproveCode, AlternativeSolution };
+
+ explicit QuickRefactorDialog(
+ QWidget *parent = nullptr, const QString &lastInstructions = QString());
+ ~QuickRefactorDialog() override = default;
+
+ QString instructions() const;
+ void setInstructions(const QString &instructions);
+
+ Action selectedAction() const;
+
+ bool eventFilter(QObject *watched, QEvent *event) override;
+
+private slots:
+ void useLastInstructions();
+ void useImproveCodeTemplate();
+ void useAlternativeSolutionTemplate();
+ void updateDialogSize();
+
+private:
+ void setupUi();
+ void createActionButtons();
+
+ QPlainTextEdit *m_textEdit;
+ QToolButton *m_repeatButton;
+ QToolButton *m_improveButton;
+ QToolButton *m_alternativeButton;
+ QLabel *m_instructionsLabel;
+
+ Action m_selectedAction = Action::Custom;
+ QString m_lastInstructions;
+};
+
+} // namespace QodeAssist