mirror of
https://github.com/overte-org/overte.git
synced 2025-04-26 07:16:25 +02:00
Looking through the log revealed the following warning: ".../qml/dialogs/FileDialog.qml:489: Error: Cannot assign to non-existent property 'sortOrder'" There was some refactoring to address some HMD functionality in51b44d90
which resulted in an update to fileTableView's model. This appears to be the point at which sorting stopped working. This updates the fileTableView's sorting methods to use fileTableModel as opposed to fileTableView's model(filesModel). This appears safe given fileTableModel internally wraps around filesModel and is responsible for updating its value. I'm relatively new to QML/Qt; any comments or suggestions are welcome. Tagging @vladest since they may want to be aware given51b44d90
. Case Link: https://highfidelity.fogbugz.com/f/cases/6107 Reviewed-by: Leander Hasty <leander@1stplayable.com> Changes Committed: modified: interface/resources/qml/dialogs/FileDialog.qml
799 lines
28 KiB
QML
799 lines
28 KiB
QML
//
|
|
// FileDialog.qml
|
|
//
|
|
// Created by Bradley Austin Davis on 14 Jan 2016
|
|
// Copyright 2015 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
import QtQuick 2.5
|
|
import QtQuick.Controls 1.4
|
|
import Qt.labs.folderlistmodel 2.1
|
|
import Qt.labs.settings 1.0
|
|
import QtQuick.Controls.Styles 1.4
|
|
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
|
|
|
import ".."
|
|
import "../controls-uit"
|
|
import "../styles-uit"
|
|
import "../windows"
|
|
|
|
import "fileDialog"
|
|
|
|
//FIXME implement shortcuts for favorite location
|
|
ModalWindow {
|
|
id: root
|
|
resizable: true
|
|
implicitWidth: 480
|
|
implicitHeight: 360 + (fileDialogItem.keyboardEnabled && fileDialogItem.keyboardRaised ? keyboard.raisedHeight + hifi.dimensions.contentSpacing.y : 0)
|
|
|
|
minSize: Qt.vector2d(360, 240)
|
|
draggable: true
|
|
|
|
HifiConstants { id: hifi }
|
|
|
|
property var filesModel: ListModel { }
|
|
|
|
Settings {
|
|
category: "FileDialog"
|
|
property alias width: root.width
|
|
property alias height: root.height
|
|
property alias x: root.x
|
|
property alias y: root.y
|
|
}
|
|
|
|
|
|
// Set from OffscreenUi::getOpenFile()
|
|
property alias caption: root.title;
|
|
// Set from OffscreenUi::getOpenFile()
|
|
property alias dir: fileTableModel.folder;
|
|
// Set from OffscreenUi::getOpenFile()
|
|
property alias filter: selectionType.filtersString;
|
|
// Set from OffscreenUi::getOpenFile()
|
|
property int options; // <-- FIXME unused
|
|
|
|
property string iconText: root.title !== "" ? hifi.glyphs.scriptUpload : ""
|
|
property int iconSize: 40
|
|
|
|
property bool selectDirectory: false;
|
|
property bool showHidden: false;
|
|
// FIXME implement
|
|
property bool multiSelect: false;
|
|
property bool saveDialog: false;
|
|
property var helper: fileDialogHelper
|
|
property alias model: fileTableView.model
|
|
property var drives: helper.drives()
|
|
|
|
property int titleWidth: 0
|
|
|
|
signal selectedFile(var file);
|
|
signal canceled();
|
|
|
|
Component.onCompleted: {
|
|
console.log("Helper " + helper + " drives " + drives);
|
|
|
|
fileDialogItem.keyboardEnabled = HMD.active;
|
|
|
|
// HACK: The following lines force the model to initialize properly such that the go-up button
|
|
// works properly from the initial screen.
|
|
var initialFolder = folderListModel.folder;
|
|
fileTableModel.folder = helper.pathToUrl(drives[0]);
|
|
fileTableModel.folder = initialFolder;
|
|
|
|
iconText = root.title !== "" ? hifi.glyphs.scriptUpload : "";
|
|
|
|
// Clear selection when click on external frame.
|
|
frameClicked.connect(function() { d.clearSelection(); });
|
|
|
|
if (selectDirectory) {
|
|
currentSelection.text = d.capitalizeDrive(helper.urlToPath(initialFolder));
|
|
d.currentSelectionIsFolder = true;
|
|
d.currentSelectionUrl = initialFolder;
|
|
}
|
|
|
|
helper.contentsChanged.connect(function() {
|
|
if (folderListModel) {
|
|
// Make folderListModel refresh.
|
|
var save = folderListModel.folder;
|
|
folderListModel.folder = "";
|
|
folderListModel.folder = save;
|
|
}
|
|
});
|
|
|
|
fileTableView.forceActiveFocus();
|
|
}
|
|
|
|
Item {
|
|
id: fileDialogItem
|
|
clip: true
|
|
width: pane.width
|
|
height: pane.height
|
|
anchors.margins: 0
|
|
|
|
property bool keyboardEnabled: false
|
|
property bool keyboardRaised: false
|
|
property bool punctuationMode: false
|
|
|
|
MouseArea {
|
|
// Clear selection when click on internal unused area.
|
|
anchors.fill: parent
|
|
drag.target: root
|
|
onClicked: {
|
|
d.clearSelection();
|
|
frame.forceActiveFocus(); // Defocus text field so that the keyboard gets hidden.
|
|
}
|
|
}
|
|
|
|
Row {
|
|
id: navControls
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: hifi.dimensions.contentMargin.y
|
|
left: parent.left
|
|
}
|
|
spacing: hifi.dimensions.contentSpacing.x
|
|
|
|
GlyphButton {
|
|
id: upButton
|
|
glyph: hifi.glyphs.levelUp
|
|
width: height
|
|
size: 30
|
|
enabled: fileTableModel.parentFolder && fileTableModel.parentFolder !== ""
|
|
onClicked: d.navigateUp();
|
|
}
|
|
|
|
GlyphButton {
|
|
id: homeButton
|
|
property var destination: helper.home();
|
|
glyph: hifi.glyphs.home
|
|
size: 28
|
|
width: height
|
|
enabled: d.homeDestination ? true : false
|
|
onClicked: d.navigateHome();
|
|
}
|
|
}
|
|
|
|
ComboBox {
|
|
id: pathSelector
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: hifi.dimensions.contentMargin.y
|
|
left: navControls.right
|
|
leftMargin: hifi.dimensions.contentSpacing.x
|
|
right: parent.right
|
|
}
|
|
|
|
property var lastValidFolder: helper.urlToPath(fileTableModel.folder)
|
|
|
|
function calculatePathChoices(folder) {
|
|
var folders = folder.split("/"),
|
|
choices = [],
|
|
i, length;
|
|
|
|
if (folders[folders.length - 1] === "") {
|
|
folders.pop();
|
|
}
|
|
|
|
choices.push(folders[0]);
|
|
|
|
for (i = 1, length = folders.length; i < length; i++) {
|
|
choices.push(choices[i - 1] + "/" + folders[i]);
|
|
}
|
|
|
|
if (folders[0] === "") {
|
|
// Special handling for OSX root dir.
|
|
choices[0] = "/";
|
|
}
|
|
|
|
choices.reverse();
|
|
|
|
if (drives && drives.length > 1) {
|
|
choices.push("This PC");
|
|
}
|
|
|
|
if (choices.length > 0) {
|
|
pathSelector.model = choices;
|
|
}
|
|
}
|
|
|
|
onLastValidFolderChanged: {
|
|
var folder = d.capitalizeDrive(lastValidFolder);
|
|
calculatePathChoices(folder);
|
|
}
|
|
|
|
onCurrentTextChanged: {
|
|
var folder = currentText;
|
|
|
|
if (/^[a-zA-z]:$/.test(folder)) {
|
|
folder = "file:///" + folder + "/";
|
|
} else if (folder === "This PC") {
|
|
folder = "file:///";
|
|
} else {
|
|
folder = helper.pathToUrl(folder);
|
|
}
|
|
|
|
if (helper.urlToPath(folder).toLowerCase() !== helper.urlToPath(fileTableModel.folder).toLowerCase()) {
|
|
if (root.selectDirectory) {
|
|
currentSelection.text = currentText !== "This PC" ? currentText : "";
|
|
d.currentSelectionUrl = helper.pathToUrl(currentText);
|
|
}
|
|
fileTableModel.folder = folder;
|
|
fileTableView.forceActiveFocus();
|
|
}
|
|
}
|
|
}
|
|
|
|
QtObject {
|
|
id: d
|
|
property var currentSelectionUrl;
|
|
readonly property string currentSelectionPath: helper.urlToPath(currentSelectionUrl);
|
|
property bool currentSelectionIsFolder;
|
|
property var backStack: []
|
|
property var tableViewConnection: Connections { target: fileTableView; onCurrentRowChanged: d.update(); }
|
|
property var modelConnection: Connections { target: fileTableModel; onFolderChanged: d.update(); }
|
|
property var homeDestination: helper.home();
|
|
|
|
function capitalizeDrive(path) {
|
|
// Consistently capitalize drive letter for Windows.
|
|
if (/[a-zA-Z]:/.test(path)) {
|
|
return path.charAt(0).toUpperCase() + path.slice(1);
|
|
}
|
|
return path;
|
|
}
|
|
|
|
function update() {
|
|
var row = fileTableView.currentRow;
|
|
|
|
if (row === -1) {
|
|
if (!root.selectDirectory) {
|
|
currentSelection.text = "";
|
|
currentSelectionIsFolder = false;
|
|
}
|
|
return;
|
|
}
|
|
|
|
currentSelectionUrl = helper.pathToUrl(fileTableView.model.get(row).filePath);
|
|
currentSelectionIsFolder = fileTableView.model !== filesModel ?
|
|
fileTableView.model.isFolder(row) :
|
|
fileTableModel.isFolder(row);
|
|
if (root.selectDirectory || !currentSelectionIsFolder) {
|
|
currentSelection.text = capitalizeDrive(helper.urlToPath(currentSelectionUrl));
|
|
} else {
|
|
currentSelection.text = "";
|
|
}
|
|
}
|
|
|
|
function navigateUp() {
|
|
if (fileTableModel.parentFolder && fileTableModel.parentFolder !== "") {
|
|
fileTableModel.folder = fileTableModel.parentFolder;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
function navigateHome() {
|
|
fileTableModel.folder = homeDestination;
|
|
return true;
|
|
}
|
|
|
|
function clearSelection() {
|
|
fileTableView.selection.clear();
|
|
fileTableView.currentRow = -1;
|
|
update();
|
|
}
|
|
}
|
|
|
|
FolderListModel {
|
|
id: folderListModel
|
|
nameFilters: selectionType.currentFilter
|
|
showDirsFirst: true
|
|
showDotAndDotDot: false
|
|
showFiles: !root.selectDirectory
|
|
Component.onCompleted: {
|
|
showFiles = !root.selectDirectory
|
|
}
|
|
|
|
onFolderChanged: {
|
|
fileTableModel.update(); // Update once the data from the folder change is available.
|
|
}
|
|
|
|
function getItem(index, field) {
|
|
return get(index, field);
|
|
}
|
|
}
|
|
|
|
ListModel {
|
|
// Emulates FolderListModel but contains drive data.
|
|
id: driveListModel
|
|
|
|
property int count: 1
|
|
|
|
Component.onCompleted: initialize();
|
|
|
|
function initialize() {
|
|
var drive,
|
|
i;
|
|
|
|
count = drives.length;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
drive = drives[i].slice(0, -1); // Remove trailing "/".
|
|
append({
|
|
fileName: drive,
|
|
fileModified: new Date(0),
|
|
fileSize: 0,
|
|
filePath: drive + "/",
|
|
fileIsDir: true,
|
|
fileNameSort: drive.toLowerCase()
|
|
});
|
|
}
|
|
}
|
|
|
|
function getItem(index, field) {
|
|
return get(index)[field];
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: filesModelBuilder
|
|
ListModel { }
|
|
}
|
|
|
|
QtObject {
|
|
id: fileTableModel
|
|
|
|
// FolderListModel has a couple of problems:
|
|
// 1) Files and directories sort case-sensitively: https://bugreports.qt.io/browse/QTBUG-48757
|
|
// 2) Cannot browse up to the "computer" level to view Windows drives: https://bugreports.qt.io/browse/QTBUG-42901
|
|
//
|
|
// To solve these problems an intermediary ListModel is used that implements proper sorting and can be populated with
|
|
// drive information when viewing at the computer level.
|
|
|
|
property var folder
|
|
property int sortOrder: Qt.AscendingOrder
|
|
property int sortColumn: 0
|
|
property var model: folderListModel
|
|
property string parentFolder: calculateParentFolder();
|
|
|
|
readonly property string rootFolder: "file:///"
|
|
|
|
function calculateParentFolder() {
|
|
if (model === folderListModel) {
|
|
if (folderListModel.parentFolder.toString() === "" && driveListModel.count > 1) {
|
|
return rootFolder;
|
|
} else {
|
|
return folderListModel.parentFolder;
|
|
}
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
onFolderChanged: {
|
|
if (folder === rootFolder) {
|
|
model = driveListModel;
|
|
helper.monitorDirectory("");
|
|
update();
|
|
} else {
|
|
var needsUpdate = model === driveListModel && folder === folderListModel.folder;
|
|
|
|
model = folderListModel;
|
|
folderListModel.folder = folder;
|
|
helper.monitorDirectory(helper.urlToPath(folder));
|
|
|
|
if (needsUpdate) {
|
|
update();
|
|
}
|
|
}
|
|
}
|
|
|
|
function isFolder(row) {
|
|
if (row === -1) {
|
|
return false;
|
|
}
|
|
return filesModel.get(row).fileIsDir;
|
|
}
|
|
|
|
function get(row) {
|
|
return filesModel.get(row)
|
|
}
|
|
|
|
function update() {
|
|
var dataFields = ["fileName", "fileModified", "fileSize"],
|
|
sortFields = ["fileNameSort", "fileModified", "fileSize"],
|
|
dataField = dataFields[sortColumn],
|
|
sortField = sortFields[sortColumn],
|
|
sortValue,
|
|
fileName,
|
|
fileIsDir,
|
|
comparisonFunction,
|
|
lower,
|
|
middle,
|
|
upper,
|
|
rows = 0,
|
|
i;
|
|
|
|
var newFilesModel = filesModelBuilder.createObject(root);
|
|
|
|
comparisonFunction = sortOrder === Qt.AscendingOrder
|
|
? function(a, b) { return a < b; }
|
|
: function(a, b) { return a > b; }
|
|
|
|
for (i = 0; i < model.count; i++) {
|
|
fileName = model.getItem(i, "fileName");
|
|
fileIsDir = model.getItem(i, "fileIsDir");
|
|
|
|
sortValue = model.getItem(i, dataField);
|
|
if (dataField === "fileName") {
|
|
// Directories first by prefixing a "*".
|
|
// Case-insensitive.
|
|
sortValue = (fileIsDir ? "*" : "") + sortValue.toLowerCase();
|
|
}
|
|
|
|
lower = 0;
|
|
upper = rows;
|
|
while (lower < upper) {
|
|
middle = Math.floor((lower + upper) / 2);
|
|
var lessThan;
|
|
if (comparisonFunction(sortValue, newFilesModel.get(middle)[sortField])) {
|
|
lessThan = true;
|
|
upper = middle;
|
|
} else {
|
|
lessThan = false;
|
|
lower = middle + 1;
|
|
}
|
|
}
|
|
|
|
newFilesModel.insert(lower, {
|
|
fileName: fileName,
|
|
fileModified: (fileIsDir ? new Date(0) : model.getItem(i, "fileModified")),
|
|
fileSize: model.getItem(i, "fileSize"),
|
|
filePath: model.getItem(i, "filePath"),
|
|
fileIsDir: fileIsDir,
|
|
fileNameSort: (fileIsDir ? "*" : "") + fileName.toLowerCase()
|
|
});
|
|
|
|
rows++;
|
|
}
|
|
filesModel = newFilesModel;
|
|
|
|
d.clearSelection();
|
|
}
|
|
}
|
|
|
|
Table {
|
|
id: fileTableView
|
|
colorScheme: hifi.colorSchemes.light
|
|
anchors {
|
|
top: navControls.bottom
|
|
topMargin: hifi.dimensions.contentSpacing.y
|
|
left: parent.left
|
|
right: parent.right
|
|
bottom: currentSelection.top
|
|
bottomMargin: hifi.dimensions.contentSpacing.y + currentSelection.controlHeight - currentSelection.height
|
|
}
|
|
headerVisible: !selectDirectory
|
|
onDoubleClicked: navigateToRow(row);
|
|
focus: true
|
|
Keys.onReturnPressed: navigateToCurrentRow();
|
|
Keys.onEnterPressed: navigateToCurrentRow();
|
|
|
|
sortIndicatorColumn: 0
|
|
sortIndicatorOrder: Qt.AscendingOrder
|
|
sortIndicatorVisible: true
|
|
|
|
model: filesModel
|
|
|
|
function updateSort() {
|
|
fileTableModel.sortOrder = sortIndicatorOrder;
|
|
fileTableModel.sortColumn = sortIndicatorColumn;
|
|
fileTableModel.update();
|
|
}
|
|
|
|
onSortIndicatorColumnChanged: { updateSort(); }
|
|
|
|
onSortIndicatorOrderChanged: { updateSort(); }
|
|
|
|
itemDelegate: Item {
|
|
clip: true
|
|
|
|
FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; }
|
|
FontLoader { id: firaSansRegular; source: "../../fonts/FiraSans-Regular.ttf"; }
|
|
|
|
FiraSansSemiBold {
|
|
text: getText();
|
|
elide: styleData.elideMode
|
|
anchors {
|
|
left: parent.left
|
|
leftMargin: hifi.dimensions.tablePadding
|
|
right: parent.right
|
|
rightMargin: hifi.dimensions.tablePadding
|
|
verticalCenter: parent.verticalCenter
|
|
}
|
|
size: hifi.fontSizes.tableText
|
|
color: hifi.colors.baseGrayHighlight
|
|
font.family: (styleData.row !== -1 && fileTableView.model.get(styleData.row).fileIsDir)
|
|
? firaSansSemiBold.name : firaSansRegular.name
|
|
|
|
function getText() {
|
|
if (styleData.row === -1) {
|
|
return styleData.value;
|
|
}
|
|
|
|
switch (styleData.column) {
|
|
case 1: return fileTableView.model.get(styleData.row).fileIsDir ? "" : styleData.value;
|
|
case 2: return fileTableView.model.get(styleData.row).fileIsDir ? "" : formatSize(styleData.value);
|
|
default: return styleData.value;
|
|
}
|
|
}
|
|
function formatSize(size) {
|
|
var suffixes = [ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" ];
|
|
var suffixIndex = 0
|
|
while ((size / 1024.0) > 1.1) {
|
|
size /= 1024.0;
|
|
++suffixIndex;
|
|
}
|
|
|
|
size = Math.round(size*1000)/1000;
|
|
size = size.toLocaleString()
|
|
|
|
return size + " " + suffixes[suffixIndex];
|
|
}
|
|
}
|
|
}
|
|
|
|
TableViewColumn {
|
|
id: fileNameColumn
|
|
role: "fileName"
|
|
title: "Name"
|
|
width: (selectDirectory ? 1.0 : 0.5) * fileTableView.width
|
|
movable: false
|
|
resizable: true
|
|
}
|
|
TableViewColumn {
|
|
id: fileMofifiedColumn
|
|
role: "fileModified"
|
|
title: "Date"
|
|
width: 0.3 * fileTableView.width
|
|
movable: false
|
|
resizable: true
|
|
visible: !selectDirectory
|
|
}
|
|
TableViewColumn {
|
|
role: "fileSize"
|
|
title: "Size"
|
|
width: fileTableView.width - fileNameColumn.width - fileMofifiedColumn.width
|
|
movable: false
|
|
resizable: true
|
|
visible: !selectDirectory
|
|
}
|
|
|
|
function navigateToRow(row) {
|
|
currentRow = row;
|
|
navigateToCurrentRow();
|
|
}
|
|
|
|
function navigateToCurrentRow() {
|
|
var currentModel = fileTableView.model !== filesModel ? fileTableView.model : fileTableModel
|
|
var row = fileTableView.currentRow
|
|
var isFolder = currentModel.isFolder(row);
|
|
var file = currentModel.get(row).filePath;
|
|
if (isFolder) {
|
|
currentModel.folder = helper.pathToUrl(file);
|
|
} else {
|
|
okAction.trigger();
|
|
}
|
|
}
|
|
|
|
property string prefix: ""
|
|
|
|
function addToPrefix(event) {
|
|
if (!event.text || event.text === "") {
|
|
return false;
|
|
}
|
|
var newPrefix = prefix + event.text.toLowerCase();
|
|
var matchedIndex = -1;
|
|
for (var i = 0; i < model.count; ++i) {
|
|
var name = model !== filesModel ? model.get(i).fileName.toLowerCase() :
|
|
filesModel.get(i).fileName.toLowerCase();
|
|
if (0 === name.indexOf(newPrefix)) {
|
|
matchedIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (matchedIndex !== -1) {
|
|
fileTableView.selection.clear();
|
|
fileTableView.selection.select(matchedIndex);
|
|
fileTableView.currentRow = matchedIndex;
|
|
fileTableView.prefix = newPrefix;
|
|
}
|
|
prefixClearTimer.restart();
|
|
return true;
|
|
}
|
|
|
|
Timer {
|
|
id: prefixClearTimer
|
|
interval: 1000
|
|
repeat: false
|
|
running: false
|
|
onTriggered: fileTableView.prefix = "";
|
|
}
|
|
|
|
Keys.onPressed: {
|
|
switch (event.key) {
|
|
case Qt.Key_Backspace:
|
|
case Qt.Key_Tab:
|
|
case Qt.Key_Backtab:
|
|
event.accepted = false;
|
|
break;
|
|
|
|
default:
|
|
if (addToPrefix(event)) {
|
|
event.accepted = true
|
|
} else {
|
|
event.accepted = false;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
TextField {
|
|
id: currentSelection
|
|
label: selectDirectory ? "Directory:" : "File name:"
|
|
anchors {
|
|
left: parent.left
|
|
right: selectionType.visible ? selectionType.left: parent.right
|
|
rightMargin: selectionType.visible ? hifi.dimensions.contentSpacing.x : 0
|
|
bottom: keyboard.top
|
|
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
}
|
|
readOnly: !root.saveDialog
|
|
activeFocusOnTab: !readOnly
|
|
onActiveFocusChanged: if (activeFocus) { selectAll(); }
|
|
onAccepted: okAction.trigger();
|
|
}
|
|
|
|
FileTypeSelection {
|
|
id: selectionType
|
|
anchors {
|
|
top: currentSelection.top
|
|
left: buttonRow.left
|
|
right: parent.right
|
|
}
|
|
visible: !selectDirectory && filtersCount > 1
|
|
KeyNavigation.left: fileTableView
|
|
KeyNavigation.right: openButton
|
|
}
|
|
|
|
Keyboard {
|
|
id: keyboard
|
|
raised: parent.keyboardEnabled && parent.keyboardRaised
|
|
numeric: parent.punctuationMode
|
|
anchors {
|
|
left: parent.left
|
|
right: parent.right
|
|
bottom: buttonRow.top
|
|
bottomMargin: visible ? hifi.dimensions.contentSpacing.y : 0
|
|
}
|
|
}
|
|
|
|
Row {
|
|
id: buttonRow
|
|
anchors {
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
}
|
|
spacing: hifi.dimensions.contentSpacing.y
|
|
|
|
Button {
|
|
id: openButton
|
|
color: hifi.buttons.blue
|
|
action: okAction
|
|
Keys.onReturnPressed: okAction.trigger()
|
|
KeyNavigation.up: selectionType
|
|
KeyNavigation.left: selectionType
|
|
KeyNavigation.right: cancelButton
|
|
}
|
|
|
|
Button {
|
|
id: cancelButton
|
|
action: cancelAction
|
|
KeyNavigation.up: selectionType
|
|
KeyNavigation.left: openButton
|
|
KeyNavigation.right: fileTableView.contentItem
|
|
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
|
}
|
|
}
|
|
|
|
Action {
|
|
id: okAction
|
|
text: currentSelection.text ? (root.selectDirectory && fileTableView.currentRow === -1 ? "Choose" : (root.saveDialog ? "Save" : "Open")) : "Open"
|
|
enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
|
|
onTriggered: {
|
|
if (!root.selectDirectory && !d.currentSelectionIsFolder
|
|
|| root.selectDirectory && fileTableView.currentRow === -1) {
|
|
okActionTimer.start();
|
|
} else {
|
|
fileTableView.navigateToCurrentRow();
|
|
}
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: okActionTimer
|
|
interval: 50
|
|
running: false
|
|
repeat: false
|
|
onTriggered: {
|
|
if (!root.saveDialog) {
|
|
selectedFile(d.currentSelectionUrl);
|
|
root.destroy()
|
|
return;
|
|
}
|
|
|
|
// Handle the ambiguity between different cases
|
|
// * typed name (with or without extension)
|
|
// * full path vs relative vs filename only
|
|
var selection = helper.saveHelper(currentSelection.text, root.dir, selectionType.currentFilter);
|
|
|
|
if (!selection) {
|
|
desktop.messageBox({ icon: OriginalDialogs.StandardIcon.Warning, text: "Unable to parse selection" })
|
|
return;
|
|
}
|
|
|
|
if (helper.urlIsDir(selection)) {
|
|
root.dir = selection;
|
|
currentSelection.text = "";
|
|
return;
|
|
}
|
|
|
|
// Check if the file is a valid target
|
|
if (!helper.urlIsWritable(selection)) {
|
|
desktop.messageBox({
|
|
icon: OriginalDialogs.StandardIcon.Warning,
|
|
text: "Unable to write to location " + selection
|
|
})
|
|
return;
|
|
}
|
|
|
|
if (helper.urlExists(selection)) {
|
|
var messageBox = desktop.messageBox({
|
|
icon: OriginalDialogs.StandardIcon.Question,
|
|
buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No,
|
|
text: "Do you wish to overwrite " + selection + "?",
|
|
});
|
|
var result = messageBox.exec();
|
|
if (OriginalDialogs.StandardButton.Yes !== result) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
console.log("Selecting " + selection)
|
|
selectedFile(selection);
|
|
root.destroy();
|
|
}
|
|
}
|
|
|
|
Action {
|
|
id: cancelAction
|
|
text: "Cancel"
|
|
onTriggered: { canceled(); root.shown = false; }
|
|
}
|
|
}
|
|
|
|
Keys.onPressed: {
|
|
switch (event.key) {
|
|
case Qt.Key_Backspace:
|
|
event.accepted = d.navigateUp();
|
|
break;
|
|
|
|
case Qt.Key_Home:
|
|
event.accepted = d.navigateHome();
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|