Merge pull request #3218 from Ultimaker/CURA-3710_setting_visibility_preset

CURA-3710 Add preset setting visibility files
This commit is contained in:
Ian Paschal 2018-02-05 09:51:52 +01:00 committed by GitHub
commit f627c97a92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 940 additions and 56 deletions

View File

@ -1,6 +1,7 @@
# Copyright (c) 2017 Ultimaker B.V. # Copyright (c) 2018 Ultimaker B.V.
# Copyright (c) 2017 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.
#Type hinting.
from typing import Dict
from PyQt5.QtNetwork import QLocalServer from PyQt5.QtNetwork import QLocalServer
from PyQt5.QtNetwork import QLocalSocket from PyQt5.QtNetwork import QLocalSocket
@ -87,6 +88,7 @@ from PyQt5.QtGui import QColor, QIcon
from PyQt5.QtWidgets import QMessageBox from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType from PyQt5.QtQml import qmlRegisterUncreatableType, qmlRegisterSingletonType, qmlRegisterType
from configparser import ConfigParser
import sys import sys
import os.path import os.path
import numpy import numpy
@ -95,6 +97,7 @@ import os
import argparse import argparse
import json import json
numpy.seterr(all="ignore") numpy.seterr(all="ignore")
MYPY = False MYPY = False
@ -348,57 +351,19 @@ class CuraApplication(QtApplication):
preferences.setDefault("local_file/last_used_type", "text/x-gcode") preferences.setDefault("local_file/last_used_type", "text/x-gcode")
preferences.setDefault("general/visible_settings", """ setting_visibily_preset_names = self.getVisibilitySettingPresetTypes()
machine_settings preferences.setDefault("general/visible_settings_preset", setting_visibily_preset_names)
resolution
layer_height preset_setting_visibility_choice = Preferences.getInstance().getValue("general/preset_setting_visibility_choice")
shell
wall_thickness default_preset_visibility_group_name = "Basic"
top_bottom_thickness if preset_setting_visibility_choice == "" or preset_setting_visibility_choice is None:
z_seam_x if preset_setting_visibility_choice not in setting_visibily_preset_names:
z_seam_y preset_setting_visibility_choice = default_preset_visibility_group_name
infill
infill_sparse_density visible_settings = self.getVisibilitySettingPreset(settings_preset_name = preset_setting_visibility_choice)
gradual_infill_steps preferences.setDefault("general/visible_settings", visible_settings)
material preferences.setDefault("general/preset_setting_visibility_choice", preset_setting_visibility_choice)
material_print_temperature
material_bed_temperature
material_diameter
material_flow
retraction_enable
speed
speed_print
speed_travel
acceleration_print
acceleration_travel
jerk_print
jerk_travel
travel
cooling
cool_fan_enabled
support
support_enable
support_extruder_nr
support_type
platform_adhesion
adhesion_type
adhesion_extruder_nr
brim_width
raft_airgap
layer_0_z_overlap
raft_surface_layers
dual
prime_tower_enable
prime_tower_size
prime_tower_position_x
prime_tower_position_y
meshfix
blackmagic
print_sequence
infill_mesh
cutting_mesh
experimental
""".replace("\n", ";").replace(" ", ""))
self.applicationShuttingDown.connect(self.saveSettings) self.applicationShuttingDown.connect(self.saveSettings)
self.engineCreatedSignal.connect(self._onEngineCreated) self.engineCreatedSignal.connect(self._onEngineCreated)
@ -410,6 +375,93 @@ class CuraApplication(QtApplication):
self.getCuraSceneController().setActiveBuildPlate(0) # Initialize self.getCuraSceneController().setActiveBuildPlate(0) # Initialize
@pyqtSlot(str, result = str)
def getVisibilitySettingPreset(self, settings_preset_name) -> str:
result = self._loadPresetSettingVisibilityGroup(settings_preset_name)
formatted_preset_settings = self._serializePresetSettingVisibilityData(result)
return formatted_preset_settings
## Serialise the given preset setting visibitlity group dictionary into a string which is concatenated by ";"
#
def _serializePresetSettingVisibilityData(self, settings_data: dict) -> str:
result_string = ""
for key in settings_data:
result_string += key + ";"
for value in settings_data[key]:
result_string += value + ";"
return result_string
## Load the preset setting visibility group with the given name
#
def _loadPresetSettingVisibilityGroup(self, visibility_preset_name) -> Dict[str, str]:
preset_dir = Resources.getPath(Resources.PresetSettingVisibilityGroups)
result = {}
right_preset_found = False
for item in os.listdir(preset_dir):
file_path = os.path.join(preset_dir, item)
if not os.path.isfile(file_path):
continue
parser = ConfigParser(allow_no_value = True) # accept options without any value,
try:
parser.read([file_path])
if not parser.has_option("general", "name"):
continue
if parser["general"]["name"] == visibility_preset_name:
right_preset_found = True
for section in parser.sections():
if section == 'general':
continue
else:
section_settings = []
for option in parser[section].keys():
section_settings.append(option)
result[section] = section_settings
if right_preset_found:
break
except Exception as e:
Logger.log("e", "Failed to load setting visibility preset %s: %s", file_path, str(e))
return result
## Check visibility setting preset folder and returns available types
#
def getVisibilitySettingPresetTypes(self):
preset_dir = Resources.getPath(Resources.PresetSettingVisibilityGroups)
result = {}
for item in os.listdir(preset_dir):
file_path = os.path.join(preset_dir, item)
if not os.path.isfile(file_path):
continue
parser = ConfigParser(allow_no_value=True) # accept options without any value,
try:
parser.read([file_path])
if not parser.has_option("general", "name") and not parser.has_option("general", "weight"):
continue
result[parser["general"]["weight"]] = parser["general"]["name"]
except Exception as e:
Logger.log("e", "Failed to load setting preset %s: %s", file_path, str(e))
return result
def _onEngineCreated(self): def _onEngineCreated(self):
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider()) self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())

View File

@ -453,6 +453,7 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
Logger.log("w", "Workspace did not contain visible settings. Leaving visibility unchanged") Logger.log("w", "Workspace did not contain visible settings. Leaving visibility unchanged")
else: else:
global_preferences.setValue("general/visible_settings", visible_settings) global_preferences.setValue("general/visible_settings", visible_settings)
global_preferences.setValue("general/preset_setting_visibility_choice", "Custom")
categories_expanded = temp_preferences.getValue("cura/categories_expanded") categories_expanded = temp_preferences.getValue("cura/categories_expanded")
if categories_expanded is None: if categories_expanded is None:

View File

@ -0,0 +1,254 @@
[general]
name = Advanced
weight = 2
[machine_settings]
[resolution]
layer_height
layer_height_0
line_width
[shell]
wall_extruder_nr
wall_thickness
wall_0_wipe_dist
roofing_extruder_nr
roofing_layer_count
top_bottom_extruder_nr
top_bottom_thickness
top_bottom_pattern
top_bottom_pattern_0
skin_angles
wall_0_inset
optimize_wall_printing_order
outer_inset_first
alternate_extra_perimeter
travel_compensate_overlapping_walls_enabled
fill_perimeter_gaps
filter_out_tiny_gaps
fill_outline_gaps
xy_offset
xy_offset_layer_0
z_seam_type
z_seam_x
z_seam_y
z_seam_corner
z_seam_relative
skin_no_small_gaps_heuristic
skin_outline_count
ironing_enabled
ironing_only_highest_layer
ironing_pattern
ironing_line_spacing
ironing_flow
ironing_inset
speed_ironing
acceleration_ironing
jerk_ironing
[infill]
infill_extruder_nr
infill_sparse_density
infill_pattern
zig_zaggify_infill
infill_angles
infill_offset_x
infill_offset_y
sub_div_rad_add
infill_overlap
skin_overlap
infill_wipe_dist
infill_sparse_thickness
gradual_infill_steps
gradual_infill_step_height
infill_before_walls
min_infill_area
skin_preshrink
expand_skins_expand_distance
max_skin_angle_for_expansion
[material]
default_material_print_temperature
material_print_temperature
material_print_temperature_layer_0
material_initial_print_temperature
material_final_print_temperature
material_extrusion_cool_down_speed
default_material_bed_temperature
material_bed_temperature
material_bed_temperature_layer_0
material_diameter
material_adhesion_tendency
material_surface_energy
material_flow
retraction_enable
retract_at_layer_change
retraction_amount
retraction_speed
retraction_extra_prime_amount
retraction_min_travel
retraction_count_max
retraction_extrusion_window
material_standby_temperature
switch_extruder_retraction_amount
switch_extruder_retraction_speeds
[speed]
speed_print
speed_travel
speed_layer_0
skirt_brim_speed
max_feedrate_z_override
speed_slowdown_layers
speed_equalize_flow_enabled
speed_equalize_flow_max
acceleration_enabled
acceleration_print
acceleration_travel
acceleration_layer_0
acceleration_skirt_brim
jerk_enabled
jerk_print
jerk_travel
jerk_layer_0
jerk_skirt_brim
[travel]
retraction_combing
travel_retract_before_outer_wall
travel_avoid_other_parts
travel_avoid_distance
start_layers_at_same_position
layer_start_x
layer_start_y
retraction_hop_enabled
retraction_hop_only_when_collides
retraction_hop
retraction_hop_after_extruder_switch
[cooling]
cool_fan_enabled
cool_fan_speed
cool_min_layer_time_fan_speed_max
cool_fan_speed_0
cool_fan_full_at_height
cool_min_layer_time
cool_min_speed
cool_lift_head
[support]
support_enable
support_extruder_nr
support_type
support_angle
support_pattern
support_connect_zigzags
support_infill_rate
support_z_distance
support_xy_distance
support_xy_overrides_z
support_xy_distance_overhang
support_bottom_stair_step_height
support_bottom_stair_step_width
support_join_distance
support_offset
support_infill_sparse_thickness
gradual_support_infill_steps
gradual_support_infill_step_height
support_interface_enable
support_interface_height
support_interface_skip_height
support_interface_density
support_interface_pattern
support_use_towers
support_tower_diameter
support_minimal_diameter
support_tower_roof_angle
support_mesh_drop_down
[platform_adhesion]
prime_blob_enable
extruder_prime_pos_x
extruder_prime_pos_y
adhesion_type
adhesion_extruder_nr
skirt_line_count
skirt_gap
skirt_brim_minimal_length
brim_width
brim_outside_only
raft_margin
raft_smoothing
raft_airgap
layer_0_z_overlap
raft_surface_layers
raft_surface_thickness
raft_surface_line_width
raft_surface_line_spacing
raft_interface_thickness
raft_interface_line_width
raft_interface_line_spacing
raft_base_thickness
raft_base_line_width
raft_base_line_spacing
raft_speed
raft_acceleration
raft_jerk
raft_fan_speed
[dual]
prime_tower_enable
prime_tower_size
prime_tower_min_volume
prime_tower_position_x
prime_tower_position_y
prime_tower_flow
prime_tower_wipe_enabled
dual_pre_wipe
prime_tower_purge_volume
ooze_shield_enabled
ooze_shield_angle
ooze_shield_dist
[meshfix]
meshfix_union_all
meshfix_union_all_remove_holes
meshfix_extensive_stitching
meshfix_keep_open_polygons
multiple_mesh_overlap
carve_multiple_volumes
alternate_carve_order
remove_empty_first_layers
[blackmagic]
print_sequence
infill_mesh
infill_mesh_order
cutting_mesh
mold_enabled
mold_width
mold_roof_height
mold_angle
support_mesh
anti_overhang_mesh
magic_mesh_surface_mode
magic_spiralize
smooth_spiralized_contours
relative_extrusion
[experimental]
infill_enable_travel_optimization
material_flow_dependent_temperature
material_flow_temp_graph
meshfix_maximum_resolution
roofing_angles
roofing_pattern
slicing_tolerance
support_tree_angle
support_tree_branch_diameter
support_tree_branch_diameter_angle
support_tree_branch_distance
support_tree_collision_resolution
support_tree_enable
support_tree_wall_thickness

View File

@ -0,0 +1,66 @@
[general]
name = Basic
weight = 1
[machine_settings]
[resolution]
layer_height
[shell]
wall_thickness
top_bottom_thickness
z_seam_x
z_seam_y
[infill]
infill_sparse_density
gradual_infill_steps
[material]
material_print_temperature
material_bed_temperature
material_diameter
material_flow
retraction_enable
[speed]
speed_print
speed_travel
acceleration_print
acceleration_travel
jerk_print
jerk_travel
[travel]
[cooling]
cool_fan_enabled
[support]
support_enable
support_extruder_nr
support_type
[platform_adhesion]
adhesion_type
adhesion_extruder_nr
brim_width
raft_airgap
layer_0_z_overlap
raft_surface_layers
[dual]
prime_tower_enable
prime_tower_size
prime_tower_position_x
prime_tower_position_y
[meshfix]
[blackmagic]
print_sequence
infill_mesh
cutting_mesh
[experimental]

View File

@ -0,0 +1,285 @@
[general]
name = Expert
weight = 3
[machine_settings]
[resolution]
layer_height
layer_height_0
line_width
[shell]
wall_extruder_nr
wall_thickness
wall_0_wipe_dist
roofing_extruder_nr
roofing_layer_count
top_bottom_extruder_nr
top_bottom_thickness
top_bottom_pattern
top_bottom_pattern_0
skin_angles
wall_0_inset
optimize_wall_printing_order
outer_inset_first
alternate_extra_perimeter
travel_compensate_overlapping_walls_enabled
fill_perimeter_gaps
filter_out_tiny_gaps
fill_outline_gaps
xy_offset
xy_offset_layer_0
z_seam_type
z_seam_x
z_seam_y
z_seam_corner
z_seam_relative
skin_no_small_gaps_heuristic
skin_outline_count
ironing_enabled
ironing_only_highest_layer
ironing_pattern
ironing_line_spacing
ironing_flow
ironing_inset
speed_ironing
acceleration_ironing
jerk_ironing
[infill]
infill_extruder_nr
infill_sparse_density
infill_pattern
zig_zaggify_infill
infill_angles
infill_offset_x
infill_offset_y
sub_div_rad_add
infill_overlap
skin_overlap
infill_wipe_dist
infill_sparse_thickness
gradual_infill_steps
gradual_infill_step_height
infill_before_walls
min_infill_area
skin_preshrink
expand_skins_expand_distance
max_skin_angle_for_expansion
[material]
default_material_print_temperature
material_print_temperature
material_print_temperature_layer_0
material_initial_print_temperature
material_final_print_temperature
material_extrusion_cool_down_speed
default_material_bed_temperature
material_bed_temperature
material_bed_temperature_layer_0
material_diameter
material_adhesion_tendency
material_surface_energy
material_flow
retraction_enable
retract_at_layer_change
retraction_amount
retraction_speed
retraction_extra_prime_amount
retraction_min_travel
retraction_count_max
retraction_extrusion_window
material_standby_temperature
switch_extruder_retraction_amount
switch_extruder_retraction_speeds
[speed]
speed_print
speed_travel
speed_layer_0
skirt_brim_speed
max_feedrate_z_override
speed_slowdown_layers
speed_equalize_flow_enabled
speed_equalize_flow_max
acceleration_enabled
acceleration_print
acceleration_travel
acceleration_layer_0
acceleration_skirt_brim
jerk_enabled
jerk_print
jerk_travel
jerk_layer_0
jerk_skirt_brim
[travel]
retraction_combing
travel_retract_before_outer_wall
travel_avoid_other_parts
travel_avoid_distance
start_layers_at_same_position
layer_start_x
layer_start_y
retraction_hop_enabled
retraction_hop_only_when_collides
retraction_hop
retraction_hop_after_extruder_switch
[cooling]
cool_fan_enabled
cool_fan_speed
cool_min_layer_time_fan_speed_max
cool_fan_speed_0
cool_fan_full_at_height
cool_min_layer_time
cool_min_speed
cool_lift_head
[support]
support_enable
support_extruder_nr
support_type
support_angle
support_pattern
support_connect_zigzags
support_infill_rate
support_z_distance
support_xy_distance
support_xy_overrides_z
support_xy_distance_overhang
support_bottom_stair_step_height
support_bottom_stair_step_width
support_join_distance
support_offset
support_infill_sparse_thickness
gradual_support_infill_steps
gradual_support_infill_step_height
support_interface_enable
support_interface_height
support_interface_skip_height
support_interface_density
support_interface_pattern
support_use_towers
support_tower_diameter
support_minimal_diameter
support_tower_roof_angle
support_mesh_drop_down
[platform_adhesion]
prime_blob_enable
extruder_prime_pos_x
extruder_prime_pos_y
adhesion_type
adhesion_extruder_nr
skirt_line_count
skirt_gap
skirt_brim_minimal_length
brim_width
brim_outside_only
raft_margin
raft_smoothing
raft_airgap
layer_0_z_overlap
raft_surface_layers
raft_surface_thickness
raft_surface_line_width
raft_surface_line_spacing
raft_interface_thickness
raft_interface_line_width
raft_interface_line_spacing
raft_base_thickness
raft_base_line_width
raft_base_line_spacing
raft_speed
raft_acceleration
raft_jerk
raft_fan_speed
[dual]
prime_tower_enable
prime_tower_size
prime_tower_min_volume
prime_tower_position_x
prime_tower_position_y
prime_tower_flow
prime_tower_wipe_enabled
dual_pre_wipe
prime_tower_purge_volume
ooze_shield_enabled
ooze_shield_angle
ooze_shield_dist
[meshfix]
meshfix_union_all
meshfix_union_all_remove_holes
meshfix_extensive_stitching
meshfix_keep_open_polygons
multiple_mesh_overlap
carve_multiple_volumes
alternate_carve_order
remove_empty_first_layers
[blackmagic]
print_sequence
infill_mesh
infill_mesh_order
cutting_mesh
mold_enabled
mold_width
mold_roof_height
mold_angle
support_mesh
anti_overhang_mesh
magic_mesh_surface_mode
magic_spiralize
smooth_spiralized_contours
relative_extrusion
[experimental]
support_skip_some_zags
support_skip_zag_per_mm
draft_shield_enabled
draft_shield_dist
draft_shield_height_limitation
draft_shield_height
conical_overhang_enabled
conical_overhang_angle
coasting_enable
coasting_volume
coasting_min_volume
coasting_speed
skin_alternate_rotation
cross_infill_pocket_size
cross_infill_apply_pockets_alternatingly
spaghetti_infill_enabled
spaghetti_infill_stepped
spaghetti_max_infill_angle
spaghetti_max_height
spaghetti_inset
spaghetti_flow
spaghetti_infill_extra_volume
support_conical_enabled
support_conical_angle
support_conical_min_width
infill_hollow
magic_fuzzy_skin_enabled
magic_fuzzy_skin_thickness
magic_fuzzy_skin_point_density
flow_rate_max_extrusion_offset
flow_rate_extrusion_offset_factor
infill_enable_travel_optimization
material_flow_dependent_temperature
material_flow_temp_graph
meshfix_maximum_resolution
roofing_angles
roofing_pattern
slicing_tolerance
support_tree_angle
support_tree_branch_diameter
support_tree_branch_diameter_angle
support_tree_branch_distance
support_tree_collision_resolution
support_tree_enable
support_tree_wall_thickness

View File

@ -24,6 +24,11 @@ UM.PreferencesPage
function reset() function reset()
{ {
UM.Preferences.resetPreference("general/visible_settings") UM.Preferences.resetPreference("general/visible_settings")
// After calling this function update Setting visibility preset combobox.
// Reset should set "Basic" setting preset
visibilityPreset.setBasicPreset()
} }
resetEnabled: true; resetEnabled: true;
@ -72,6 +77,9 @@ UM.PreferencesPage
{ {
definitionsModel.setAllVisible(false) definitionsModel.setAllVisible(false)
} }
// After change set "Custom" option
visibilityPreset.currentIndex = visibilityPreset.model.count - 1
} }
} }
} }
@ -85,7 +93,8 @@ UM.PreferencesPage
top: parent.top top: parent.top
left: toggleVisibleSettings.right left: toggleVisibleSettings.right
leftMargin: UM.Theme.getSize("default_margin").width leftMargin: UM.Theme.getSize("default_margin").width
right: parent.right right: visibilityPreset.left
rightMargin: UM.Theme.getSize("default_margin").width
} }
placeholderText: catalog.i18nc("@label:textbox", "Filter...") placeholderText: catalog.i18nc("@label:textbox", "Filter...")
@ -93,6 +102,86 @@ UM.PreferencesPage
onTextChanged: definitionsModel.filter = {"i18n_label": "*" + text} onTextChanged: definitionsModel.filter = {"i18n_label": "*" + text}
} }
ComboBox
{
property int customOptionValue: 100
function setBasicPreset()
{
var index = 0
for(var i = 0; i < presetNamesList.count; ++i)
{
if(model.get(i).text == "Basic")
{
index = i;
break;
}
}
visibilityPreset.currentIndex = index
}
id: visibilityPreset
width: 150
anchors
{
top: parent.top
right: parent.right
}
model: ListModel
{
id: presetNamesList
Component.onCompleted:
{
// returned value is Dictionary (Ex: {1:"Basic"}, The number 1 is the weight and sort by weight)
var itemsDict = UM.Preferences.getValue("general/visible_settings_preset")
var sorted = [];
for(var key in itemsDict) {
sorted[sorted.length] = key;
}
sorted.sort();
for(var i = 0; i < sorted.length; i++) {
presetNamesList.append({text: itemsDict[sorted[i]], value: i});
}
// By agreement lets "Custom" option will have value 100
presetNamesList.append({text: "Custom", value: visibilityPreset.customOptionValue});
}
}
currentIndex:
{
// Load previously selected preset.
var text = UM.Preferences.getValue("general/preset_setting_visibility_choice");
var index = 0;
for(var i = 0; i < presetNamesList.count; ++i)
{
if(model.get(i).text == text)
{
index = i;
break;
}
}
return index;
}
onActivated:
{
// TODO What to do if user is selected "Custom from Combobox" ?
if (model.get(index).text == "Custom")
return
var newVisibleSettings = CuraApplication.getVisibilitySettingPreset(model.get(index).text)
UM.Preferences.setValue("general/visible_settings", newVisibleSettings)
UM.Preferences.setValue("general/preset_setting_visibility_choice", model.get(index).text)
}
}
ScrollView ScrollView
{ {
id: scrollView id: scrollView
@ -162,7 +251,18 @@ UM.PreferencesPage
{ {
id: settingVisibilityItem; id: settingVisibilityItem;
UM.SettingVisibilityItem { } UM.SettingVisibilityItem {
// after changing any visibility of settings, set the preset to the "Custom" option
visibilityChangeCallback : function()
{
// If already "Custom" then don't do nothing
if (visibilityPreset.currentIndex != visibilityPreset.model.count - 1)
{
visibilityPreset.currentIndex = visibilityPreset.model.count - 1
}
}
}
} }
} }
} }

View File

@ -0,0 +1,126 @@
#!/usr/bin/env python
import configparser
import json
import os
import sys
class PresetSettingsValidator:
def __init__(self, cura_dir: str):
self._cura_dir = os.path.abspath(cura_dir)
self._resource_dir = os.path.join(self._cura_dir, "resources")
self._definitions_dir = os.path.join(self._resource_dir, "definitions")
self._preset_settings_dir = os.path.join(self._resource_dir, "preset_setting_visibility_groups")
self._fdmprinter_def_path = os.path.join(self._definitions_dir, "fdmprinter.def.json")
def validate(self) -> bool:
"""
Validates the preset settings files and returns True or False indicating whether there are invalid files.
"""
if not os.path.isfile(self._fdmprinter_def_path):
raise FileNotFoundError("[%s] is not a file or doesn't exist, please make sure you have specified the correct cura directory [%s]." % (self._fdmprinter_def_path, self._cura_dir))
if not os.path.isdir(self._preset_settings_dir):
raise FileNotFoundError("[%s] is not a directory or doesn't exist, please make sure you have specified the correct cura directory [%s]." % (self._preset_settings_dir, self._cura_dir))
# parse the definition file
setting_tree_dict = self._parse_definition_file(self._fdmprinter_def_path)
has_invalid_files = False
# go through all the preset settings files
for root_dir, _, filenames in os.walk(self._preset_settings_dir):
for filename in filenames:
file_path = os.path.join(root_dir, filename)
print("Validating [%s] ..." % file_path)
incorrect_sections = []
incorrect_settings = {}
parser = configparser.ConfigParser(allow_no_value = True)
with open(file_path, "r", encoding = "utf-8") as f:
parser.read_file(f)
for key in parser:
# skip general
if key in ("general", configparser.DEFAULTSECT):
continue
if key not in setting_tree_dict:
incorrect_sections.append(key)
continue
for setting_key in parser[key]:
if setting_key not in setting_tree_dict[key]:
if setting_key not in incorrect_settings:
incorrect_settings[setting_key] = {"seen_in": [],
"should_be_in": self._should_setting_be_in(setting_tree_dict, setting_key)}
incorrect_settings[setting_key]["seen_in"].append(key)
# show results
print("==========================================")
if incorrect_sections or incorrect_settings:
has_invalid_files = True
print("[INVALID] [%s] is invalid, details below" % file_path)
# show details
for section_name in sorted(incorrect_sections):
print(" -- section name [%s] is incorrect, please check fdmprinter.def.json." % section_name)
for setting_name in sorted(incorrect_settings.keys()):
details_dict = incorrect_settings[setting_name]
msg = " -- setting [%s] is found in sections [%s], " % (setting_name, ", ".join(details_dict["seen_in"]))
if details_dict["should_be_in"] is not None:
msg += "but should be in section [%s] only." % details_dict["should_be_in"]
else:
msg += "but it cannot be found in fdmprinter.def.json"
print(msg)
else:
print("[%s] is valid" % file_path)
print("==========================================")
return not has_invalid_files
def _parse_definition_file(self, file_path: str):
with open(file_path, "r", encoding = "utf-8") as f:
def_dict = json.load(f, encoding = "utf-8")
tree_dict = {}
for key, item in def_dict.get("settings", {}).items():
setting_list = []
self._generate_tree(setting_list, item.get("children", {}))
tree_dict[key] = setting_list
return tree_dict
def _generate_tree(self, setting_list: list, setting_dict: dict):
for key, item in setting_dict.items():
setting_list.append(key)
if "children" in item:
self._generate_tree(setting_list, item["children"])
def _should_setting_be_in(self, setting_dict: dict, setting_name: str) -> str:
"""
Check which section the given setting belongs to. Returns None if the setting cannot be found.
"""
section_name = None
for key, setting_list in setting_dict.items():
if setting_name in setting_list:
section_name = key
break
return section_name
if __name__ == "__main__":
script_dir = os.path.dirname(os.path.realpath(__file__))
cura_dir = os.path.abspath(os.path.join(script_dir, ".."))
validator = PresetSettingsValidator(cura_dir)
is_everything_validate = validator.validate()
ret_code = 0 if is_everything_validate else 1
sys.exit(ret_code)