mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-06 14:03:27 +02:00
536 lines
17 KiB
QML
536 lines
17 KiB
QML
//
|
|
// AssetDialogContent.qml
|
|
//
|
|
// Created by David Rowe on 19 Apr 2017
|
|
// Copyright 2017 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 "../../controls-uit"
|
|
import "../../styles-uit"
|
|
|
|
import "../fileDialog"
|
|
|
|
Item {
|
|
// Set from OffscreenUi::assetDialog()
|
|
property alias dir: assetTableModel.folder
|
|
property alias filter: selectionType.filtersString // FIXME: Currently only supports simple filters, "*.xxx".
|
|
property int options // Not used.
|
|
|
|
property bool selectDirectory: false
|
|
|
|
// Not implemented.
|
|
//property bool saveDialog: false;
|
|
//property bool multiSelect: false;
|
|
|
|
property bool singleClickNavigate: false
|
|
|
|
HifiConstants { id: hifi }
|
|
|
|
Component.onCompleted: {
|
|
homeButton.destination = dir;
|
|
|
|
if (selectDirectory) {
|
|
d.currentSelectionIsFolder = true;
|
|
d.currentSelectionPath = assetTableModel.folder;
|
|
}
|
|
|
|
assetTableView.forceActiveFocus();
|
|
}
|
|
|
|
Item {
|
|
id: assetDialogItem
|
|
anchors.fill: parent
|
|
clip: true
|
|
|
|
MouseArea {
|
|
// Clear selection when click on internal unused area.
|
|
anchors.fill: parent
|
|
drag.target: root
|
|
onClicked: {
|
|
d.clearSelection();
|
|
frame.forceActiveFocus();
|
|
assetTableView.forceActiveFocus();
|
|
}
|
|
}
|
|
|
|
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: assetTableModel.parentFolder !== ""
|
|
onClicked: d.navigateUp();
|
|
}
|
|
|
|
GlyphButton {
|
|
id: homeButton
|
|
property string destination: ""
|
|
glyph: hifi.glyphs.home
|
|
size: 28
|
|
width: height
|
|
enabled: destination !== ""
|
|
//onClicked: d.navigateHome();
|
|
onClicked: assetTableModel.folder = destination;
|
|
}
|
|
}
|
|
|
|
ComboBox {
|
|
id: pathSelector
|
|
anchors {
|
|
top: parent.top
|
|
topMargin: hifi.dimensions.contentMargin.y
|
|
left: navControls.right
|
|
leftMargin: hifi.dimensions.contentSpacing.x
|
|
right: parent.right
|
|
}
|
|
z: 10
|
|
|
|
property string lastValidFolder: assetTableModel.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] === "") {
|
|
choices[0] = "/";
|
|
}
|
|
|
|
choices.reverse();
|
|
|
|
if (choices.length > 0) {
|
|
pathSelector.model = choices;
|
|
}
|
|
}
|
|
|
|
onLastValidFolderChanged: {
|
|
var folder = lastValidFolder;
|
|
calculatePathChoices(folder);
|
|
}
|
|
|
|
onCurrentTextChanged: {
|
|
var folder = currentText;
|
|
|
|
if (folder !== "/") {
|
|
folder += "/";
|
|
}
|
|
|
|
if (folder !== assetTableModel.folder) {
|
|
if (root.selectDirectory) {
|
|
currentSelection.text = currentText;
|
|
d.currentSelectionPath = currentText;
|
|
}
|
|
assetTableModel.folder = folder;
|
|
assetTableView.forceActiveFocus();
|
|
}
|
|
}
|
|
}
|
|
|
|
QtObject {
|
|
id: d
|
|
|
|
property string currentSelectionPath
|
|
property bool currentSelectionIsFolder
|
|
property var tableViewConnection: Connections { target: assetTableView; onCurrentRowChanged: d.update(); }
|
|
|
|
function update() {
|
|
var row = assetTableView.currentRow;
|
|
|
|
if (row === -1) {
|
|
if (!root.selectDirectory) {
|
|
currentSelection.text = "";
|
|
currentSelectionIsFolder = false;
|
|
}
|
|
return;
|
|
}
|
|
|
|
var rowInfo = assetTableModel.get(row);
|
|
currentSelectionPath = rowInfo.filePath;
|
|
currentSelectionIsFolder = rowInfo.fileIsDir;
|
|
if (root.selectDirectory || !currentSelectionIsFolder) {
|
|
currentSelection.text = currentSelectionPath;
|
|
} else {
|
|
currentSelection.text = "";
|
|
}
|
|
}
|
|
|
|
function navigateUp() {
|
|
if (assetTableModel.parentFolder !== "") {
|
|
assetTableModel.folder = assetTableModel.parentFolder;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function navigateHome() {
|
|
assetTableModel.folder = homeButton.destination;
|
|
return true;
|
|
}
|
|
|
|
function clearSelection() {
|
|
assetTableView.selection.clear();
|
|
assetTableView.currentRow = -1;
|
|
update();
|
|
}
|
|
}
|
|
|
|
ListModel {
|
|
id: assetTableModel
|
|
|
|
property string folder
|
|
property string parentFolder: ""
|
|
readonly property string rootFolder: "/"
|
|
|
|
onFolderChanged: {
|
|
parentFolder = calculateParentFolder();
|
|
update();
|
|
}
|
|
|
|
function calculateParentFolder() {
|
|
if (folder !== "/") {
|
|
return folder.slice(0, folder.slice(0, -1).lastIndexOf("/") + 1);
|
|
}
|
|
return "";
|
|
}
|
|
|
|
function isFolder(row) {
|
|
if (row === -1) {
|
|
return false;
|
|
}
|
|
return get(row).fileIsDir;
|
|
}
|
|
|
|
function onGetAllMappings(error, map) {
|
|
var mappings,
|
|
fileTypeFilter,
|
|
index,
|
|
path,
|
|
fileName,
|
|
fileType,
|
|
fileIsDir,
|
|
isValid,
|
|
subDirectory,
|
|
subDirectories = [],
|
|
fileNameSort,
|
|
rows = 0,
|
|
lower,
|
|
middle,
|
|
upper,
|
|
i,
|
|
length;
|
|
|
|
clear();
|
|
|
|
if (error === "") {
|
|
mappings = Object.keys(map);
|
|
fileTypeFilter = filter.replace("*", "").toLowerCase();
|
|
|
|
for (i = 0, length = mappings.length; i < length; i++) {
|
|
index = mappings[i].lastIndexOf("/");
|
|
|
|
path = mappings[i].slice(0, mappings[i].lastIndexOf("/") + 1);
|
|
fileName = mappings[i].slice(path.length);
|
|
fileType = fileName.slice(fileName.lastIndexOf("."));
|
|
fileIsDir = false;
|
|
isValid = false;
|
|
|
|
if (fileType.toLowerCase() === fileTypeFilter) {
|
|
if (path === folder) {
|
|
isValid = !selectDirectory;
|
|
} else if (path.length > folder.length) {
|
|
subDirectory = path.slice(folder.length);
|
|
index = subDirectory.indexOf("/");
|
|
if (index === subDirectory.lastIndexOf("/")) {
|
|
fileName = subDirectory.slice(0, index);
|
|
if (subDirectories.indexOf(fileName) === -1) {
|
|
fileIsDir = true;
|
|
isValid = true;
|
|
subDirectories.push(fileName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isValid) {
|
|
fileNameSort = (fileIsDir ? "*" : "") + fileName.toLowerCase();
|
|
|
|
lower = 0;
|
|
upper = rows;
|
|
while (lower < upper) {
|
|
middle = Math.floor((lower + upper) / 2);
|
|
var lessThan;
|
|
if (fileNameSort < get(middle)["fileNameSort"]) {
|
|
lessThan = true;
|
|
upper = middle;
|
|
} else {
|
|
lessThan = false;
|
|
lower = middle + 1;
|
|
}
|
|
}
|
|
|
|
insert(lower, {
|
|
fileName: fileName,
|
|
filePath: path + (fileIsDir ? "" : fileName),
|
|
fileIsDir: fileIsDir,
|
|
fileNameSort: fileNameSort
|
|
});
|
|
|
|
rows++;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
console.log("Error getting mappings from Asset Server");
|
|
}
|
|
}
|
|
|
|
function update() {
|
|
d.clearSelection();
|
|
clear();
|
|
Assets.getAllMappings(onGetAllMappings);
|
|
}
|
|
}
|
|
|
|
Table {
|
|
id: assetTableView
|
|
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
|
|
}
|
|
|
|
model: assetTableModel
|
|
|
|
focus: true
|
|
|
|
onClicked: {
|
|
if (singleClickNavigate) {
|
|
navigateToRow(row);
|
|
}
|
|
}
|
|
|
|
onDoubleClicked: navigateToRow(row);
|
|
Keys.onReturnPressed: navigateToCurrentRow();
|
|
Keys.onEnterPressed: navigateToCurrentRow();
|
|
|
|
itemDelegate: Item {
|
|
clip: true
|
|
|
|
FontLoader { id: firaSansSemiBold; source: "../../../fonts/FiraSans-SemiBold.ttf"; }
|
|
FontLoader { id: firaSansRegular; source: "../../../fonts/FiraSans-Regular.ttf"; }
|
|
|
|
FiraSansSemiBold {
|
|
text: styleData.value
|
|
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 && assetTableView.model.get(styleData.row).fileIsDir)
|
|
? firaSansSemiBold.name : firaSansRegular.name
|
|
}
|
|
}
|
|
|
|
TableViewColumn {
|
|
id: fileNameColumn
|
|
role: "fileName"
|
|
title: "Name"
|
|
width: assetTableView.width
|
|
movable: false
|
|
resizable: false
|
|
}
|
|
|
|
function navigateToRow(row) {
|
|
currentRow = row;
|
|
navigateToCurrentRow();
|
|
}
|
|
|
|
function navigateToCurrentRow() {
|
|
if (model.isFolder(currentRow)) {
|
|
model.folder = model.get(currentRow).filePath;
|
|
} else {
|
|
okAction.trigger();
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: prefixClearTimer
|
|
interval: 1000
|
|
repeat: false
|
|
running: false
|
|
onTriggered: assetTableView.prefix = "";
|
|
}
|
|
|
|
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.get(i).fileName.toLowerCase();
|
|
if (0 === name.indexOf(newPrefix)) {
|
|
matchedIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (matchedIndex !== -1) {
|
|
assetTableView.selection.clear();
|
|
assetTableView.selection.select(matchedIndex);
|
|
assetTableView.currentRow = matchedIndex;
|
|
assetTableView.prefix = newPrefix;
|
|
}
|
|
prefixClearTimer.restart();
|
|
return true;
|
|
}
|
|
|
|
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: buttonRow.top
|
|
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
}
|
|
readOnly: true
|
|
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: assetTableView
|
|
KeyNavigation.right: openButton
|
|
}
|
|
|
|
Action {
|
|
id: okAction
|
|
text: currentSelection.text && root.selectDirectory && assetTableView.currentRow === -1 ? "Choose" : "Open"
|
|
enabled: currentSelection.text || !root.selectDirectory && d.currentSelectionIsFolder ? true : false
|
|
onTriggered: {
|
|
if (!root.selectDirectory && !d.currentSelectionIsFolder
|
|
|| root.selectDirectory && assetTableView.currentRow === -1) {
|
|
selectedAsset(d.currentSelectionPath);
|
|
root.destroy();
|
|
} else {
|
|
assetTableView.navigateToCurrentRow();
|
|
}
|
|
}
|
|
}
|
|
|
|
Action {
|
|
id: cancelAction
|
|
text: "Cancel"
|
|
onTriggered: {
|
|
canceled();
|
|
root.destroy();
|
|
}
|
|
}
|
|
|
|
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: assetTableView.contentItem
|
|
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
|
}
|
|
}
|
|
}
|
|
|
|
Keys.onPressed: {
|
|
switch (event.key) {
|
|
case Qt.Key_Backspace:
|
|
event.accepted = d.navigateUp();
|
|
break;
|
|
|
|
case Qt.Key_Home:
|
|
event.accepted = d.navigateHome();
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|