Revert making the open file dialog a separate LocalFileProvider plugin

This reverts commits 00de7497a4c2986cf8fd13be8f598a0f615f3d63 to 5f6b3b52c1848416c98f7d276fe02f08d067f675

CURA-7868
This commit is contained in:
Kostas Karmas 2021-01-07 16:35:40 +01:00
parent 606ec587fe
commit 96c4d66029
9 changed files with 182 additions and 244 deletions

View File

@ -1,47 +0,0 @@
# 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

@ -1,171 +0,0 @@
// 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

@ -1,11 +0,0 @@
# 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

@ -1,8 +0,0 @@
{
"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

@ -1,4 +1,4 @@
// Copyright (c) 2021 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.7 import QtQuick 2.7
@ -96,7 +96,7 @@ Item
id: openFileButton id: openFileButton
height: UM.Theme.getSize("stage_menu").height height: UM.Theme.getSize("stage_menu").height
width: UM.Theme.getSize("stage_menu").height width: UM.Theme.getSize("stage_menu").height
onClicked: CuraApplication.getFileProviderModel().triggerFirst() onClicked: Cura.Actions.open.trigger()
hoverEnabled: true hoverEnabled: true
contentItem: Item contentItem: Item

View File

@ -1,4 +1,4 @@
// Copyright (c) 2021 Ultimaker B.V. // Copyright (c) 2018 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
pragma Singleton pragma Singleton
@ -12,6 +12,7 @@ import Cura 1.0 as Cura
Item Item
{ {
property alias newProject: newProjectAction; property alias newProject: newProjectAction;
property alias open: openAction;
property alias quit: quitAction; property alias quit: quitAction;
property alias undo: undoAction; property alias undo: undoAction;
@ -412,6 +413,14 @@ Item
onTriggered: CuraApplication.resetAll(); onTriggered: CuraApplication.resetAll();
} }
Action
{
id: openAction;
text: catalog.i18nc("@action:inmenu menubar:file","&Open File(s)...");
iconName: "document-open";
shortcut: StandardKey.Open;
}
Action Action
{ {
id: newProjectAction id: newProjectAction

View File

@ -619,6 +619,114 @@ UM.MainWindow
onTriggered: base.exitFullscreen() 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 MessageDialog
{ {
id: packageInstallDialog id: packageInstallDialog
@ -627,6 +735,51 @@ UM.MainWindow
modality: Qt.ApplicationModal 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 Connections
{ {
target: Cura.Actions.showProfileFolder target: Cura.Actions.showProfileFolder

View File

@ -22,7 +22,7 @@ Menu
MenuItem MenuItem
{ {
id: openMenu id: openMenu
onTriggered: CuraApplication.getFileProviderModel().triggerFirst() action: Cura.Actions.open
visible: (base.fileProviderModel.count == 1) visible: (base.fileProviderModel.count == 1)
} }

View File

@ -1,4 +1,4 @@
// Copyright (c) 2021 Ultimaker B.V. // Copyright (c) 2020 Ultimaker B.V.
// Cura is released under the terms of the LGPLv3 or higher. // Cura is released under the terms of the LGPLv3 or higher.
import QtQuick 2.2 import QtQuick 2.2
@ -21,8 +21,21 @@ Menu
model: CuraApplication.getFileProviderModel() model: CuraApplication.getFileProviderModel()
MenuItem MenuItem
{ {
text: model.displayText text:
onTriggered: CuraApplication.getFileProviderModel().trigger(model.name) {
return model.displayText;
}
onTriggered:
{
if (model.index == 0) // The 0th element is the "From Disk" option, which should activate the open local file dialog
{
Cura.Actions.open.trigger()
}
else
{
CuraApplication.getFileProviderModel().trigger(model.name);
}
}
shortcut: model.shortcut shortcut: model.shortcut
} }
onObjectAdded: openFilesMenu.insertItem(index, object) onObjectAdded: openFilesMenu.insertItem(index, object)