mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-14 04:15:53 +08:00
Merge branch 'master' of https://github.com/Ultimaker/Cura
This commit is contained in:
commit
4e507a203a
@ -43,6 +43,8 @@ if(NOT APPLE AND NOT WIN32)
|
||||
DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages/cura)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/cura.desktop
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/cura.appdata.xml
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/appdata)
|
||||
install(FILES cura.sharedmimeinfo
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages/
|
||||
RENAME cura.xml )
|
||||
|
31
cura.appdata.xml
Normal file
31
cura.appdata.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright 2016 Richard Hughes <richard@hughsie.com> -->
|
||||
<component type="desktop">
|
||||
<id>cura.desktop</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>AGPL-3.0 and CC-BY-SA-4.0</project_license>
|
||||
<name>Cura</name>
|
||||
<summary>The world's most advanced 3d printer software</summary>
|
||||
<description>
|
||||
<p>
|
||||
Cura creates a seamless integration between hardware, software and
|
||||
materials for the best 3D printing experience around.
|
||||
Cura supports the 3MF, OBJ and STL file formats and is available on
|
||||
Windows, Mac and Linux.
|
||||
</p>
|
||||
<ul>
|
||||
<li>Novices can start printing right away</li>
|
||||
<li>Experts are able to customize 200 settings to achieve the best results</li>
|
||||
<li>Optimized profiles for Ultimaker materials</li>
|
||||
<li>Supported by a global network of Ultimaker certified service partners</li>
|
||||
<li>Print multiple objects at once with different settings for each object</li>
|
||||
<li>Cura supports STL, 3MF and OBJ file formats</li>
|
||||
<li>Open source and completely free</li>
|
||||
</ul>
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot type="default" width="1280" height="720">http://software.ultimaker.com/Cura.png</screenshot>
|
||||
</screenshots>
|
||||
<url type="homepage">https://ultimaker.com/en/products/cura-software</url>
|
||||
<translation type="gettext">Cura</translation>
|
||||
</component>
|
@ -49,11 +49,44 @@ from PyQt5.QtGui import QColor, QIcon
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
import sys
|
||||
import os.path
|
||||
import numpy
|
||||
import copy
|
||||
import urllib
|
||||
import os
|
||||
import time
|
||||
|
||||
CONFIG_LOCK_FILENAME = "cura.lock"
|
||||
|
||||
## Contextmanager to create a lock file and remove it afterwards.
|
||||
@contextmanager
|
||||
def lockFile(filename):
|
||||
try:
|
||||
with open(filename, 'w') as lock_file:
|
||||
lock_file.write("Lock file - Cura is currently writing")
|
||||
except:
|
||||
Logger.log("e", "Could not create lock file [%s]" % filename)
|
||||
yield
|
||||
try:
|
||||
if os.path.exists(filename):
|
||||
os.remove(filename)
|
||||
except:
|
||||
Logger.log("e", "Could not delete lock file [%s]" % filename)
|
||||
|
||||
|
||||
## Wait for a lock file to disappear
|
||||
# the maximum allowable age is settable; if the file is too old, it will be ignored too
|
||||
def waitFileDisappear(filename, max_age_seconds=10, msg=""):
|
||||
now = time.time()
|
||||
while os.path.exists(filename) and now < os.path.getmtime(filename) + max_age_seconds and now > os.path.getmtime(filename):
|
||||
if msg:
|
||||
Logger.log("d", msg)
|
||||
time.sleep(1)
|
||||
now = time.time()
|
||||
|
||||
|
||||
numpy.seterr(all="ignore")
|
||||
|
||||
@ -201,6 +234,9 @@ class CuraApplication(QtApplication):
|
||||
empty_quality_changes_container.addMetaDataEntry("type", "quality_changes")
|
||||
ContainerRegistry.getInstance().addContainer(empty_quality_changes_container)
|
||||
|
||||
# Set the filename to create if cura is writing in the config dir.
|
||||
self._config_lock_filename = os.path.join(Resources.getConfigStoragePath(), CONFIG_LOCK_FILENAME)
|
||||
self.waitConfigLockFile()
|
||||
ContainerRegistry.getInstance().load()
|
||||
|
||||
Preferences.getInstance().addPreference("cura/active_mode", "simple")
|
||||
@ -281,6 +317,12 @@ class CuraApplication(QtApplication):
|
||||
|
||||
self._recent_files.append(QUrl.fromLocalFile(f))
|
||||
|
||||
## Lock file check: if (another) Cura is writing in the Config dir.
|
||||
# one may not be able to read a valid set of files while writing. Not entirely fool-proof,
|
||||
# but works when you start Cura shortly after shutting down.
|
||||
def waitConfigLockFile(self):
|
||||
waitFileDisappear(self._config_lock_filename, max_age_seconds=10, msg="Waiting for Cura to finish writing in the config dir...")
|
||||
|
||||
def _onEngineCreated(self):
|
||||
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
||||
|
||||
@ -308,38 +350,43 @@ class CuraApplication(QtApplication):
|
||||
if not self._started: # Do not do saving during application start
|
||||
return
|
||||
|
||||
for instance in ContainerRegistry.getInstance().findInstanceContainers():
|
||||
if not instance.isDirty():
|
||||
continue
|
||||
self.waitConfigLockFile()
|
||||
|
||||
try:
|
||||
data = instance.serialize()
|
||||
except NotImplementedError:
|
||||
continue
|
||||
except Exception:
|
||||
Logger.logException("e", "An exception occurred when serializing container %s", instance.getId())
|
||||
continue
|
||||
# When starting Cura, we check for the lockFile which is created and deleted here
|
||||
with lockFile(self._config_lock_filename):
|
||||
|
||||
mime_type = ContainerRegistry.getMimeTypeForContainer(type(instance))
|
||||
file_name = urllib.parse.quote_plus(instance.getId()) + "." + mime_type.preferredSuffix
|
||||
instance_type = instance.getMetaDataEntry("type")
|
||||
path = None
|
||||
if instance_type == "material":
|
||||
path = Resources.getStoragePath(self.ResourceTypes.MaterialInstanceContainer, file_name)
|
||||
elif instance_type == "quality" or instance_type == "quality_changes":
|
||||
path = Resources.getStoragePath(self.ResourceTypes.QualityInstanceContainer, file_name)
|
||||
elif instance_type == "user":
|
||||
path = Resources.getStoragePath(self.ResourceTypes.UserInstanceContainer, file_name)
|
||||
elif instance_type == "variant":
|
||||
path = Resources.getStoragePath(self.ResourceTypes.VariantInstanceContainer, file_name)
|
||||
for instance in ContainerRegistry.getInstance().findInstanceContainers():
|
||||
if not instance.isDirty():
|
||||
continue
|
||||
|
||||
if path:
|
||||
instance.setPath(path)
|
||||
with SaveFile(path, "wt", -1, "utf-8") as f:
|
||||
f.write(data)
|
||||
try:
|
||||
data = instance.serialize()
|
||||
except NotImplementedError:
|
||||
continue
|
||||
except Exception:
|
||||
Logger.logException("e", "An exception occurred when serializing container %s", instance.getId())
|
||||
continue
|
||||
|
||||
for stack in ContainerRegistry.getInstance().findContainerStacks():
|
||||
self.saveStack(stack)
|
||||
mime_type = ContainerRegistry.getMimeTypeForContainer(type(instance))
|
||||
file_name = urllib.parse.quote_plus(instance.getId()) + "." + mime_type.preferredSuffix
|
||||
instance_type = instance.getMetaDataEntry("type")
|
||||
path = None
|
||||
if instance_type == "material":
|
||||
path = Resources.getStoragePath(self.ResourceTypes.MaterialInstanceContainer, file_name)
|
||||
elif instance_type == "quality" or instance_type == "quality_changes":
|
||||
path = Resources.getStoragePath(self.ResourceTypes.QualityInstanceContainer, file_name)
|
||||
elif instance_type == "user":
|
||||
path = Resources.getStoragePath(self.ResourceTypes.UserInstanceContainer, file_name)
|
||||
elif instance_type == "variant":
|
||||
path = Resources.getStoragePath(self.ResourceTypes.VariantInstanceContainer, file_name)
|
||||
|
||||
if path:
|
||||
instance.setPath(path)
|
||||
with SaveFile(path, "wt", -1, "utf-8") as f:
|
||||
f.write(data)
|
||||
|
||||
for stack in ContainerRegistry.getInstance().findContainerStacks():
|
||||
self.saveStack(stack)
|
||||
|
||||
def saveStack(self, stack):
|
||||
if not stack.isDirty():
|
||||
|
@ -20,6 +20,6 @@ Generic Nylon profile. Serves as an example file, data in this file is not corre
|
||||
<settings>
|
||||
<setting key="print temperature">250</setting>
|
||||
<setting key="heated bed temperature">60</setting>
|
||||
<setting key="standby temperature">100</setting>
|
||||
<setting key="standby temperature">175</setting>
|
||||
</settings>
|
||||
</fdmmaterial>
|
||||
|
@ -20,6 +20,6 @@ Generic Nylon profile. Serves as an example file, data in this file is not corre
|
||||
<settings>
|
||||
<setting key="print temperature">250</setting>
|
||||
<setting key="heated bed temperature">60</setting>
|
||||
<setting key="standby temperature">100</setting>
|
||||
<setting key="standby temperature">175</setting>
|
||||
</settings>
|
||||
</fdmmaterial>
|
||||
|
Loading…
x
Reference in New Issue
Block a user