def _iterate_scene_children(self, idx: int, node: NodeInfo, parent_item: KnechtItem, use_config: bool = False): child_idx = parent_item.childCount() parent_item.insertChildren( child_idx, 1, (f'{idx:03d}', node.name, node.pr_tags, node.trigger_rules)) node_item = parent_item.child(child_idx) # -- Style Schaltgruppen if node.pr_tags: KnechtItemStyle.style_column(node_item, 'plmxml_item') # -- Style visible nodes in Config Display if use_config and node.visible: node_item.style_bg_green() # -- Skip invisible child nodes in Config Display if use_config and node.pr_tags and not node.visible: node_item.style_recursive() return for idx, child_node in enumerate( self.plmxml.iterate_child_nodes(node)): self._iterate_scene_children(idx, child_node, node_item, use_config)
def _build_material_tree(self, use_config: bool = False): material_root_item = KnechtItem(data=('', 'Material Name', 'PR-Tags', 'Desc')) for idx, (name, target) in enumerate(self.plmxml.look_lib.materials.items()): child_idx = material_root_item.childCount() material_root_item.insertChildren(child_idx, 1, (f'{idx:03d}', name, '', '')) target_item = material_root_item.child(child_idx) KnechtItemStyle.style_column(target_item, 'fakom_option') # -- Create Material Variants for c_idx, v in enumerate(target.variants): # -- Skip invisible variants in Config Display if use_config: if v != target.visible_variant: continue target_child_idx = target_item.childCount() target_item.insertChildren( target_child_idx, 1, (f'{c_idx:03d}', v.name, v.pr_tags, v.desc)) if use_config: variant_item = target_item.child(target_child_idx) variant_item.style_bg_green() update_material_tree = UpdateModel(self.material_tree) update_material_tree.update(KnechtModel(material_root_item))
def _create_tree_item(self, node, parent_item: KnechtItem = None) -> KnechtItem: data = self._data_from_element_attribute(node) if parent_item is None: child_position = self.root_item.childCount() self.root_item.insertChildren(child_position, 1, data) parent_item = self.root_item.child(child_position) self.xml_id.update_preset_uuid(node, parent_item) return parent_item position = parent_item.childCount() result = parent_item.insertChildren(position, 1, data) if not result: LOGGER.error('Could not insert child %s %s', position, parent_item.childCount()) return parent_item self.xml_id.update_reference_uuid(node, parent_item.child(position)) return parent_item
def create_presets(self): root_item = KnechtItem() for (src_index, item) in self.image_view.editor.iterator.iterate_view(): if item.data(self.check_column, Qt.CheckStateRole) == Qt.Unchecked: continue name = item.data(Kg.NAME) data = (f'{root_item.childCount():03d}', name, '', 'preset', '', Kid.convert_id(f'{root_item.childCount()}')) root_item.insertChildren(root_item.childCount(), 1, data) date = datetime.datetime.now().strftime('%Y%m%d') project = self._current_project_name.replace(' ', '_') self.finished.emit(KnechtModel(root_item), Path(f'{date}_{project}.xml'))
def create_packages(self, trim: KnTrim, parent_item: KnechtItem, filter_pkg_by_pr_family: bool): for pkg in trim.iterate_packages(): if not pkg.child_count(): continue pkg_item = self.create_package(trim, pkg, parent_item.childCount()) pkg_item.parentItem = parent_item keep_package = True if not [ pr for pr in pkg.iterate_pr() if pr.family in self.data.selected_pr_families ]: keep_package = False if pkg_item.childCount(): if filter_pkg_by_pr_family and keep_package: # Only create packages that contain at least one PR Family from pr family filter parent_item.append_item_child(pkg_item) elif not filter_pkg_by_pr_family: # Create all packages and do not apply any filtering parent_item.append_item_child(pkg_item)
def _xml_items_loaded(self, root_item: KnechtItem, error: str, file: Path): if not root_item.childCount(): LOGGER.info('Could not load Xml. KnechtXml returned %s', error) self.load_aborted.emit(error, file) return # Transfer root_item to new_model new_model = KnechtModel(root_item) # Add recent file entry if self.create_recent_entries: KnechtSettings.add_recent_file(file.as_posix(), 'xml') KnechtSettings.app['current_path'] = file.parent.as_posix() # Output load info self.last_progress_time = time.time() - self.load_start_time LOGGER.info( f'Xml file {file.name} took {self.last_progress_time:.4}s to parse. {root_item.thread()}' ) # Transfer model self.model_loaded.emit(new_model, file)
class KnechtDataToModel: progress_signal = None def __init__(self, data: KnData): self.data = data self.id_gen = KnechtUuidGenerator() self.root_item = KnechtItem() def _show_progress(self, msg: str): if self.progress_signal is None: return self.progress_signal.emit(msg) def create_root_item(self): self.create_items() LOGGER.debug('Created %s items from ExcelData.', self.root_item.childCount()) return self.root_item def create_items(self): progress_idx = 0 for trim in self.data.models: model = trim.model if model not in self.data.selected_models: continue progress_idx += 1 self._show_progress( _('Erstelle Model {} {:02d}/{:02d}...').format( model, progress_idx, len(self.data.selected_models))) # -- Create Trim line item -- if self.data.read_trim: trim_item = self.create_trim(trim) self.root_item.append_item_child(trim_item) # -- Create options -- if self.data.read_options: # Filter rows matching E options_item = self.create_trim_options( trim, self.data.options_text_filter) self.root_item.append_item_child(options_item) # -- Create packages -- if self.data.read_packages: self.create_packages(trim, self.root_item, self.data.pr_fam_filter_packages) if self.data.read_fakom: self.create_fakom(trim) def create_trim(self, trim: KnTrim) -> KnechtItem: # -- Create trim line item -- data = ( f'{self.root_item.childCount():03d}', # Order trim.model_text, # Name trim.model, # Value 'trim_setup', # Type '', # Ref ID self.id_gen.create_id(), # ID f'{trim.market} - {trim.gearbox}' # Description ) trim_item = KnechtItem(self.root_item, data) trim_code_item = KnechtItem(trim_item, ('000', trim.model, 'on')) trim_item.append_item_child(trim_code_item) self.create_pr_options(trim.iterate_trim_pr(), trim_item) return trim_item def create_trim_options(self, trim, text_filter_options=False): # -- Create trim line options item -- data = (f'{self.root_item.childCount():03d}', f'{trim.model_text} Options', trim.model, 'options', '', self.id_gen.create_id(), f'{trim.market} - {trim.gearbox}') options_item = KnechtItem(self.root_item, data) if text_filter_options: self.create_pr_options(trim.iterate_optional_filtered_pr(), options_item) else: self.create_pr_options(trim.iterate_optional_pr(), options_item) return options_item def create_package(self, trim: KnTrim, pkg: KnPackage, order: int = 0) -> KnechtItem: data = ( f'{order:03d}', # Order f'{pkg.name} {pkg.desc} {trim.model} {trim.market}', # Name pkg.name, # Value 'package', # Type '', # Ref ID self.id_gen.create_id() # ID ) pkg_item = KnechtItem(None, data) for pr in pkg.iterate_pr(): pr_item = KnechtItem(pkg_item, (f'{pkg_item.childCount():03d}', pr.name, 'on', pr.family, '', '', pr.desc)) pkg_item.append_item_child(pr_item) return pkg_item def create_packages(self, trim: KnTrim, parent_item: KnechtItem, filter_pkg_by_pr_family: bool): for pkg in trim.iterate_packages(): if not pkg.child_count(): continue pkg_item = self.create_package(trim, pkg, parent_item.childCount()) pkg_item.parentItem = parent_item keep_package = True if not [ pr for pr in pkg.iterate_pr() if pr.family in self.data.selected_pr_families ]: keep_package = False if pkg_item.childCount(): if filter_pkg_by_pr_family and keep_package: # Only create packages that contain at least one PR Family from pr family filter parent_item.append_item_child(pkg_item) elif not filter_pkg_by_pr_family: # Create all packages and do not apply any filtering parent_item.append_item_child(pkg_item) def create_pr_options(self, pr_iterator: List[KnPr], parent_item: KnechtItem, ignore_pr_family=False): for pr in pr_iterator: if not ignore_pr_family and pr.family not in self.data.selected_pr_families: continue pr_item = KnechtItem(parent_item, (f'{parent_item.childCount():03d}', pr.name, 'on', pr.family, '', '', pr.desc)) parent_item.append_item_child(pr_item) def create_fakom(self, trim: KnTrim, is_preset_wizard: bool = False, parent_item: KnechtItem = None): model_short_desc = shorten_model_name(trim.model_text) # Create lists of List[KnPr] for SIB/VOS/LUM families sib_pr_ls = [ pr for pr in trim.iterate_available_pr() if pr.family.casefold() == 'sib' ] sib_pr_codes = [pr.name for pr in sib_pr_ls] lum_pr_ls = [ pr for pr in trim.iterate_available_pr() if pr.family.casefold() == 'lum' ] vos_pr_ls = [ pr for pr in trim.iterate_available_pr() if pr.family.casefold() == 'vos' ] if not parent_item: parent_item = self.root_item for color, sib_set in self.data.fakom.iterate_colors(): valid_sib_set = sib_set.intersection(sib_pr_codes) if not valid_sib_set: continue fa_parent, grp_item = parent_item, parent_item if is_preset_wizard: grp_item = KnechtItem(parent_item, (f'{parent_item.childCount():03d}', color, '', 'fakom_option')) grp_item.fixed_userType = Kg.group_item parent_item.append_item_child(grp_item) # --- Iterate SIB Codes --- for sib_pr in sib_pr_ls: if sib_pr.name not in valid_sib_set: # Skip seat covers not matching continue if is_preset_wizard: sib_grp_item = KnechtItem(grp_item, (f'{grp_item.childCount():03d}', sib_pr.name, '', 'options')) sib_grp_item.fixed_userType = Kg.group_item grp_item.append_item_child(sib_grp_item) fa_parent = sib_grp_item # --- Iterate VOS Codes --- for vos_pr in vos_pr_ls: # --- Iterate LUM Codes --- for lum_pr in lum_pr_ls: # Determine if all options belong to standard equipment L fakom_type = 'fakom_option' if not {sib_pr.value, vos_pr.value, lum_pr.value }.difference('L'): fakom_type = 'fakom_setup' fa_item = self.create_fakom_item( fa_parent, trim.model, model_short_desc, color, sib_pr.name, vos_pr.name, lum_pr.name, sib_pr.desc, vos_pr.desc, lum_pr.desc, fakom_type, is_preset_wizard) if is_preset_wizard: continue fa_parent.append_item_child(fa_item) def create_fakom_item(self, parent: Union[KnechtItem, None], model, model_desc, color, sib, vos, lum, sib_text, vos_text, lum_text, fakom_type, preset_wizard: bool = False): name = f'{model_desc} {color}-{sib}-{vos}-{lum}' if preset_wizard: name = f'{color}-{sib}-{vos}-{lum}' order = 0 if parent: order = parent.childCount() data = (f'{order:03d}', f'{name}', model, fakom_type, '', self.id_gen.create_id()) # Create FaKom item fa_item = KnechtItem(parent, data) if preset_wizard: fa_item.fixed_userType = Kg.dialog_item if parent: parent.append_item_child(fa_item) return # Create FaKom item content color_item = KnechtItem(fa_item, ('000', color, 'on')) sib_item = KnechtItem(fa_item, ('001', sib, 'on', 'SIB', '', '', sib_text)) vos_item = KnechtItem(fa_item, ('002', vos, 'on', 'VOS', '', '', vos_text)) lum_item = KnechtItem(fa_item, ('003', lum, 'on', 'LUM', '', '', lum_text)) for i in (color_item, sib_item, vos_item, lum_item): fa_item.append_item_child(i) return fa_item
class KnechtXmlReader: """ Read RenderKnecht Xml :param: error: String containing the error message for the user """ def __init__(self): # Helper class to convert and create QUuids self.xml_id = KnechtXmlId() # Temporary item stores -currently- iterated preset item self.__preset_item = None # Loaded items temporary root item self.root_item = KnechtItem() # Store error message self.error = str() def read_xml(self, file: Union[Path, str, bytes]) -> KnechtItem: """ Read RenderKnecht Xml and return list of KnechtItem's Stores Xml read errors in class attribute errors. :param: file: Xml file to load or utf-8 encoded Xml string :type: file: Path or str :rtype: KnechtItem: KnechtItem Root Node :returns: tree root node """ xml = None if path_is_xml_string(file): try: xml = Et.fromstring(file) except Exception as e: LOGGER.error('Error parsing Xml string data: %s', e) self.set_error(0) return self.root_item if xml is None: try: xml = Et.parse(file.as_posix()) except Exception as e: LOGGER.error('Error parsing Xml document:\n%s', e) self.set_error(0) return self.root_item if not self._validate_renderknecht_xml(xml): self.set_error(1) return self.root_item # Transfer Xml to self.root_item self._xml_to_items(xml) if not self.root_item.childCount(): self.set_error(2) # Return the list of item data return self.root_item def _xml_to_items(self, xml): for e in xml.iterfind('./*//'): self._read_node(e) def _read_node(self, node: Et.Element): # Re-write order with leading zeros if 'order' in node.attrib.keys(): node.set('order', f'{int(node.attrib["order"]):03d}') # Backwards compatible, value stored in tag text if node.tag == KgTags.variant_tag and node.text: node.set('value', node.text) if node.tag in KgTags.preset_tags: # Create preset item: node, parent self.__preset_item = self._create_tree_item(node) elif node.tag == KgTags.render_preset_tag: self.__preset_item = self._create_tree_item(node) elif node.tag in KgTags.separator_tags: self._create_tree_item(node) elif node.tag in KgTags.sub_separator_tags: node.attrib['type'] = 'sub_separator' self._create_tree_item(node, self.__preset_item) elif node.tag in KgTags.render_setting_tags: self._create_tree_item(node, self.__preset_item) elif node.tag in KgTags.variants_tags: if node.getparent().tag == Kg.xml_dom_tags['level_1']: # Parse orphans aswell for session load / variants widget self._create_tree_item(node) else: # Create variant / reference with parent: last preset_item self._create_tree_item(node, self.__preset_item) def _create_tree_item(self, node, parent_item: KnechtItem = None) -> KnechtItem: data = self._data_from_element_attribute(node) if parent_item is None: child_position = self.root_item.childCount() self.root_item.insertChildren(child_position, 1, data) parent_item = self.root_item.child(child_position) self.xml_id.update_preset_uuid(node, parent_item) return parent_item position = parent_item.childCount() result = parent_item.insertChildren(position, 1, data) if not result: LOGGER.error('Could not insert child %s %s', position, parent_item.childCount()) return parent_item self.xml_id.update_reference_uuid(node, parent_item.child(position)) return parent_item def set_error(self, error_type: int = 0): error_msg = { 0: _('Das gewählte Xml Dokument ist kein gültiges Xml Dokument und konnte nicht gelesen werden.' ), 1: _('Das gewählte Xml Dokument enthält nicht die erwarteten Daten. Es ist kein RenderKnecht ' 'kompatibles Xml Dokument.'), 2: _('Das gewählte Xml Dokument ist gültig, enthält aber kein Daten.' ), } self.error = error_msg[error_type] @staticmethod def _data_from_element_attribute(node) -> tuple: data = list() for key in Kg.column_keys: data.append(node.attrib.get(key) or '') return tuple(data) @staticmethod def _validate_renderknecht_xml(xml): root = xml.find('.') if root.tag != Kg.xml_dom_tags['root']: LOGGER.error( 'Can not load Xml document. Expected xml root tag: %s, received: %s', Kg.xml_dom_tags['root'], root.tag) return False return True
def collect_result(self): kn_data = self.session.data.import_data converter = KnechtDataToModel(kn_data) trim_items = dict() # --- Create Trim Setups --- for model_code in self.session.data.fakom_selection.keys(): trim = self._get_trim_from_models(kn_data.models, model_code) trim_items[model_code] = dict() trim_item = converter.create_trim(trim) trim_item.refresh_id_data() trim_items[model_code]['trim_setup'] = trim_item trim_items[model_code][ 'trim_option'] = converter.create_trim_options( trim, kn_data.options_text_filter) trim_items[model_code]['packages'] = list() trim_items[model_code]['fakom'] = dict() # -- Create FaKom Items -- for preset_page in self.session.iterate_preset_pages(): fakom_ls = preset_page.fakom.split('-') if len(fakom_ls) < 4: continue trim = self._get_trim_from_models(kn_data.models, preset_page.model) # Create lists of List[KnPr] for SIB/VOS/LUM families sib_pr_ls = [ pr for pr in trim.iterate_available_pr() if pr.family.casefold() == 'sib' ] lum_pr_ls = [ pr for pr in trim.iterate_available_pr() if pr.family.casefold() == 'lum' ] vos_pr_ls = [ pr for pr in trim.iterate_available_pr() if pr.family.casefold() == 'vos' ] fa, sib, vos, lum = fakom_ls LOGGER.debug('Creating Fakom Item %s %s %s %s', fa, sib, vos, lum) sib_pr = self._get_pr_from_list(sib_pr_ls, sib) vos_pr = self._get_pr_from_list(vos_pr_ls, vos) lum_pr = self._get_pr_from_list(lum_pr_ls, lum) fakom_type = 'fakom_option' if not {sib_pr.value, vos_pr.value, lum_pr.value}.difference('L'): fakom_type = 'fakom_setup' fa_item = converter.create_fakom_item(None, trim.model, trim.model_text, fa, sib, vos, lum, sib_pr.desc, vos_pr.desc, lum_pr.desc, fakom_type, False) fa_item.refresh_id_data() trim_items[preset_page.model]['fakom'][preset_page.fakom] = fa_item # --- Prepare presets --- preset_items = list() for preset_page in self.session.iterate_preset_pages(): # -- Create Preset item -- preset_item = KnechtItem( None, ('000', preset_page.subTitle(), '', Kg.type_keys[Kg.preset], '', Kid.create_id())) # -- Add reference to trim setup -- trim_ref = trim_items[preset_page.model]['trim_setup'].copy( copy_children=False) trim_ref.convert_to_reference() trim_ref.setData(0, '000') preset_item.append_item_child(trim_ref) # -- Add reference to fakom item -- fa_ref = trim_items[preset_page.model]['fakom'][ preset_page.fakom].copy(copy_children=False) fa_ref.convert_to_reference() fa_ref.setData(0, '001') preset_item.append_item_child(fa_ref) # -- Collect preset content -- for _, pr_item in preset_page.preset_tree.editor.iterator.iterate_view( ): if pr_item.userType == Kg.variant: # --- Add PR-option --- pr_item_copy = pr_item.copy() pr_item_copy.setData(0, f'{preset_item.childCount():03d}') preset_item.append_item_child(pr_item_copy) else: # --- Add package reference --- pkg_ref = pr_item.copy(copy_children=False) pkg_ref.convert_to_reference() pkg_ref.setData(0, f'{preset_item.childCount():03d}') preset_item.append_item_child(pkg_ref) # --- Add package --- trim_items[preset_page.model]['packages'].append( pr_item.copy()) preset_items.append(preset_item) # --- Create trim, package and fakom items --- root_item = KnechtItem() for model_code in self.session.data.fakom_selection.keys(): # -- Add trim setup -- trim_item = trim_items[model_code]['trim_setup'] trim_item.setData(Kg.ORDER, f'{root_item.childCount():03d}') root_item.append_item_child(trim_item) # -- Add trim options -- trim_options = trim_items[model_code]['trim_option'] trim_options.setData(Kg.ORDER, f'{root_item.childCount():03d}') root_item.append_item_child(trim_options) # -- Add Packages -- for pkg_item in trim_items[model_code]['packages']: pkg_item.setData(Kg.ORDER, f'{root_item.childCount():03d}') root_item.append_item_child(pkg_item) # -- Add FaKom Items -- for fa_item in trim_items[model_code]['fakom'].values(): fa_item.setData(Kg.ORDER, f'{root_item.childCount():03d}') root_item.append_item_child(fa_item) # -- Add separator -- root_item.append_item_child( KnechtItem( None, (f'{root_item.childCount():03d}', '', '', 'separator'))) # -- Create default Reset -- reset_item = create_reset_item(root_item.childCount()) root_item.append_item_child(reset_item) # -- Add separator -- root_item.append_item_child( KnechtItem(None, (f'{root_item.childCount():03d}', '', '', 'separator'))) # --- Create Preset items --- for preset_item in preset_items: preset_item.setData(Kg.ORDER, f'{root_item.childCount():03d}') root_item.append_item_child(preset_item) UpdateModel(self.result_tree).update(KnechtModel(root_item))