VersionUpgrade462to47.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. # Copyright (c) 2020 Ultimaker B.V.
  2. # Cura is released under the terms of the LGPLv3 or higher.
  3. import configparser
  4. from typing import Tuple, List, Dict, Set
  5. import io
  6. from UM.Util import parseBool
  7. from UM.VersionUpgrade import VersionUpgrade
  8. # Renamed definition files
  9. _RENAMED_DEFINITION_DICT = {
  10. "dagoma_discoeasy200": "dagoma_discoeasy200_bicolor",
  11. } # type: Dict[str, str]
  12. _removed_settings = {
  13. "spaghetti_infill_enabled",
  14. "spaghetti_infill_stepped",
  15. "spaghetti_max_infill_angle",
  16. "spaghetti_max_height",
  17. "spaghetti_inset",
  18. "spaghetti_flow",
  19. "spaghetti_infill_extra_volume",
  20. "support_tree_enable"
  21. } # type: Set[str]
  22. class VersionUpgrade462to47(VersionUpgrade):
  23. def upgradePreferences(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
  24. """
  25. Upgrades preferences to have the new version number.
  26. :param serialized: The original contents of the preferences file.
  27. :param filename: The file name of the preferences file.
  28. :return: A list of new file names, and a list of the new contents for
  29. those files.
  30. """
  31. parser = configparser.ConfigParser(interpolation = None)
  32. parser.read_string(serialized)
  33. # Update version number.
  34. parser["metadata"]["setting_version"] = "15"
  35. if "general" in parser and "visible_settings" in parser["general"]:
  36. settings = set(parser["general"]["visible_settings"].split(";"))
  37. # add support_structure to the visible settings list if necessary
  38. if "support_tree_enable" in parser["general"]["visible_settings"]:
  39. settings.add("support_structure")
  40. # Remove deleted settings from the visible settings list.
  41. settings.difference_update(_removed_settings)
  42. # serialize
  43. parser["general"]["visible_settings"] = ";".join(settings)
  44. result = io.StringIO()
  45. parser.write(result)
  46. return [filename], [result.getvalue()]
  47. def upgradeInstanceContainer(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
  48. """
  49. Upgrades instance containers to have the new version number.
  50. This changes the maximum deviation setting if that setting was present
  51. in the profile.
  52. :param serialized: The original contents of the instance container.
  53. :param filename: The original file name of the instance container.
  54. :return: A list of new file names, and a list of the new contents for
  55. those files.
  56. """
  57. parser = configparser.ConfigParser(interpolation = None, comment_prefixes = ())
  58. parser.read_string(serialized)
  59. # Update version number.
  60. parser["metadata"]["setting_version"] = "15"
  61. if "values" in parser:
  62. # Maximum Deviation's effect was corrected. Previously the deviation
  63. # ended up being only half of what the user had entered. This was
  64. # fixed in Cura 4.7 so there we need to halve the deviation that the
  65. # user had entered.
  66. #
  67. # This got accidentally merged in Cura 4.6.0. In 4.6.2 we removed
  68. # that. In 4.7 it's not unmerged, so there we need to revert all
  69. # that again.
  70. if "meshfix_maximum_deviation" in parser["values"]:
  71. maximum_deviation = parser["values"]["meshfix_maximum_deviation"]
  72. if maximum_deviation.startswith("="):
  73. maximum_deviation = maximum_deviation[1:]
  74. maximum_deviation = "=(" + maximum_deviation + ") / 2"
  75. parser["values"]["meshfix_maximum_deviation"] = maximum_deviation
  76. # Ironing inset is now based on the flow-compensated line width to make the setting have a more logical UX.
  77. # Adjust so that the actual print result remains the same.
  78. if "ironing_inset" in parser["values"]:
  79. ironing_inset = parser["values"]["ironing_inset"]
  80. if ironing_inset.startswith("="):
  81. ironing_inset = ironing_inset[1:]
  82. if "ironing_pattern" in parser["values"] and parser["values"]["ironing_pattern"] == "concentric":
  83. correction = " + ironing_line_spacing - skin_line_width * (1.0 + ironing_flow / 100) / 2"
  84. else: # If ironing_pattern doesn't exist, it means the default (zigzag) is selected
  85. correction = " + skin_line_width * (1.0 - ironing_flow / 100) / 2"
  86. ironing_inset = "=(" + ironing_inset + ")" + correction
  87. parser["values"]["ironing_inset"] = ironing_inset
  88. # Set support_structure if necessary
  89. if "support_tree_enable" in parser["values"]:
  90. if parseBool(parser["values"]["support_tree_enable"]):
  91. parser["values"]["support_structure"] = "tree"
  92. parser["values"]["support_enable"] = "True"
  93. for removed in set(parser["values"].keys()).intersection(_removed_settings):
  94. del parser["values"][removed]
  95. # Check renamed definitions
  96. if "definition" in parser["general"] and parser["general"]["definition"] in _RENAMED_DEFINITION_DICT:
  97. parser["general"]["definition"] = _RENAMED_DEFINITION_DICT[parser["general"]["definition"]]
  98. result = io.StringIO()
  99. parser.write(result)
  100. return [filename], [result.getvalue()]
  101. def upgradeStack(self, serialized: str, filename: str) -> Tuple[List[str], List[str]]:
  102. """
  103. Upgrades stacks to have the new version number.
  104. :param serialized: The original contents of the stack.
  105. :param filename: The original file name of the stack.
  106. :return: A list of new file names, and a list of the new contents for
  107. those files.
  108. """
  109. parser = configparser.ConfigParser(interpolation = None)
  110. parser.read_string(serialized)
  111. # Update version number.
  112. if "metadata" not in parser:
  113. parser["metadata"] = {}
  114. parser["metadata"]["setting_version"] = "15"
  115. # Update Pause at Height script parameters if present.
  116. if "post_processing_scripts" in parser["metadata"]:
  117. new_scripts_entries = []
  118. for script_str in parser["metadata"]["post_processing_scripts"].split("\n"):
  119. if not script_str:
  120. continue
  121. script_str = script_str.replace(r"\\\n", "\n").replace(r"\\\\", "\\\\") # Unescape escape sequences.
  122. script_parser = configparser.ConfigParser(interpolation=None)
  123. script_parser.optionxform = str # type: ignore # Don't transform the setting keys as they are case-sensitive.
  124. script_parser.read_string(script_str)
  125. # Unify all Pause at Height
  126. script_id = script_parser.sections()[0]
  127. if script_id in ["BQ_PauseAtHeight", "PauseAtHeightRepRapFirmwareDuet", "PauseAtHeightforRepetier"]:
  128. script_settings = script_parser.items(script_id)
  129. script_settings.append(("pause_method", {
  130. "BQ_PauseAtHeight": "bq",
  131. "PauseAtHeightforRepetier": "repetier",
  132. "PauseAtHeightRepRapFirmwareDuet": "reprap"
  133. }[script_id]))
  134. # Since we cannot rename a section, we remove the original section and create a new section with the new script id.
  135. script_parser.remove_section(script_id)
  136. script_id = "PauseAtHeight"
  137. script_parser.add_section(script_id)
  138. for setting_tuple in script_settings:
  139. script_parser.set(script_id, setting_tuple[0], setting_tuple[1])
  140. # Update redo_layers to redo_layer
  141. if "PauseAtHeight" in script_parser:
  142. if "redo_layers" in script_parser["PauseAtHeight"]:
  143. script_parser["PauseAtHeight"]["redo_layer"] = str(int(script_parser["PauseAtHeight"]["redo_layers"]) > 0)
  144. del script_parser["PauseAtHeight"]["redo_layers"] # Has been renamed to without the S.
  145. # Migrate DisplayCompleteOnLCD to DisplayProgressOnLCD
  146. if script_id == "DisplayRemainingTimeOnLCD":
  147. was_enabled = parseBool(script_parser[script_id]["TurnOn"]) if "TurnOn" in script_parser[script_id] else False
  148. script_parser.remove_section(script_id)
  149. script_id = "DisplayProgressOnLCD"
  150. script_parser.add_section(script_id)
  151. if was_enabled:
  152. script_parser.set(script_id, "time_remaining", "True")
  153. script_io = io.StringIO()
  154. script_parser.write(script_io)
  155. script_str = script_io.getvalue()
  156. script_str = script_str.replace("\\\\", r"\\\\").replace("\n", r"\\\n") # Escape newlines because configparser sees those as section delimiters.
  157. new_scripts_entries.append(script_str)
  158. parser["metadata"]["post_processing_scripts"] = "\n".join(new_scripts_entries)
  159. # check renamed definition
  160. if parser.has_option("containers", "7") and parser["containers"]["7"] in _RENAMED_DEFINITION_DICT:
  161. parser["containers"]["7"] = _RENAMED_DEFINITION_DICT[parser["containers"]["7"]]
  162. result = io.StringIO()
  163. parser.write(result)
  164. return [filename], [result.getvalue()]