docs: 添加涉密文件自检工具实施计划
This commit is contained in:
@@ -0,0 +1,488 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
import QtQml 2.14 as Qml
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Controls.Private 1.0 as ControlsPrivate
|
||||
import QtQuick.Dialogs 1.1
|
||||
import QtQuick.Dialogs.Private 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Window 2.1
|
||||
import Qt.labs.folderlistmodel 2.1
|
||||
import Qt.labs.settings 1.0
|
||||
import "qml"
|
||||
|
||||
AbstractFileDialog {
|
||||
id: root
|
||||
|
||||
property Component modelComponent: Component {
|
||||
FolderListModel {
|
||||
showFiles: !root.selectFolder
|
||||
nameFilters: root.selectedNameFilterExtensions
|
||||
sortField: (view.sortIndicatorColumn === 0 ? FolderListModel.Name :
|
||||
(view.sortIndicatorColumn === 1 ? FolderListModel.Type :
|
||||
(view.sortIndicatorColumn === 2 ? FolderListModel.Size : FolderListModel.LastModified)))
|
||||
sortReversed: view.sortIndicatorOrder === Qt.DescendingOrder
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
// If the TableView doesn't have a model yet, create it asynchronously to avoid a UI freeze
|
||||
if (!view.model) {
|
||||
var incubator = modelComponent.incubateObject(null, { })
|
||||
function init(model) {
|
||||
view.model = model
|
||||
model.nameFilters = root.selectedNameFilterExtensions
|
||||
root.folder = model.folder
|
||||
}
|
||||
|
||||
if (incubator.status === Component.Ready) {
|
||||
init(incubator.object)
|
||||
} else {
|
||||
incubator.onStatusChanged = function(status) {
|
||||
if (status === Component.Ready)
|
||||
init(incubator.object)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
view.needsWidthAdjustment = true
|
||||
view.selection.clear()
|
||||
view.focus = true
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
filterField.currentIndex = root.selectedNameFilterIndex
|
||||
root.favoriteFolders = settings.favoriteFolders
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
settings.favoriteFolders = root.favoriteFolders
|
||||
}
|
||||
|
||||
property Settings settings: Settings {
|
||||
category: "QQControlsFileDialog"
|
||||
property alias width: root.width
|
||||
property alias height: root.height
|
||||
property alias sidebarWidth: sidebar.width
|
||||
property alias sidebarSplit: shortcutsScroll.height
|
||||
property alias sidebarVisible: root.sidebarVisible
|
||||
property variant favoriteFolders: []
|
||||
}
|
||||
|
||||
property bool showFocusHighlight: false
|
||||
property SystemPalette palette: SystemPalette { }
|
||||
property var favoriteFolders: []
|
||||
|
||||
function dirDown(path) {
|
||||
view.selection.clear()
|
||||
root.folder = "file://" + path
|
||||
}
|
||||
function dirUp() {
|
||||
view.selection.clear()
|
||||
if (view.model.parentFolder != "")
|
||||
root.folder = view.model.parentFolder
|
||||
}
|
||||
function acceptSelection() {
|
||||
// transfer the view's selections to QQuickFileDialog
|
||||
clearSelection()
|
||||
if (selectFolder && view.selection.count === 0)
|
||||
addSelection(folder)
|
||||
else {
|
||||
view.selection.forEach(function(idx) {
|
||||
if (view.model.isFolder(idx)) {
|
||||
if (selectFolder)
|
||||
addSelection(view.model.get(idx, "fileURL"))
|
||||
} else {
|
||||
if (!selectFolder)
|
||||
addSelection(view.model.get(idx, "fileURL"))
|
||||
}
|
||||
})
|
||||
}
|
||||
accept()
|
||||
}
|
||||
|
||||
property Action dirUpAction: Action {
|
||||
text: "\ue810"
|
||||
shortcut: "Ctrl+U"
|
||||
onTriggered: dirUp()
|
||||
tooltip: qsTr("Go up to the folder containing this one")
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: window
|
||||
implicitWidth: Math.min(root.__maximumDimension, Math.max(Screen.pixelDensity * 100, splitter.implicitWidth))
|
||||
implicitHeight: Math.min(root.__maximumDimension, Screen.pixelDensity * 80)
|
||||
color: root.palette.window
|
||||
|
||||
Qml.Binding {
|
||||
target: view.model
|
||||
property: "folder"
|
||||
value: root.folder
|
||||
restoreMode: Binding.RestoreBinding
|
||||
}
|
||||
Qml.Binding {
|
||||
target: currentPathField
|
||||
property: "text"
|
||||
value: root.urlToPath(root.folder)
|
||||
restoreMode: Binding.RestoreBinding
|
||||
}
|
||||
Keys.onPressed: {
|
||||
event.accepted = true
|
||||
switch (event.key) {
|
||||
case Qt.Key_Back:
|
||||
case Qt.Key_Escape:
|
||||
reject()
|
||||
break
|
||||
default:
|
||||
event.accepted = false
|
||||
break
|
||||
}
|
||||
}
|
||||
Keys.forwardTo: [view.flickableItem]
|
||||
|
||||
SplitView {
|
||||
id: splitter
|
||||
x: 0
|
||||
width: parent.width
|
||||
anchors.top: titleBar.bottom
|
||||
anchors.bottom: bottomBar.top
|
||||
|
||||
Column {
|
||||
id: sidebar
|
||||
Component.onCompleted: if (width < 1) width = sidebarSplitter.maxShortcutWidth
|
||||
height: parent.height
|
||||
width: 0 // initial width only; settings and onCompleted will override it
|
||||
visible: root.sidebarVisible
|
||||
SplitView {
|
||||
id: sidebarSplitter
|
||||
orientation: Qt.Vertical
|
||||
property real rowHeight: 10
|
||||
property real maxShortcutWidth: 80
|
||||
width: parent.width
|
||||
height: parent.height - favoritesButtons.height
|
||||
|
||||
ScrollView {
|
||||
id: shortcutsScroll
|
||||
Component.onCompleted: {
|
||||
if (height < 1)
|
||||
height = sidebarSplitter.rowHeight * 4.65
|
||||
Layout.minimumHeight = sidebarSplitter.rowHeight * 2.65
|
||||
}
|
||||
height: 0 // initial width only; settings and onCompleted will override it
|
||||
ListView {
|
||||
id: shortcutsView
|
||||
model: __shortcuts.length
|
||||
anchors.bottomMargin: ControlsPrivate.Settings.hasTouchScreen ? Screen.pixelDensity * 3.5 : anchors.margins
|
||||
implicitHeight: model.count * sidebarSplitter.rowHeight
|
||||
delegate: Item {
|
||||
id: shortcutItem
|
||||
width: sidebarSplitter.width
|
||||
height: shortcutLabel.implicitHeight * 1.5
|
||||
Text {
|
||||
id: shortcutLabel
|
||||
text: __shortcuts[index].name
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 4
|
||||
}
|
||||
elide: Text.ElideLeft
|
||||
renderType: ControlsPrivate.Settings.isMobile ? Text.QtRendering : Text.NativeRendering
|
||||
Component.onCompleted: {
|
||||
sidebarSplitter.rowHeight = parent.height
|
||||
if (implicitWidth * 1.2 > sidebarSplitter.maxShortcutWidth)
|
||||
sidebarSplitter.maxShortcutWidth = implicitWidth * 1.2
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.folder = __shortcuts[index].url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
Layout.minimumHeight: sidebarSplitter.rowHeight * 2.5
|
||||
ListView {
|
||||
id: favorites
|
||||
model: root.favoriteFolders
|
||||
anchors.topMargin: ControlsPrivate.Settings.hasTouchScreen ? Screen.pixelDensity * 3.5 : anchors.margins
|
||||
delegate: Item {
|
||||
width: favorites.width
|
||||
height: folderLabel.implicitHeight * 1.5
|
||||
Text {
|
||||
id: folderLabel
|
||||
text: root.favoriteFolders[index]
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
margins: 4
|
||||
}
|
||||
elide: Text.ElideLeft
|
||||
renderType: ControlsPrivate.Settings.isMobile ? Text.QtRendering : Text.NativeRendering
|
||||
}
|
||||
Menu {
|
||||
id: favoriteCtxMenu
|
||||
title: root.favoriteFolders[index]
|
||||
MenuItem {
|
||||
text: qsTr("Remove favorite")
|
||||
onTriggered: {
|
||||
root.favoriteFolders.splice(index, 1)
|
||||
favorites.model = root.favoriteFolders
|
||||
}
|
||||
}
|
||||
}
|
||||
MouseArea {
|
||||
id: favoriteArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
if (mouse.button == Qt.LeftButton)
|
||||
root.folder = root.favoriteFolders[index]
|
||||
else if (mouse.button == Qt.RightButton)
|
||||
favoriteCtxMenu.popup()
|
||||
}
|
||||
onExited: ControlsPrivate.Tooltip.hideText()
|
||||
onCanceled: ControlsPrivate.Tooltip.hideText()
|
||||
Timer {
|
||||
interval: 1000
|
||||
running: favoriteArea.containsMouse && !favoriteArea.pressed && folderLabel.truncated
|
||||
onTriggered: ControlsPrivate.Tooltip.showText(favoriteArea,
|
||||
Qt.point(favoriteArea.mouseX, favoriteArea.mouseY), urlToPath(root.favoriteFolders[index]))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: favoritesButtons
|
||||
height: plusButton.height + 1
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 6
|
||||
layoutDirection: Qt.RightToLeft
|
||||
Button {
|
||||
id: plusButton
|
||||
style: IconButtonStyle { }
|
||||
text: "\ue83e"
|
||||
tooltip: qsTr("Add the current directory as a favorite")
|
||||
width: height
|
||||
onClicked: {
|
||||
root.favoriteFolders.push(root.folder)
|
||||
favorites.model = root.favoriteFolders
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableView {
|
||||
id: view
|
||||
sortIndicatorVisible: true
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: 40
|
||||
property bool needsWidthAdjustment: true
|
||||
selectionMode: root.selectMultiple ?
|
||||
(ControlsPrivate.Settings.hasTouchScreen ? SelectionMode.MultiSelection : SelectionMode.ExtendedSelection) :
|
||||
SelectionMode.SingleSelection
|
||||
onRowCountChanged: if (needsWidthAdjustment && rowCount > 0) {
|
||||
resizeColumnsToContents()
|
||||
needsWidthAdjustment = false
|
||||
}
|
||||
model: null
|
||||
|
||||
onActivated: if (view.focus) {
|
||||
if (view.selection.count > 0 && view.model.isFolder(row)) {
|
||||
dirDown(view.model.get(row, "filePath"))
|
||||
} else {
|
||||
root.acceptSelection()
|
||||
}
|
||||
}
|
||||
onClicked: currentPathField.text = view.model.get(row, "filePath")
|
||||
|
||||
|
||||
TableViewColumn {
|
||||
id: fileNameColumn
|
||||
role: "fileName"
|
||||
title: qsTr("Filename")
|
||||
delegate: Item {
|
||||
implicitWidth: pathText.implicitWidth + pathText.anchors.leftMargin + pathText.anchors.rightMargin
|
||||
IconGlyph {
|
||||
id: fileIcon
|
||||
x: 4
|
||||
height: parent.height - 2
|
||||
unicode: view.model.isFolder(styleData.row) ? "\ue804" : "\ue802"
|
||||
}
|
||||
Text {
|
||||
id: pathText
|
||||
text: styleData.value
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: fileIcon.width + 6
|
||||
rightMargin: 4
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
color: styleData.textColor
|
||||
elide: Text.ElideRight
|
||||
renderType: ControlsPrivate.Settings.isMobile ? Text.QtRendering : Text.NativeRendering
|
||||
}
|
||||
}
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "fileSuffix"
|
||||
title: qsTr("Type", "file type (extension)")
|
||||
// TODO should not need to create a whole new component just to customize the text value
|
||||
// something like textFormat: function(text) { return view.model.get(styleData.row, "fileIsDir") ? "folder" : text }
|
||||
delegate: Item {
|
||||
implicitWidth: sizeText.implicitWidth + sizeText.anchors.leftMargin + sizeText.anchors.rightMargin
|
||||
Text {
|
||||
id: sizeText
|
||||
text: view.model.get(styleData.row, "fileIsDir") ? "folder" : styleData.value
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: 4
|
||||
rightMargin: 4
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
color: styleData.textColor
|
||||
elide: Text.ElideRight
|
||||
renderType: ControlsPrivate.Settings.isMobile ? Text.QtRendering : Text.NativeRendering
|
||||
}
|
||||
}
|
||||
}
|
||||
TableViewColumn {
|
||||
role: "fileSize"
|
||||
title: qsTr("Size", "file size")
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
TableViewColumn { id: modifiedColumn; role: "fileModified" ; title: qsTr("Modified", "last-modified time") }
|
||||
TableViewColumn { id: accessedColumn; role: "fileAccessed" ; title: qsTr("Accessed", "last-accessed time") }
|
||||
}
|
||||
}
|
||||
|
||||
ToolBar {
|
||||
id: titleBar
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
ToolButton {
|
||||
action: dirUpAction
|
||||
style: IconButtonStyle { }
|
||||
Layout.maximumWidth: height * 1.5
|
||||
}
|
||||
TextField {
|
||||
id: currentPathField
|
||||
Layout.fillWidth: true
|
||||
function doAccept() {
|
||||
root.clearSelection()
|
||||
if (root.addSelection(root.pathToUrl(text)))
|
||||
root.accept()
|
||||
else
|
||||
root.folder = root.pathFolder(text)
|
||||
}
|
||||
onAccepted: doAccept()
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: bottomBar
|
||||
width: parent.width
|
||||
height: buttonRow.height + buttonRow.spacing * 2
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
Row {
|
||||
id: buttonRow
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: spacing
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 4
|
||||
Button {
|
||||
id: toggleSidebarButton
|
||||
checkable: true
|
||||
style: IconButtonStyle { }
|
||||
text: "\u25E7"
|
||||
height: cancelButton.height
|
||||
width: height
|
||||
checked: root.sidebarVisible
|
||||
onClicked: {
|
||||
root.sidebarVisible = !root.sidebarVisible
|
||||
}
|
||||
}
|
||||
ComboBox {
|
||||
id: filterField
|
||||
model: root.nameFilters
|
||||
visible: !selectFolder
|
||||
width: bottomBar.width - toggleSidebarButton.width - cancelButton.width - okButton.width - parent.spacing * 6
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onCurrentTextChanged: {
|
||||
root.selectNameFilter(currentText)
|
||||
if (view.model)
|
||||
view.model.nameFilters = root.selectedNameFilterExtensions
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: cancelButton
|
||||
text: qsTr("Cancel")
|
||||
onClicked: root.reject()
|
||||
}
|
||||
Button {
|
||||
id: okButton
|
||||
text: root.selectFolder ? qsTr("Choose") : (selectExisting ? qsTr("Open") : qsTr("Save"))
|
||||
onClicked: {
|
||||
if (view.model.isFolder(view.currentRow) && !selectFolder)
|
||||
dirDown(view.model.get(view.currentRow, "filePath"))
|
||||
else if (!(root.selectExisting))
|
||||
currentPathField.doAccept()
|
||||
else
|
||||
root.acceptSelection()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user