mirror of
https://github.com/Palm1r/QodeAssist.git
synced 2025-11-22 02:22:44 -05:00
feat: Add open in editor and remove from list (#267)
* refactor: Rename and move chat items * feat: Add hotkeys for open in editor and remove file from list * feat: Add opening by system * feat: Add context action menu
This commit is contained in:
@ -10,18 +10,20 @@ qt_add_qml_module(QodeAssistChatView
|
|||||||
QtQuick
|
QtQuick
|
||||||
QML_FILES
|
QML_FILES
|
||||||
qml/RootItem.qml
|
qml/RootItem.qml
|
||||||
qml/ChatItem.qml
|
|
||||||
qml/dialog/CodeBlock.qml
|
qml/chatparts/CodeBlock.qml
|
||||||
qml/dialog/TextBlock.qml
|
qml/chatparts/FileEditBlock.qml
|
||||||
qml/parts/TopBar.qml
|
qml/chatparts/TextBlock.qml
|
||||||
qml/parts/BottomBar.qml
|
qml/chatparts/ThinkingBlock.qml
|
||||||
qml/parts/AttachedFilesPlace.qml
|
qml/chatparts/ToolBlock.qml
|
||||||
qml/parts/Toast.qml
|
qml/chatparts/ChatItem.qml
|
||||||
qml/ToolStatusItem.qml
|
|
||||||
qml/ThinkingStatusItem.qml
|
qml/controls/AttachedFilesPlace.qml
|
||||||
qml/FileEditItem.qml
|
qml/controls/BottomBar.qml
|
||||||
qml/parts/RulesViewer.qml
|
qml/controls/FileEditsActionBar.qml
|
||||||
qml/parts/FileEditsActionBar.qml
|
qml/controls/RulesViewer.qml
|
||||||
|
qml/controls/Toast.qml
|
||||||
|
qml/controls/TopBar.qml
|
||||||
|
|
||||||
RESOURCES
|
RESOURCES
|
||||||
icons/attach-file-light.svg
|
icons/attach-file-light.svg
|
||||||
@ -56,7 +58,7 @@ qt_add_qml_module(QodeAssistChatView
|
|||||||
ChatSerializer.hpp ChatSerializer.cpp
|
ChatSerializer.hpp ChatSerializer.cpp
|
||||||
ChatView.hpp ChatView.cpp
|
ChatView.hpp ChatView.cpp
|
||||||
ChatData.hpp
|
ChatData.hpp
|
||||||
|
FileItem.hpp FileItem.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(QodeAssistChatView
|
target_link_libraries(QodeAssistChatView
|
||||||
|
|||||||
76
ChatView/FileItem.cpp
Normal file
76
ChatView/FileItem.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FileItem.hpp"
|
||||||
|
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
|
#include <logger/Logger.hpp>
|
||||||
|
#include <utils/filepath.h>
|
||||||
|
|
||||||
|
namespace QodeAssist::Chat {
|
||||||
|
|
||||||
|
FileItem::FileItem(QQuickItem *parent)
|
||||||
|
: QQuickItem(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void FileItem::openFileInEditor()
|
||||||
|
{
|
||||||
|
if (m_filePath.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::FilePath filePathObj = Utils::FilePath::fromString(m_filePath);
|
||||||
|
Core::IEditor *editor = Core::EditorManager::openEditor(filePathObj);
|
||||||
|
|
||||||
|
if (!editor) {
|
||||||
|
LOG_MESSAGE(QString("Failed to open file in editor: %1").arg(m_filePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileItem::openFileInExternalEditor()
|
||||||
|
{
|
||||||
|
if (m_filePath.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = QDesktopServices::openUrl(QUrl::fromLocalFile(m_filePath));
|
||||||
|
if (success) {
|
||||||
|
LOG_MESSAGE(QString("Opened file in external application: %1").arg(m_filePath));
|
||||||
|
} else {
|
||||||
|
LOG_MESSAGE(QString("Failed to open file externally: %1").arg(m_filePath));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileItem::filePath() const
|
||||||
|
{
|
||||||
|
return m_filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileItem::setFilePath(const QString &newFilePath)
|
||||||
|
{
|
||||||
|
if (m_filePath == newFilePath)
|
||||||
|
return;
|
||||||
|
m_filePath = newFilePath;
|
||||||
|
emit filePathChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QodeAssist::Chat
|
||||||
48
ChatView/FileItem.hpp
Normal file
48
ChatView/FileItem.hpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QQuickItem>
|
||||||
|
|
||||||
|
namespace QodeAssist::Chat {
|
||||||
|
|
||||||
|
class FileItem: public QQuickItem
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_NAMED_ELEMENT(FileItem)
|
||||||
|
|
||||||
|
Q_PROPERTY(QString filePath READ filePath WRITE setFilePath NOTIFY filePathChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
FileItem(QQuickItem *parent = nullptr);
|
||||||
|
|
||||||
|
Q_INVOKABLE void openFileInEditor();
|
||||||
|
Q_INVOKABLE void openFileInExternalEditor();
|
||||||
|
|
||||||
|
QString filePath() const;
|
||||||
|
void setFilePath(const QString &newFilePath);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void filePathChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_filePath;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -24,7 +24,8 @@ import QtQuick.Layouts
|
|||||||
import ChatView
|
import ChatView
|
||||||
import UIControls
|
import UIControls
|
||||||
import Qt.labs.platform as Platform
|
import Qt.labs.platform as Platform
|
||||||
import "./parts"
|
|
||||||
|
import "./chatparts"
|
||||||
|
|
||||||
ChatRootView {
|
ChatRootView {
|
||||||
id: root
|
id: root
|
||||||
@ -188,7 +189,7 @@ ChatRootView {
|
|||||||
Component {
|
Component {
|
||||||
id: toolMessageComponent
|
id: toolMessageComponent
|
||||||
|
|
||||||
ToolStatusItem {
|
ToolBlock {
|
||||||
id: toolsItem
|
id: toolsItem
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@ -208,7 +209,7 @@ ChatRootView {
|
|||||||
Component {
|
Component {
|
||||||
id: fileEditMessageComponent
|
id: fileEditMessageComponent
|
||||||
|
|
||||||
FileEditItem {
|
FileEditBlock {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
editContent: model.content
|
editContent: model.content
|
||||||
|
|
||||||
@ -233,7 +234,7 @@ ChatRootView {
|
|||||||
Component {
|
Component {
|
||||||
id: thinkingMessageComponent
|
id: thinkingMessageComponent
|
||||||
|
|
||||||
ThinkingStatusItem {
|
ThinkingBlock {
|
||||||
id: thinking
|
id: thinking
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|||||||
@ -23,8 +23,6 @@ import QtQuick.Controls
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import UIControls
|
import UIControls
|
||||||
|
|
||||||
import "./dialog"
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@ -40,19 +40,68 @@ Flow {
|
|||||||
Repeater {
|
Repeater {
|
||||||
id: attachRepeater
|
id: attachRepeater
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: FileItem {
|
||||||
|
id: fileItem
|
||||||
|
|
||||||
required property int index
|
required property int index
|
||||||
required property string modelData
|
required property string modelData
|
||||||
|
|
||||||
|
filePath: modelData
|
||||||
|
|
||||||
height: 30
|
height: 30
|
||||||
width: contentRow.width + 10
|
width: contentRow.width + 10
|
||||||
radius: 4
|
|
||||||
color: palette.button
|
|
||||||
border.width: 1
|
|
||||||
border.color: mouse.hovered ? palette.highlight : root.accentColor
|
|
||||||
|
|
||||||
HoverHandler {
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 4
|
||||||
|
color: palette.button
|
||||||
|
border.width: 1
|
||||||
|
border.color: mouse.containsMouse ? palette.highlight : root.accentColor
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
id: mouse
|
id: mouse
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
if (mouse.button === Qt.RightButton) {
|
||||||
|
contextMenu.popup()
|
||||||
|
} else if (mouse.button === Qt.MiddleButton ||
|
||||||
|
(mouse.button === Qt.LeftButton && (mouse.modifiers & Qt.ControlModifier))) {
|
||||||
|
root.removeFileFromListByIndex(fileItem.index)
|
||||||
|
} else if (mouse.modifiers & Qt.ShiftModifier) {
|
||||||
|
fileItem.openFileInExternalEditor()
|
||||||
|
} else {
|
||||||
|
fileItem.openFileInEditor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToolTip.visible: containsMouse
|
||||||
|
ToolTip.delay: 500
|
||||||
|
ToolTip.text: "Click: Open in Qt Creator\nShift+Click: Open in external editor\nCtrl+Click / Middle Click: Remove"
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
id: contextMenu
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Open in Qt Creator"
|
||||||
|
onTriggered: fileItem.openFileInEditor()
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Open in External Editor"
|
||||||
|
onTriggered: fileItem.openFileInExternalEditor()
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuSeparator {}
|
||||||
|
|
||||||
|
MenuItem {
|
||||||
|
text: "Remove"
|
||||||
|
onTriggered: root.removeFileFromListByIndex(fileItem.index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
Reference in New Issue
Block a user