Move open dialogue to separate file provider plug-in

We can now define plug-ins that specify where to open files from. This is one of the places where you can open files.
This breaks the main button to open files in the interface. It needs to be redirected to trigger the plug-in to show the open file dialogue.

Contributest o issue CURA-7868.
This commit is contained in:
Ghostkeeper 2021-01-04 15:48:51 +01:00
parent 4b375ce2fe
commit 00de7497a4
No known key found for this signature in database
GPG Key ID: D2A8871EE34EC59A
5 changed files with 237 additions and 147 deletions

View File

@ -0,0 +1,47 @@
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
import os.path
from UM.FileProvider import FileProvider # The plug-in type we're going to implement.
from UM.i18n import i18nCatalog
from UM.Logger import Logger
from UM.PluginRegistry import PluginRegistry # To get resources from the plug-in folder.
from cura.CuraApplication import CuraApplication # To create QML elements.
i18n_catalog = i18nCatalog("cura")
class LocalFileProvider(FileProvider):
"""
Allows the user to open files from their local file system.
These files will then be interpreted through the file handlers.
"""
def __init__(self):
super().__init__()
self.menu_item_display_text = i18n_catalog.i18nc("@menu Open files from local disk", "Local disk")
self.shortcut = "Ctrl+O"
self._dialog = None # Lazy-load this QML element.
def _load_file_dialog(self):
"""
Loads the file dialog QML element into the QML context so that it can be shown.
:return:
"""
plugin_path = PluginRegistry.getInstance().getPluginPath(self.getPluginId())
if plugin_path is None:
plugin_path = os.path.dirname(__file__)
path = os.path.join(plugin_path, "OpenLocalFile.qml")
self._dialog = CuraApplication.getInstance().createQmlComponent(path)
if self._dialog is None:
Logger.log("e", "Unable to create open file dialogue.")
def run(self):
if self._dialog is None:
self._load_file_dialog()
if self._dialog is None:
return # Will already have logged an error in _load_file_dialog.
self._dialog.show()

View File

@ -0,0 +1,171 @@
// Copyright (c) 2021 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7
import QtQuick.Dialogs 1.2
import UM 1.3 as UM
import Cura 1.1 as Cura
Item
{
id: base
function show()
{
openDialog.visible = true;
}
UM.I18nCatalog
{
id: catalog
name: "cura"
}
FileDialog
{
id: openDialog;
//: File open dialog title
title: catalog.i18nc("@title:window","Open file(s)")
modality: Qt.WindowModal
selectMultiple: true
nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
folder:
{
//Because several implementations of the file dialog only update the folder when it is explicitly set.
folder = CuraApplication.getDefaultPath("dialog_load_path");
return CuraApplication.getDefaultPath("dialog_load_path");
}
onAccepted:
{
// Because several implementations of the file dialog only update the folder
// when it is explicitly set.
var f = folder;
folder = f;
CuraApplication.setDefaultPath("dialog_load_path", folder);
handleOpenFileUrls(fileUrls);
}
// Yeah... I know... it is a mess to put all those things here.
// There are lots of user interactions in this part of the logic, such as showing a warning dialog here and there,
// etc. This means it will come back and forth from time to time between QML and Python. So, separating the logic
// and view here may require more effort but make things more difficult to understand.
function handleOpenFileUrls(fileUrlList)
{
// look for valid project files
var projectFileUrlList = [];
var hasGcode = false;
var nonGcodeFileList = [];
for (var i in fileUrlList)
{
var endsWithG = /\.g$/;
var endsWithGcode = /\.gcode$/;
if (endsWithG.test(fileUrlList[i]) || endsWithGcode.test(fileUrlList[i]))
{
continue;
}
else if (CuraApplication.checkIsValidProjectFile(fileUrlList[i]))
{
projectFileUrlList.push(fileUrlList[i]);
}
nonGcodeFileList.push(fileUrlList[i]);
}
hasGcode = nonGcodeFileList.length < fileUrlList.length;
// show a warning if selected multiple files together with Gcode
var hasProjectFile = projectFileUrlList.length > 0;
var selectedMultipleFiles = fileUrlList.length > 1;
if (selectedMultipleFiles && hasGcode)
{
infoMultipleFilesWithGcodeDialog.selectedMultipleFiles = selectedMultipleFiles;
infoMultipleFilesWithGcodeDialog.hasProjectFile = hasProjectFile;
infoMultipleFilesWithGcodeDialog.fileUrls = nonGcodeFileList.slice();
infoMultipleFilesWithGcodeDialog.projectFileUrlList = projectFileUrlList.slice();
infoMultipleFilesWithGcodeDialog.open();
}
else
{
handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList);
}
}
function handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList)
{
// we only allow opening one project file
if (selectedMultipleFiles && hasProjectFile)
{
openFilesIncludingProjectsDialog.fileUrls = fileUrlList.slice();
openFilesIncludingProjectsDialog.show();
return;
}
if (hasProjectFile)
{
var projectFile = projectFileUrlList[0];
// check preference
var choice = UM.Preferences.getValue("cura/choice_on_open_project");
if (choice == "open_as_project")
{
openFilesIncludingProjectsDialog.loadProjectFile(projectFile);
}
else if (choice == "open_as_model")
{
openFilesIncludingProjectsDialog.loadModelFiles([projectFile].slice());
}
else // always ask
{
// ask whether to open as project or as models
askOpenAsProjectOrModelsDialog.fileUrl = projectFile;
askOpenAsProjectOrModelsDialog.show();
}
}
else
{
openFilesIncludingProjectsDialog.loadModelFiles(fileUrlList.slice());
}
}
}
MessageDialog
{
id: infoMultipleFilesWithGcodeDialog
title: catalog.i18nc("@title:window", "Open File(s)")
icon: StandardIcon.Information
standardButtons: StandardButton.Ok
text: catalog.i18nc("@text:window", "We have found one or more G-Code files within the files you have selected. You can only open one G-Code file at a time. If you want to open a G-Code file, please just select only one.")
property var selectedMultipleFiles
property var hasProjectFile
property var fileUrls
property var projectFileUrlList
onAccepted:
{
openDialog.handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrls, projectFileUrlList);
}
}
Cura.AskOpenAsProjectOrModelsDialog
{
id: askOpenAsProjectOrModelsDialog
}
Connections
{
target: CuraApplication
onOpenProjectFile:
{
askOpenAsProjectOrModelsDialog.fileUrl = project_file;
askOpenAsProjectOrModelsDialog.show();
}
}
Cura.OpenFilesIncludingProjectsDialog
{
id: openFilesIncludingProjectsDialog
}
}

View File

@ -0,0 +1,11 @@
# Copyright (c) 2021 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher.
from . import LocalFileProvider
def getMetaData():
return {}
def register(app):
return { "file_provider": LocalFileProvider.LocalFileProvider() }

View File

@ -0,0 +1,8 @@
{
"name": "Local File Provider",
"description": "Enables opening files from the local file system.",
"author": "Ultimaker B.V.",
"version": "1.0.0",
"api": "7.4.0",
"i18n-catalog": "cura"
}

View File

@ -619,114 +619,6 @@ UM.MainWindow
onTriggered: base.exitFullscreen()
}
FileDialog
{
id: openDialog;
//: File open dialog title
title: catalog.i18nc("@title:window","Open file(s)")
modality: Qt.WindowModal
selectMultiple: true
nameFilters: UM.MeshFileHandler.supportedReadFileTypes;
folder:
{
//Because several implementations of the file dialog only update the folder when it is explicitly set.
folder = CuraApplication.getDefaultPath("dialog_load_path");
return CuraApplication.getDefaultPath("dialog_load_path");
}
onAccepted:
{
// Because several implementations of the file dialog only update the folder
// when it is explicitly set.
var f = folder;
folder = f;
CuraApplication.setDefaultPath("dialog_load_path", folder);
handleOpenFileUrls(fileUrls);
}
// Yeah... I know... it is a mess to put all those things here.
// There are lots of user interactions in this part of the logic, such as showing a warning dialog here and there,
// etc. This means it will come back and forth from time to time between QML and Python. So, separating the logic
// and view here may require more effort but make things more difficult to understand.
function handleOpenFileUrls(fileUrlList)
{
// look for valid project files
var projectFileUrlList = [];
var hasGcode = false;
var nonGcodeFileList = [];
for (var i in fileUrlList)
{
var endsWithG = /\.g$/;
var endsWithGcode = /\.gcode$/;
if (endsWithG.test(fileUrlList[i]) || endsWithGcode.test(fileUrlList[i]))
{
continue;
}
else if (CuraApplication.checkIsValidProjectFile(fileUrlList[i]))
{
projectFileUrlList.push(fileUrlList[i]);
}
nonGcodeFileList.push(fileUrlList[i]);
}
hasGcode = nonGcodeFileList.length < fileUrlList.length;
// show a warning if selected multiple files together with Gcode
var hasProjectFile = projectFileUrlList.length > 0;
var selectedMultipleFiles = fileUrlList.length > 1;
if (selectedMultipleFiles && hasGcode)
{
infoMultipleFilesWithGcodeDialog.selectedMultipleFiles = selectedMultipleFiles;
infoMultipleFilesWithGcodeDialog.hasProjectFile = hasProjectFile;
infoMultipleFilesWithGcodeDialog.fileUrls = nonGcodeFileList.slice();
infoMultipleFilesWithGcodeDialog.projectFileUrlList = projectFileUrlList.slice();
infoMultipleFilesWithGcodeDialog.open();
}
else
{
handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList);
}
}
function handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList)
{
// we only allow opening one project file
if (selectedMultipleFiles && hasProjectFile)
{
openFilesIncludingProjectsDialog.fileUrls = fileUrlList.slice();
openFilesIncludingProjectsDialog.show();
return;
}
if (hasProjectFile)
{
var projectFile = projectFileUrlList[0];
// check preference
var choice = UM.Preferences.getValue("cura/choice_on_open_project");
if (choice == "open_as_project")
{
openFilesIncludingProjectsDialog.loadProjectFile(projectFile);
}
else if (choice == "open_as_model")
{
openFilesIncludingProjectsDialog.loadModelFiles([projectFile].slice());
}
else // always ask
{
// ask whether to open as project or as models
askOpenAsProjectOrModelsDialog.fileUrl = projectFile;
askOpenAsProjectOrModelsDialog.show();
}
}
else
{
openFilesIncludingProjectsDialog.loadModelFiles(fileUrlList.slice());
}
}
}
MessageDialog
{
id: packageInstallDialog
@ -735,51 +627,12 @@ UM.MainWindow
modality: Qt.ApplicationModal
}
MessageDialog
{
id: infoMultipleFilesWithGcodeDialog
title: catalog.i18nc("@title:window", "Open File(s)")
icon: StandardIcon.Information
standardButtons: StandardButton.Ok
text: catalog.i18nc("@text:window", "We have found one or more G-Code files within the files you have selected. You can only open one G-Code file at a time. If you want to open a G-Code file, please just select only one.")
property var selectedMultipleFiles
property var hasProjectFile
property var fileUrls
property var projectFileUrlList
onAccepted:
{
openDialog.handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrls, projectFileUrlList);
}
}
Connections
{
target: Cura.Actions.open
onTriggered: openDialog.open()
}
OpenFilesIncludingProjectsDialog
{
id: openFilesIncludingProjectsDialog
}
AskOpenAsProjectOrModelsDialog
{
id: askOpenAsProjectOrModelsDialog
}
Connections
{
target: CuraApplication
onOpenProjectFile:
{
askOpenAsProjectOrModelsDialog.fileUrl = project_file;
askOpenAsProjectOrModelsDialog.show();
}
}
Connections
{
target: Cura.Actions.showProfileFolder