mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 18:42:58 +02:00
Support for directory browsing
This commit is contained in:
parent
2026821d9e
commit
c7186590ea
11 changed files with 364 additions and 294 deletions
|
@ -6,11 +6,19 @@ import Qt.labs.settings 1.0
|
||||||
import ".."
|
import ".."
|
||||||
import "../windows"
|
import "../windows"
|
||||||
import "../styles"
|
import "../styles"
|
||||||
|
import "../controls" as VrControls
|
||||||
|
import "fileDialog"
|
||||||
|
|
||||||
// Work in progress....
|
//FIXME implement shortcuts for favorite location
|
||||||
ModalWindow {
|
ModalWindow {
|
||||||
id: root
|
id: root
|
||||||
HifiConstants { id: hifi }
|
|
||||||
|
property bool selectDirectory: false;
|
||||||
|
property bool showHidden: false;
|
||||||
|
// FIXME implement
|
||||||
|
property bool multiSelect: false;
|
||||||
|
// FIXME implement
|
||||||
|
property bool saveDialog: false;
|
||||||
|
|
||||||
signal selectedFile(var file);
|
signal selectedFile(var file);
|
||||||
signal canceled();
|
signal canceled();
|
||||||
|
@ -18,149 +26,144 @@ ModalWindow {
|
||||||
width: 640
|
width: 640
|
||||||
height: 480
|
height: 480
|
||||||
|
|
||||||
property string settingsName: ""
|
property var helper: fileDialogHelper
|
||||||
property alias folder: folderModel.folder
|
property alias model: fileTableView.model
|
||||||
property alias filterModel: selectionType.model
|
property alias filterModel: selectionType.model
|
||||||
|
property alias folder: model.folder
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: "white"
|
color: "white"
|
||||||
|
|
||||||
Settings {
|
Row {
|
||||||
// fixme, combine with a property to allow different saved locations
|
id: navControls
|
||||||
category: "FileOpenLastFolder." + settingsName
|
anchors { left: parent.left; top: parent.top; margins: 8 }
|
||||||
property alias folder: folderModel.folder
|
spacing: 8
|
||||||
|
// FIXME implement back button
|
||||||
|
// VrControls.FontAwesome {
|
||||||
|
// id: backButton
|
||||||
|
// text: "\uf0a8"
|
||||||
|
// size: currentDirectory.height
|
||||||
|
// enabled: d.backStack.length != 0
|
||||||
|
// MouseArea { anchors.fill: parent; onClicked: d.navigateBack() }
|
||||||
|
// }
|
||||||
|
VrControls.FontAwesome {
|
||||||
|
id: upButton
|
||||||
|
text: "\uf0aa"
|
||||||
|
size: currentDirectory.height
|
||||||
|
color: enabled ? "black" : "gray"
|
||||||
|
MouseArea { anchors.fill: parent; onClicked: d.navigateUp() }
|
||||||
|
}
|
||||||
|
VrControls.FontAwesome {
|
||||||
|
id: homeButton
|
||||||
|
property var destination: helper.home();
|
||||||
|
visible: destination ? true : false
|
||||||
|
text: "\uf015"
|
||||||
|
size: currentDirectory.height
|
||||||
|
MouseArea { anchors.fill: parent; onClicked: model.folder = parent.destination }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: currentDirectory
|
id: currentDirectory
|
||||||
anchors.left: parent.left
|
anchors { left: navControls.right; right: parent.right; top: parent.top; margins: 8 }
|
||||||
anchors.right: parent.right
|
property var lastValidFolder: helper.urlToPath(model.folder)
|
||||||
anchors.top: parent.top
|
onLastValidFolderChanged: text = lastValidFolder;
|
||||||
anchors.margins: 8
|
|
||||||
readOnly: true
|
// FIXME add support auto-completion
|
||||||
text: folderModel.folder
|
onAccepted: {
|
||||||
|
if (!helper.validFolder(text)) {
|
||||||
|
text = lastValidFolder;
|
||||||
|
return
|
||||||
|
}
|
||||||
|
model.folder = helper.pathToUrl(text);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
QtObject {
|
||||||
id: fileItemDelegate
|
id: d
|
||||||
Item {
|
property var currentSelectionUrl;
|
||||||
clip: true
|
readonly property string currentSelectionPath: helper.urlToPath(currentSelectionUrl);
|
||||||
Text {
|
property bool currentSelectionIsFolder;
|
||||||
x: 3
|
property var backStack: []
|
||||||
id: columnText
|
property var tableViewConnection: Connections { target: fileTableView; onCurrentRowChanged: d.update(); }
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
property var modelConnection: Connections { target: model; onFolderChanged: d.update(); }
|
||||||
// font.pointSize: 12
|
Component.onCompleted: update();
|
||||||
color: tableView.activeFocus && styleData.row === tableView.currentRow ? "yellow" : styleData.textColor
|
|
||||||
elide: styleData.elideMode
|
|
||||||
text: getText();
|
|
||||||
font.italic: folderModel.get(styleData.row, "fileIsDir") ? true : false
|
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
var row = fileTableView.currentRow;
|
||||||
|
if (row === -1 && root.selectDirectory) {
|
||||||
|
currentSelectionUrl = fileTableView.model.folder;
|
||||||
|
currentSelectionIsFolder = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
currentSelectionUrl = fileTableView.model.get(row, "fileURL");
|
||||||
target: tableView
|
currentSelectionIsFolder = fileTableView.model.isFolder(row);
|
||||||
//onCurrentRowChanged: columnText.color = (tableView.activeFocus && styleData.row === tableView.currentRow ? "yellow" : styleData.textColor)
|
if (root.selectDirectory || !currentSelectionIsFolder) {
|
||||||
}
|
currentSelection.text = helper.urlToPath(currentSelectionUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getText() {
|
function navigateUp() {
|
||||||
switch (styleData.column) {
|
if (model.parentFolder && model.parentFolder !== "") {
|
||||||
//case 1: return Date.fromLocaleString(locale, styleData.value, "yyyy-MM-dd hh:mm:ss");
|
model.folder = model.parentFolder
|
||||||
case 2: return folderModel.get(styleData.row, "fileIsDir") ? "" : formatSize(styleData.value);
|
return true;
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TableView {
|
FileTableView {
|
||||||
id: tableView
|
id: fileTableView
|
||||||
focus: true
|
anchors { left: parent.left; right: parent.right; top: currentDirectory.bottom; bottom: currentSelection.top; margins: 8 }
|
||||||
|
onDoubleClicked: navigateToRow(row);
|
||||||
model: FolderListModel {
|
model: FolderListModel {
|
||||||
id: folderModel
|
id: model
|
||||||
showDotAndDotDot: true
|
|
||||||
showDirsFirst: true
|
showDirsFirst: true
|
||||||
onFolderChanged: {
|
showDotAndDotDot: false
|
||||||
tableView.currentRow = -1;
|
showFiles: !root.selectDirectory
|
||||||
tableView.positionViewAtRow(0, ListView.Beginning)
|
// For some reason, declaring these bindings directly in the targets doesn't
|
||||||
|
// work for setting the initial state
|
||||||
|
Component.onCompleted: {
|
||||||
|
currentDirectory.lastValidFolder = Qt.binding(function() { return helper.urlToPath(model.folder); });
|
||||||
|
upButton.enabled = Qt.binding(function() { return (model.parentFolder && model.parentFolder != "") ? true : false; });
|
||||||
|
showFiles = !root.selectDirectory
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
anchors.top: currentDirectory.bottom
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: selectionType.top
|
|
||||||
anchors.margins: 8
|
|
||||||
itemDelegate: fileItemDelegate
|
|
||||||
// rowDelegate: Rectangle {
|
|
||||||
// id: rowDelegate
|
|
||||||
// color: styleData.selected ? "#7f0000ff" : "#00000000"
|
|
||||||
// Connections { target: folderModel; onFolderChanged: rowDelegate.visible = false }
|
|
||||||
// Connections { target: tableView; onCurrentRowChanged: rowDelegate.visible = true; }
|
|
||||||
// }
|
|
||||||
|
|
||||||
TableViewColumn {
|
function navigateToRow(row) {
|
||||||
role: "fileName"
|
currentRow = row;
|
||||||
title: "Name"
|
navigateToCurrentRow();
|
||||||
width: 400
|
|
||||||
}
|
|
||||||
TableViewColumn {
|
|
||||||
role: "fileModified"
|
|
||||||
title: "Date Modified"
|
|
||||||
width: 200
|
|
||||||
}
|
|
||||||
TableViewColumn {
|
|
||||||
role: "fileSize"
|
|
||||||
title: "Size"
|
|
||||||
width: 200
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onReturnPressed: selectCurrentFile();
|
function navigateToCurrentRow() {
|
||||||
onDoubleClicked: { currentRow = row; selectCurrentFile(); }
|
var row = fileTableView.currentRow
|
||||||
onCurrentRowChanged: currentSelection.text = model.get(currentRow, "fileName");
|
var isFolder = model.isFolder(row);
|
||||||
KeyNavigation.left: cancelButton
|
var file = model.get(row, "fileURL");
|
||||||
KeyNavigation.right: selectionType
|
if (isFolder) {
|
||||||
|
fileTableView.model.folder = file
|
||||||
|
currentRow = -1;
|
||||||
|
} else {
|
||||||
|
root.selectedFile(file);
|
||||||
|
root.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: currentSelection
|
id: currentSelection
|
||||||
anchors.right: selectionType.left
|
anchors { right: root.selectDirectory ? parent.right : selectionType.left; rightMargin: 8; left: parent.left; leftMargin: 8; top: selectionType.top }
|
||||||
anchors.rightMargin: 8
|
readOnly: true
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: 8
|
|
||||||
anchors.top: selectionType.top
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: selectionType
|
id: selectionType
|
||||||
anchors.bottom: buttonRow.top
|
anchors { bottom: buttonRow.top; bottomMargin: 8; right: parent.right; rightMargin: 8; left: buttonRow.left }
|
||||||
anchors.bottomMargin: 8
|
visible: !selectDirectory
|
||||||
anchors.right: parent.right
|
model: ListModel { ListElement { text: "All Files (*.*)"; filter: "*.*" } }
|
||||||
anchors.rightMargin: 8
|
// onCurrentIndexChanged: model.nameFilters = [ filterModel.get(currentIndex).filter ]
|
||||||
anchors.left: buttonRow.left
|
KeyNavigation.left: fileTableView
|
||||||
|
|
||||||
model: ListModel {
|
|
||||||
ListElement { text: "All Files (*.*)"; filter: "*.*" }
|
|
||||||
}
|
|
||||||
|
|
||||||
onCurrentIndexChanged: {
|
|
||||||
folderModel.nameFilters = [ filterModel.get(currentIndex).filter ]
|
|
||||||
}
|
|
||||||
KeyNavigation.left: tableView
|
|
||||||
KeyNavigation.right: openButton
|
KeyNavigation.right: openButton
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,16 +180,16 @@ ModalWindow {
|
||||||
text: "Cancel"
|
text: "Cancel"
|
||||||
KeyNavigation.up: selectionType
|
KeyNavigation.up: selectionType
|
||||||
KeyNavigation.left: openButton
|
KeyNavigation.left: openButton
|
||||||
KeyNavigation.right: tableView.contentItem
|
KeyNavigation.right: fileTableView.contentItem
|
||||||
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
Keys.onReturnPressed: { canceled(); root.enabled = false }
|
||||||
onClicked: { canceled(); close() }
|
onClicked: { canceled(); close() }
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
id: openButton
|
id: openButton
|
||||||
text: "Open"
|
text: root.selectDirectory ? "Choose" : "Open"
|
||||||
enabled: tableView.currentRow != -1 && !folderModel.get(tableView.currentRow, "fileIsDir")
|
enabled: currentSelection.text ? true : false
|
||||||
onClicked: selectCurrentFile();
|
onClicked: { selectedFile(d.currentSelectionUrl); close(); }
|
||||||
Keys.onReturnPressed: selectCurrentFile();
|
Keys.onReturnPressed: { selectedFile(d.currentSelectionUrl); close(); }
|
||||||
|
|
||||||
KeyNavigation.up: selectionType
|
KeyNavigation.up: selectionType
|
||||||
KeyNavigation.left: selectionType
|
KeyNavigation.left: selectionType
|
||||||
|
@ -195,26 +198,8 @@ ModalWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectCurrentFile() {
|
|
||||||
var row = tableView.currentRow
|
|
||||||
console.log("Selecting row " + row)
|
|
||||||
var fileName = folderModel.get(row, "fileName");
|
|
||||||
if (fileName === "..") {
|
|
||||||
folderModel.folder = folderModel.parentFolder
|
|
||||||
} else if (folderModel.isFolder(row)) {
|
|
||||||
folderModel.folder = folderModel.get(row, "fileURL");
|
|
||||||
} else {
|
|
||||||
selectedFile(folderModel.get(row, "fileURL"));
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Keys.onPressed: {
|
Keys.onPressed: {
|
||||||
if (event.key === Qt.Key_Backspace && folderModel.parentFolder && folderModel.parentFolder != "") {
|
if (event.key === Qt.Key_Backspace && d.navigateUp()) {
|
||||||
console.log("Navigating to " + folderModel.parentFolder)
|
|
||||||
folderModel.folder = folderModel.parentFolder
|
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
59
interface/resources/qml/dialogs/fileDialog/FileTableView.qml
Normal file
59
interface/resources/qml/dialogs/fileDialog/FileTableView.qml
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import QtQuick 2.0
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
|
||||||
|
TableView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
itemDelegate: Component {
|
||||||
|
Item {
|
||||||
|
clip: true
|
||||||
|
Text {
|
||||||
|
x: 3
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
color: root.activeFocus && styleData.row === root.currentRow ? "yellow" : styleData.textColor
|
||||||
|
elide: styleData.elideMode
|
||||||
|
text: getText();
|
||||||
|
font.italic: root.model.get(styleData.row, "fileIsDir") ? true : false
|
||||||
|
|
||||||
|
function getText() {
|
||||||
|
switch (styleData.column) {
|
||||||
|
//case 1: return Date.fromLocaleString(locale, styleData.value, "yyyy-MM-dd hh:mm:ss");
|
||||||
|
case 2: return root.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 {
|
||||||
|
role: "fileName"
|
||||||
|
title: "Name"
|
||||||
|
width: 400
|
||||||
|
}
|
||||||
|
TableViewColumn {
|
||||||
|
role: "fileModified"
|
||||||
|
title: "Date Modified"
|
||||||
|
width: 200
|
||||||
|
}
|
||||||
|
TableViewColumn {
|
||||||
|
role: "fileSize"
|
||||||
|
title: "Size"
|
||||||
|
width: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
33
interface/resources/qml/hifi/dialogs/preferences/Avatar.qml
Normal file
33
interface/resources/qml/hifi/dialogs/preferences/Avatar.qml
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4 as Original
|
||||||
|
import "."
|
||||||
|
|
||||||
|
Preference {
|
||||||
|
id: root
|
||||||
|
property alias spinner: spinner
|
||||||
|
height: spinner.height
|
||||||
|
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
spinner.value = preference.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
|
preference.value = spinner.value;
|
||||||
|
preference.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.label
|
||||||
|
anchors.verticalCenter: spinner.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Original.SpinBox {
|
||||||
|
id: spinner
|
||||||
|
decimals: preference.decimals
|
||||||
|
minimumValue: preference.min
|
||||||
|
maximumValue: preference.max
|
||||||
|
width: 100
|
||||||
|
anchors { right: parent.right }
|
||||||
|
}
|
||||||
|
}
|
40
libraries/ui/src/FileDialogHelper.cpp
Normal file
40
libraries/ui/src/FileDialogHelper.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// OffscreenUi.cpp
|
||||||
|
// interface/src/render-utils
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2015-04-04
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
#include "FileDialogHelper.h"
|
||||||
|
|
||||||
|
#include <QtCore/QDir>
|
||||||
|
#include <QtCore/QFile>
|
||||||
|
|
||||||
|
|
||||||
|
QUrl FileDialogHelper::home() {
|
||||||
|
return pathToUrl(QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList FileDialogHelper::standardPath(StandardLocation location) {
|
||||||
|
return QStandardPaths::standardLocations(static_cast<QStandardPaths::StandardLocation>(location));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileDialogHelper::urlToPath(const QUrl& url) {
|
||||||
|
return url.toLocalFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileDialogHelper::validPath(const QString& path) {
|
||||||
|
return QFile(path).exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileDialogHelper::validFolder(const QString& path) {
|
||||||
|
return QDir(path).exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl FileDialogHelper::pathToUrl(const QString& path) {
|
||||||
|
return QUrl::fromLocalFile(path);
|
||||||
|
}
|
||||||
|
|
57
libraries/ui/src/FileDialogHelper.h
Normal file
57
libraries/ui/src/FileDialogHelper.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2016-01-21
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_ui_FileDialogHelper_h
|
||||||
|
#define hifi_ui_FileDialogHelper_h
|
||||||
|
|
||||||
|
#include <QtCore/QObject>
|
||||||
|
#include <QtCore/QStandardPaths>
|
||||||
|
#include <QtCore/QUrl>
|
||||||
|
#include <QtCore/QString>
|
||||||
|
#include <QtCore/QStringList>
|
||||||
|
|
||||||
|
|
||||||
|
class FileDialogHelper : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_ENUMS(StandardLocation)
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Do not re-order, must match QDesktopServices
|
||||||
|
enum StandardLocation {
|
||||||
|
DesktopLocation,
|
||||||
|
DocumentsLocation,
|
||||||
|
FontsLocation,
|
||||||
|
ApplicationsLocation,
|
||||||
|
MusicLocation,
|
||||||
|
MoviesLocation,
|
||||||
|
PicturesLocation,
|
||||||
|
TempLocation,
|
||||||
|
HomeLocation,
|
||||||
|
DataLocation,
|
||||||
|
CacheLocation,
|
||||||
|
GenericDataLocation,
|
||||||
|
RuntimeLocation,
|
||||||
|
ConfigLocation,
|
||||||
|
DownloadLocation,
|
||||||
|
GenericCacheLocation,
|
||||||
|
GenericConfigLocation,
|
||||||
|
AppDataLocation,
|
||||||
|
AppConfigLocation,
|
||||||
|
AppLocalDataLocation = DataLocation
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_INVOKABLE QUrl home();
|
||||||
|
Q_INVOKABLE QStringList standardPath(StandardLocation location);
|
||||||
|
Q_INVOKABLE QString urlToPath(const QUrl& url);
|
||||||
|
Q_INVOKABLE bool validPath(const QString& path);
|
||||||
|
Q_INVOKABLE bool validFolder(const QString& path);
|
||||||
|
Q_INVOKABLE QUrl pathToUrl(const QString& path);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -17,8 +17,10 @@
|
||||||
#include <AbstractUriHandler.h>
|
#include <AbstractUriHandler.h>
|
||||||
#include <AccountManager.h>
|
#include <AccountManager.h>
|
||||||
|
|
||||||
|
#include "FileDialogHelper.h"
|
||||||
#include "VrMenu.h"
|
#include "VrMenu.h"
|
||||||
|
|
||||||
|
|
||||||
// Needs to match the constants in resources/qml/Global.js
|
// Needs to match the constants in resources/qml/Global.js
|
||||||
class OffscreenFlags : public QObject {
|
class OffscreenFlags : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -74,7 +76,6 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static UrlHandler * urlHandler { nullptr };
|
|
||||||
static OffscreenFlags* offscreenFlags { nullptr };
|
static OffscreenFlags* offscreenFlags { nullptr };
|
||||||
|
|
||||||
// This hack allows the QML UI to work with keys that are also bound as
|
// This hack allows the QML UI to work with keys that are also bound as
|
||||||
|
@ -102,10 +103,9 @@ void OffscreenUi::create(QOpenGLContext* context) {
|
||||||
OffscreenQmlSurface::create(context);
|
OffscreenQmlSurface::create(context);
|
||||||
auto rootContext = getRootContext();
|
auto rootContext = getRootContext();
|
||||||
|
|
||||||
offscreenFlags = new OffscreenFlags();
|
rootContext->setContextProperty("offscreenFlags", offscreenFlags = new OffscreenFlags());
|
||||||
rootContext->setContextProperty("offscreenFlags", offscreenFlags);
|
rootContext->setContextProperty("urlHandler", new UrlHandler());
|
||||||
urlHandler = new UrlHandler();
|
rootContext->setContextProperty("fileDialogHelper", new FileDialogHelper());
|
||||||
rootContext->setContextProperty("urlHandler", urlHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OffscreenUi::show(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) {
|
void OffscreenUi::show(const QUrl& url, const QString& name, std::function<void(QQmlContext*, QObject*)> f) {
|
||||||
|
|
|
@ -5,6 +5,11 @@ import QtQuick.Controls 1.4
|
||||||
// This is useful for testing inside Qt creator where these services don't actually exist.
|
// This is useful for testing inside Qt creator where these services don't actually exist.
|
||||||
Item {
|
Item {
|
||||||
|
|
||||||
|
Item {
|
||||||
|
objectName: "offscreenFlags"
|
||||||
|
property bool navigationFocused: false
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
objectName: "urlHandler"
|
objectName: "urlHandler"
|
||||||
function fixupUrl(url) { return url; }
|
function fixupUrl(url) { return url; }
|
||||||
|
|
|
@ -16,34 +16,18 @@ ApplicationWindow {
|
||||||
height: 720
|
height: 720
|
||||||
title: qsTr("Scratch App")
|
title: qsTr("Scratch App")
|
||||||
|
|
||||||
Component { id: listModelBuilder; ListModel{} }
|
|
||||||
|
|
||||||
function menuItemsToModel(menu) {
|
|
||||||
var items = menu.items
|
|
||||||
var newListModel = listModelBuilder.createObject(desktop);
|
|
||||||
for (var i = 0; i < items.length; ++i) {
|
|
||||||
var item = items[i];
|
|
||||||
switch (item.type) {
|
|
||||||
case 2:
|
|
||||||
newListModel.append({"type":item.type, "name": item.title, "item": item})
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
newListModel.append({"type":item.type, "name": item.text, "item": item})
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
newListModel.append({"type":item.type, "name": "-----", "item": item})
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newListModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
Desktop {
|
Desktop {
|
||||||
id: desktop
|
id: desktop
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
StubMenu { id: stubMenu }
|
rootMenu: StubMenu { id: rootMenu }
|
||||||
Component.onCompleted: offscreenWindow = appWindow
|
Component.onCompleted: offscreenWindow = appWindow
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.RightButton
|
||||||
|
onClicked: desktop.popupMenu(Qt.vector2d(mouseX, mouseY));
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: testButtons
|
id: testButtons
|
||||||
anchors { margins: 8; left: parent.left; top: parent.top }
|
anchors { margins: 8; left: parent.left; top: parent.top }
|
||||||
|
@ -52,6 +36,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
property var tabs: [];
|
property var tabs: [];
|
||||||
property var urls: [];
|
property var urls: [];
|
||||||
|
/*
|
||||||
Button {
|
Button {
|
||||||
text: "restore all"
|
text: "restore all"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
@ -72,6 +57,7 @@ ApplicationWindow {
|
||||||
blue.enabled = !blue.enabled
|
blue.enabled = !blue.enabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
Button {
|
Button {
|
||||||
text: "Show Long Error"
|
text: "Show Long Error"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
@ -93,21 +79,13 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
text: "Open File"
|
text: "Open Directory"
|
||||||
property var builder: Component {
|
property var builder: Component {
|
||||||
FileDialog { }
|
FileDialog { selectDirectory: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
ListModel {
|
|
||||||
id: jsFilters
|
|
||||||
ListElement { text: "Javascript Files (*.js)"; filter: "*.js" }
|
|
||||||
ListElement { text: "All Files (*.*)"; filter: "*.*" }
|
|
||||||
}
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var fileDialogProperties = {
|
var fileDialog = builder.createObject(desktop);
|
||||||
filterModel: jsFilters
|
|
||||||
}
|
|
||||||
var fileDialog = builder.createObject(desktop, fileDialogProperties);
|
|
||||||
fileDialog.canceled.connect(function(){
|
fileDialog.canceled.connect(function(){
|
||||||
console.log("Cancelled")
|
console.log("Cancelled")
|
||||||
})
|
})
|
||||||
|
@ -116,24 +94,31 @@ ApplicationWindow {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "Focus Test"
|
text: "Open File"
|
||||||
|
property var builder: Component {
|
||||||
|
FileDialog {
|
||||||
|
folder: "file:///C:/users/bdavis";
|
||||||
|
filterModel: ListModel {
|
||||||
|
ListElement { text: "Javascript Files (*.js)"; filter: "*.js" }
|
||||||
|
ListElement { text: "All Files (*.*)"; filter: "*.*" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var item = desktop;
|
var fileDialog = builder.createObject(desktop);
|
||||||
while (item) {
|
fileDialog.canceled.connect(function(){
|
||||||
console.log(item);
|
console.log("Cancelled")
|
||||||
item = item.parent;
|
})
|
||||||
}
|
fileDialog.selectedFile.connect(function(file){
|
||||||
item = appWindow
|
console.log("Selected " + file)
|
||||||
while (item) {
|
})
|
||||||
console.log(item);
|
|
||||||
item = item.parent;
|
|
||||||
}
|
|
||||||
console.log(appWindow.activeFocusItem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
Window {
|
Window {
|
||||||
id: blue
|
id: blue
|
||||||
closable: true
|
closable: true
|
||||||
|
@ -189,109 +174,6 @@ ApplicationWindow {
|
||||||
color: "yellow"
|
color: "yellow"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Arcane.Test {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
height: 600; width: 600
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: desktop
|
|
||||||
anchors.fill: parent
|
|
||||||
objectName: Desktop._OFFSCREEN_ROOT_OBJECT_NAME
|
|
||||||
property bool uiVisible: true
|
|
||||||
property variant toolbars: { "_root" : null }
|
|
||||||
focus: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: root
|
|
||||||
Vr.Constants { id: vr }
|
|
||||||
implicitWidth: 384; implicitHeight: 640
|
|
||||||
anchors.centerIn: parent
|
|
||||||
color: vr.windows.colors.background
|
|
||||||
border.color: vr.controls.colors.background
|
|
||||||
border.width: vr.styles.borderWidth
|
|
||||||
radius: vr.styles.borderRadius
|
|
||||||
RunningScripts { }
|
|
||||||
}
|
|
||||||
|
|
||||||
FileDialog {
|
|
||||||
id: fileDialog
|
|
||||||
width: 800; height: 600
|
|
||||||
anchors.centerIn: parent
|
|
||||||
onSelectedFile: console.log("Chose file " + file)
|
|
||||||
}
|
|
||||||
Timer {
|
|
||||||
id: timer
|
|
||||||
running: false
|
|
||||||
interval: 100
|
|
||||||
onTriggered: wireFrameContainer.enabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: wireFrameContainer
|
|
||||||
objectName: Desktop._OFFSCREEN_DIALOG_OBJECT_NAME
|
|
||||||
anchors.fill: parent
|
|
||||||
onEnabledChanged: if (!enabled) timer.running = true
|
|
||||||
|
|
||||||
NewUi.Main {
|
|
||||||
id: wireFrame
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
property var offscreenFlags: Item {
|
|
||||||
property bool navigationFocused: false
|
|
||||||
}
|
|
||||||
|
|
||||||
property var urlHandler: Item {
|
|
||||||
function fixupUrl(url) {
|
|
||||||
var urlString = url.toString();
|
|
||||||
if (urlString.indexOf("https://metaverse.highfidelity.com/") !== -1 &&
|
|
||||||
urlString.indexOf("access_token") === -1) {
|
|
||||||
console.log("metaverse URL, fixing")
|
|
||||||
return urlString + "?access_token=875885020b1d5f1ea694ce971c8601fa33ffd77f61851be01ed1e3fde8cabbe9"
|
|
||||||
}
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
function canHandleUrl(url) {
|
|
||||||
var urlString = url.toString();
|
|
||||||
if (urlString.indexOf("hifi://") === 0) {
|
|
||||||
console.log("Can handle hifi addresses: " + urlString)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urlString.indexOf(".svo.json?") !== -1) {
|
|
||||||
console.log("Can handle svo json addresses: " + urlString)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urlString.indexOf(".js?") !== -1) {
|
|
||||||
console.log("Can handle javascript addresses: " + urlString)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleUrl(url) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property var addressManager: Item {
|
|
||||||
function navigate(url) {
|
|
||||||
console.log("Navigate to: " + url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Keys.onMenuPressed: desktop.uiVisible = !desktop.uiVisible
|
|
||||||
Keys.onEscapePressed: desktop.uiVisible = !desktop.uiVisible
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ QT += gui qml quick xml webengine widgets
|
||||||
|
|
||||||
CONFIG += c++11
|
CONFIG += c++11
|
||||||
|
|
||||||
SOURCES += src/main.cpp
|
SOURCES += src/main.cpp \
|
||||||
|
../../libraries/ui/src/FileDialogHelper.cpp
|
||||||
|
|
||||||
# Additional import path used to resolve QML modules in Qt Creator's code model
|
# Additional import path used to resolve QML modules in Qt Creator's code model
|
||||||
QML_IMPORT_PATH =
|
QML_IMPORT_PATH =
|
||||||
|
@ -96,4 +97,10 @@ DISTFILES += \
|
||||||
../../interface/resources/qml/hifi/dialogs/preferences/Slider.qml \
|
../../interface/resources/qml/hifi/dialogs/preferences/Slider.qml \
|
||||||
../../interface/resources/qml/hifi/dialogs/preferences/Preference.qml \
|
../../interface/resources/qml/hifi/dialogs/preferences/Preference.qml \
|
||||||
../../interface/resources/qml/hifi/dialogs/preferences/SpinBox.qml \
|
../../interface/resources/qml/hifi/dialogs/preferences/SpinBox.qml \
|
||||||
../../interface/resources/qml/hifi/dialogs/preferences/CheckBox.qml
|
../../interface/resources/qml/hifi/dialogs/preferences/CheckBox.qml \
|
||||||
|
../../interface/resources/qml/dialogs/fileDialog/FileTableView.qml \
|
||||||
|
../../interface/resources/qml/hifi/dialogs/preferences/Avatar.qml \
|
||||||
|
../../interface/resources/qml/hifi/dialogs/preferences/AvatarBrowser.qml
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
../../libraries/ui/src/FileDialogHelper.h
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <QtWebEngine>
|
#include <QtWebEngine>
|
||||||
#include <QFileSystemModel>
|
#include <QFileSystemModel>
|
||||||
|
|
||||||
|
#include "../../../libraries/ui/src/FileDialogHelper.h"
|
||||||
|
|
||||||
|
|
||||||
class Preference : public QObject {
|
class Preference : public QObject {
|
||||||
|
@ -82,13 +83,14 @@ int main(int argc, char *argv[]) {
|
||||||
addImportPath(engine, "../../../interface/resources/qml");
|
addImportPath(engine, "../../../interface/resources/qml");
|
||||||
engine.load(QUrl(QStringLiteral("qml/Stubs.qml")));
|
engine.load(QUrl(QStringLiteral("qml/Stubs.qml")));
|
||||||
|
|
||||||
setChild(engine, "rootMenu");
|
setChild(engine, "offscreenFlags");
|
||||||
setChild(engine, "Account");
|
setChild(engine, "Account");
|
||||||
setChild(engine, "Desktop");
|
setChild(engine, "Desktop");
|
||||||
setChild(engine, "ScriptDiscoveryService");
|
setChild(engine, "ScriptDiscoveryService");
|
||||||
setChild(engine, "MenuHelper");
|
setChild(engine, "MenuHelper");
|
||||||
setChild(engine, "urlHandler");
|
setChild(engine, "urlHandler");
|
||||||
engine.rootContext()->setContextProperty("DebugQML", true);
|
engine.rootContext()->setContextProperty("DebugQML", true);
|
||||||
|
engine.rootContext()->setContextProperty("fileDialogHelper", new FileDialogHelper());
|
||||||
|
|
||||||
//engine.load(QUrl(QStringLiteral("qrc:/qml/gallery/main.qml")));
|
//engine.load(QUrl(QStringLiteral("qrc:/qml/gallery/main.qml")));
|
||||||
engine.load(QUrl(QStringLiteral("qml/main.qml")));
|
engine.load(QUrl(QStringLiteral("qml/main.qml")));
|
||||||
|
|
Loading…
Reference in a new issue