Skip to content

Commit

Permalink
Fix opening the Cura window
Browse files Browse the repository at this point in the history
It looks like there is a possible racecondition caused by the presence of qml/RenameDialog.qml inside a resource searchpath.

contributes to #35
  • Loading branch information
fieldOfView committed Apr 9, 2023
1 parent 5982ec6 commit 61cfa88
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 54 deletions.
107 changes: 53 additions & 54 deletions MeshTools.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,23 @@

from typing import Optional, List, Dict

Resources.addSearchPath(
os.path.join(
os.path.abspath(os.path.dirname(__file__)),
"resources"
)
) # Plugin translation file import

catalog = i18nCatalog("meshtools")


class MeshTools(Extension, QObject,):
def __init__(self, parent = None) -> None:
QObject.__init__(self, parent)
Extension.__init__(self)

self._application = CuraApplication.getInstance()
Resources.addSearchPath(
os.path.join(
os.path.abspath(os.path.dirname(__file__)),
"resources"
)
) # Plugin translation file import
self._catalog = i18nCatalog("meshtools")

self._qml_folder = "qml_qt6" if not USE_QT5 else "qml_qt5"

self._qml_folder = "qml" if not USE_QT5 else "qml_qt5"
self._application = CuraApplication.getInstance()

self._application.engineCreatedSignal.connect(self._onEngineCreated)
self._application.fileLoaded.connect(self._onFileLoaded)
Expand All @@ -88,23 +87,23 @@ def __init__(self, parent = None) -> None:
self._preferences.addPreference("meshtools/randomise_location_on_load", False)
self._preferences.addPreference("meshtools/model_unit_factor", 1)

self.addMenuItem(catalog.i18nc("@item:inmenu", "Reload model"), self.reloadMesh)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Rename model..."), self.renameMesh)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Replace models..."), self.replaceMeshes)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Reload model"), self.reloadMesh)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Rename model..."), self.renameMesh)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Replace models..."), self.replaceMeshes)
self.addMenuItem("", lambda: None)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Check models"), self.checkMeshes)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Analyse models"), self.analyseMeshes)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Fix simple holes"), self.fixSimpleHolesForMeshes)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Fix model normals"), self.fixNormalsForMeshes)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Split model into parts"), self.splitMeshes)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Check models"), self.checkMeshes)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Analyse models"), self.analyseMeshes)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Fix simple holes"), self.fixSimpleHolesForMeshes)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Fix model normals"), self.fixNormalsForMeshes)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Split model into parts"), self.splitMeshes)
self.addMenuItem(" ", lambda: None)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Randomise location"), self.randomiseMeshLocation)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Apply transformations to mesh"), self.bakeMeshTransformation)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Reset origin to center of mesh"), self.resetMeshOrigin)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Randomise location"), self.randomiseMeshLocation)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Apply transformations to mesh"), self.bakeMeshTransformation)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Reset origin to center of mesh"), self.resetMeshOrigin)
self.addMenuItem(" ", lambda: None)
self.addMenuItem(catalog.i18nc("@item:inmenu", "Mesh Tools settings..."), self.showSettingsDialog)
self.addMenuItem(self._catalog.i18nc("@item:inmenu", "Mesh Tools settings..."), self.showSettingsDialog)

self._message = Message(title=catalog.i18nc("@info:title", "Mesh Tools"))
self._message = Message(title=self._catalog.i18nc("@info:title", "Mesh Tools"))
self._additional_menu = None # type: Optional[QObject]

def showSettingsDialog(self) -> None:
Expand Down Expand Up @@ -155,7 +154,7 @@ def _onEngineCreated(self) -> None:

if USE_QT5:
context_menu.insertSeparator(0)
context_menu.insertMenu(0, catalog.i18nc("@info:title", "Mesh Tools"))
context_menu.insertMenu(0, self._catalog.i18nc("@info:title", "Mesh Tools"))

# Move additional menu items into context menu
self._additional_menu.moveToContextMenu(context_menu)
Expand Down Expand Up @@ -223,23 +222,23 @@ def checkQueuedNodes(self) -> None:

if self._preferences.getValue("meshtools/check_models_on_load") and not tri_node.is_watertight:
if not file_name:
file_name = catalog.i18nc("@text Print job name", "Untitled")
file_name = self._catalog.i18nc("@text Print job name", "Untitled")
base_name = os.path.basename(file_name)

if file_name in self._mesh_not_watertight_messages:
self._mesh_not_watertight_messages[file_name].hide()

message = Message(title=catalog.i18nc("@info:title", "Mesh Tools"))
body = catalog.i18nc("@info:status", "Model %s is not watertight, and may not print properly.") % base_name
message = Message(title=self._catalog.i18nc("@info:title", "Mesh Tools"))
body = self._catalog.i18nc("@info:status", "Model %s is not watertight, and may not print properly.") % base_name

# XRayView may not be available if the plugin has been disabled
active_view = self._controller.getActiveView()
if active_view and "XRayView" in self._controller.getAllViews() and active_view.getPluginId() != "XRayView":
body += " " + catalog.i18nc("@info:status", "Check X-Ray View and repair the model before printing it.")
message.addAction("X-Ray", catalog.i18nc("@action:button", "Show X-Ray View"), "", "")
body += " " + self._catalog.i18nc("@info:status", "Check X-Ray View and repair the model before printing it.")
message.addAction("X-Ray", self._catalog.i18nc("@action:button", "Show X-Ray View"), "", "")
message.actionTriggered.connect(self._showXRayView)
else:
body += " " +catalog.i18nc("@info:status", "Repair the model before printing it.")
body += " " +self._catalog.i18nc("@info:status", "Repair the model before printing it.")

message.setText(body)
message.show()
Expand Down Expand Up @@ -277,12 +276,12 @@ def _getSelectedNodes(self, force_single = False) -> List[SceneNode]:
if len(selection) == 1:
return selection[:]

self._message.setText(catalog.i18nc("@info:status", "Please select a single model first"))
self._message.setText(self._catalog.i18nc("@info:status", "Please select a single model first"))
else:
if len(selection) >= 1:
return selection[:]

self._message.setText(catalog.i18nc("@info:status", "Please select one or more models first"))
self._message.setText(self._catalog.i18nc("@info:status", "Please select one or more models first"))

self._message.show()
return []
Expand All @@ -300,7 +299,7 @@ def _getAllSelectedNodes(self) -> List[SceneNode]:
if deep_selection:
return deep_selection

self._message.setText(catalog.i18nc("@info:status", "Please select one or more models first"))
self._message.setText(self._catalog.i18nc("@info:status", "Please select one or more models first"))
self._message.show()

return []
Expand All @@ -311,16 +310,16 @@ def checkMeshes(self) -> None:
if not nodes_list:
return

message_body = catalog.i18nc("@info:status", "Check summary:")
message_body = self._catalog.i18nc("@info:status", "Check summary:")
for node in nodes_list:
tri_node = self._toTriMesh(node.getMeshData())
message_body = message_body + "\n - %s" % node.getName()
if tri_node.is_watertight:
message_body = message_body + " " + catalog.i18nc("@info:status", "is watertight")
message_body = message_body + " " + self._catalog.i18nc("@info:status", "is watertight")
else:
message_body = message_body + " " + catalog.i18nc("@info:status", "is not watertight and may not print properly")
message_body = message_body + " " + self._catalog.i18nc("@info:status", "is not watertight and may not print properly")
if tri_node.body_count > 1:
message_body = message_body + " " + catalog.i18nc("@info:status", "and consists of {body_count} submeshes").format(body_count = tri_node.body_count)
message_body = message_body + " " + self._catalog.i18nc("@info:status", "and consists of {body_count} submeshes").format(body_count = tri_node.body_count)

self._message.setText(message_body)
self._message.show()
Expand All @@ -331,13 +330,13 @@ def analyseMeshes(self) -> None:
if not nodes_list:
return

message_body = catalog.i18nc("@info:status", "Analysis summary:")
message_body = self._catalog.i18nc("@info:status", "Analysis summary:")
for node in nodes_list:
tri_node = self._toTriMesh(node.getMeshDataTransformed())
message_body = message_body + "\n - %s:" % node.getName()
message_body += "\n\t" + catalog.i18nc("@info:status", "%d vertices, %d faces") % (len(tri_node.vertices), len(tri_node.faces))
message_body += "\n\t" + self._catalog.i18nc("@info:status", "%d vertices, %d faces") % (len(tri_node.vertices), len(tri_node.faces))
if tri_node.is_watertight:
message_body += "\n\t" + catalog.i18nc("@info:status", "area: %d mm2, volume: %d mm3") % (tri_node.area, tri_node.volume)
message_body += "\n\t" + self._catalog.i18nc("@info:status", "area: %d mm2, volume: %d mm3") % (tri_node.area, tri_node.volume)

self._message.setText(message_body)
self._message.show()
Expand All @@ -353,7 +352,7 @@ def fixSimpleHolesForMeshes(self) -> None:
success = tri_node.fill_holes()
self._replaceSceneNode(node, [tri_node])
if not success:
self._message.setText(catalog.i18nc(
self._message.setText(self._catalog.i18nc(
"@info:status",
"The mesh needs more extensive repair to become watertight"
))
Expand All @@ -376,15 +375,15 @@ def splitMeshes(self) -> None:
if not nodes_list:
return

message_body = catalog.i18nc("@info:status", "Split result:")
message_body = self._catalog.i18nc("@info:status", "Split result:")
for node in nodes_list:
message_body = message_body + "\n - %s" % node.getName()
tri_node = self._toTriMesh(node.getMeshData())
if tri_node.body_count > 1:
self._replaceSceneNode(node, tri_node.split(only_watertight=False))
message_body = message_body + " " + catalog.i18nc("@info:status", "was split in %d submeshes") % tri_node.body_count
message_body = message_body + " " + self._catalog.i18nc("@info:status", "was split in %d submeshes") % tri_node.body_count
else:
message_body = message_body + " " + catalog.i18nc("@info:status", "could not be split into submeshes")
message_body = message_body + " " + self._catalog.i18nc("@info:status", "could not be split into submeshes")

self._message.setText(message_body)
self._message.show()
Expand All @@ -398,7 +397,7 @@ def replaceMeshes(self) -> None:
for node in self._node_queue:
mesh_data = node.getMeshData()
if not mesh_data:
self._message.setText(catalog.i18nc("@info:status", "Replacing a group is not supported"))
self._message.setText(self._catalog.i18nc("@info:status", "Replacing a group is not supported"))
self._message.show()
self._node_queue = [] #type: List[SceneNode]
return
Expand All @@ -419,12 +418,12 @@ def replaceMeshes(self) -> None:

file_name, _ = QFileDialog.getOpenFileName(
parent=None,
caption=catalog.i18nc("@title:window", "Select Replacement Mesh File"),
caption=self._catalog.i18nc("@title:window", "Select Replacement Mesh File"),
directory=directory, options=options, filter=filter_types
)
else:
dialog = QFileDialog()
dialog.setWindowTitle(catalog.i18nc("@title:window", "Select Replacement Mesh File"))
dialog.setWindowTitle(self._catalog.i18nc("@title:window", "Select Replacement Mesh File"))
dialog.setDirectory(directory)
dialog.setNameFilters(self._application.getMeshFileHandler().supportedReadFileTypes)
dialog.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen)
Expand Down Expand Up @@ -473,14 +472,14 @@ def reloadMesh(self) -> None:

mesh_data = self._node_queue[0].getMeshData()
if not mesh_data:
self._message.setText(catalog.i18nc("@info:status", "Reloading a group is not supported"))
self._message.setText(self._catalog.i18nc("@info:status", "Reloading a group is not supported"))
self._message.show()
self._node_queue = [] #type: List[SceneNode]
return

file_name = mesh_data.getFileName()
if not file_name:
self._message.setText(catalog.i18nc("@info:status", "No link to the original file was found"))
self._message.setText(self._catalog.i18nc("@info:status", "No link to the original file was found"))
self._message.show()
self._node_queue = [] #type: List[SceneNode]
return
Expand All @@ -492,14 +491,14 @@ def reloadMesh(self) -> None:
def _readMeshFinished(self, job) -> None:
job_result = job.getResult()
if len(job_result) == 0:
self._message.setText(catalog.i18nc("@info:status", "Failed to load mesh"))
self._message.setText(self._catalog.i18nc("@info:status", "Failed to load mesh"))
self._message.show()
self._node_queue = [] #type: List[SceneNode]
return

mesh_data = job_result[0].getMeshData()
if not mesh_data:
self._message.setText(catalog.i18nc("@info:status", "Replacing meshes with a group of meshes is not supported"))
self._message.setText(self._catalog.i18nc("@info:status", "Replacing meshes with a group of meshes is not supported"))
self._message.show()
self._node_queue = [] #type: List[SceneNode]
return
Expand All @@ -508,7 +507,7 @@ def _readMeshFinished(self, job) -> None:
if file_name:
mesh_name = os.path.basename(file_name)
else:
mesh_name = catalog.i18nc("@text Print job name", "Untitled")
mesh_name = self._catalog.i18nc("@text Print job name", "Untitled")

has_merged_nodes = False

Expand Down Expand Up @@ -572,7 +571,7 @@ def bakeMeshTransformation(self) -> None:
file_name = ""
mesh_name = os.path.basename(file_name)
if not mesh_name:
mesh_name = catalog.i18nc("@text Print job name", "Untitled")
mesh_name = self._catalog.i18nc("@text Print job name", "Untitled")

local_transformation = node.getLocalTransformation()
position = local_transformation.getTranslation()
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 61cfa88

Please sign in to comment.