Фазы 2-3: мульти-окна (WindowController, per-window FileStore), файловое дерево (FileStore+FileTreePanel, иконки/раскрытие/ПКМ/+drag&drop/подтверждения), NameDialog/ConfirmDialog; тест filestore (13/13)

This commit is contained in:
Flora (opencode)
2026-08-17 01:02:05 +03:00
parent ed633ae036
commit c740c9a756
12 changed files with 1305 additions and 76 deletions
+76
View File
@@ -0,0 +1,76 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
// Подтверждение удаления. Для непустой папки требуется двойное подтверждение:
// первое нажатие показывает предупреждение, второе — удаляет.
Dialog {
id: root
property string message: ""
property bool doubleConfirm: false
signal confirmed()
title: qsTr("Подтверждение")
modal: true
width: 420
anchors.centerIn: parent
closePolicy: Dialog.NoAutoClose
standardButtons: Dialog.NoButton
property bool armed: false
function resetDialog() {
root.armed = false
deleteButton.text = qsTr("Удалить")
warnLabel.visible = false
}
onOpened: root.resetDialog()
ColumnLayout {
anchors.fill: parent
spacing: 12
Label {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: root.message
}
Label {
id: warnLabel
Layout.fillWidth: true
wrapMode: Text.Wrap
visible: false
color: "#b00020"
text: qsTr("Внимание: папка содержит файлы. Они будут удалены безвозвратно.\n"
+ "Если вы уверены — нажмите «Точно удалить».")
}
RowLayout {
Layout.fillWidth: true
Item { Layout.fillWidth: true }
Button {
text: qsTr("Отмена")
onClicked: root.reject()
}
Button {
id: deleteButton
text: qsTr("Удалить")
highlighted: root.armed
onClicked: {
if (root.doubleConfirm && !root.armed) {
root.armed = true
deleteButton.text = qsTr("Точно удалить")
warnLabel.visible = true
return
}
root.confirmed()
root.accept()
}
}
}
}
}
+76
View File
@@ -0,0 +1,76 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
// Диалог ввода имени (новый файл/папка, переименование).
Dialog {
id: root
property string dialogTitle: qsTr("Имя")
property string actionLabel: qsTr("OK")
property string initialText: ""
property string errorText: ""
signal confirmed(string text)
title: dialogTitle
modal: true
width: 380
anchors.centerIn: parent
closePolicy: Dialog.NoAutoClose
standardButtons: Dialog.NoButton
ColumnLayout {
anchors.fill: parent
spacing: 10
TextField {
id: nameField
Layout.fillWidth: true
placeholderText: qsTr("Введите имя…")
text: root.initialText
selectByMouse: true
// Русская клавиатура: первая буква — заглавная
inputMethodHints: Qt.ImhNoPredictiveText
Component.onCompleted: {
forceActiveFocus()
selectAll()
}
onAccepted: root.tryConfirm()
onTextChanged: root.errorText = ""
}
Label {
id: errorLabel
Layout.fillWidth: true
visible: root.errorText.length > 0
color: "#b00020"
wrapMode: Text.Wrap
text: root.errorText
}
RowLayout {
Layout.fillWidth: true
Item { Layout.fillWidth: true }
Button {
text: qsTr("Отмена")
onClicked: root.reject()
}
Button {
text: root.actionLabel
enabled: nameField.text.trim().length > 0
onClicked: root.tryConfirm()
}
}
}
function tryConfirm() {
const n = nameField.text.trim()
if (n.length === 0) {
root.errorText = qsTr("Имя не может быть пустым.")
return
}
root.confirmed(n)
root.accept()
}
}