def save_uuid(self, uuid: QUuid) -> str: """ Store a Quuid and return a integer id as string to minimize file save/load effort. This method should only be used on file saving! """ uuid_str = uuid.toString() if uuid_str in self.item_ids: return self.item_ids[uuid_str] self.str_ids += 1 str_id = str(self.str_ids) self.item_ids[uuid_str] = str_id return str_id
class KnechtModelIdentifiers(QObject): debug_preset = False debug_ref = False check_recurring_id = QUuid() def __init__(self, parent_model): """ ID Manager stores item identifiers for the parent model :param modules.itemview.model.KnechtModel parent_model: """ super(KnechtModelIdentifiers, self).__init__(parent=parent_model) self.model = parent_model self._presets = IdStorage() self._references = IdStorage() self.invalid_references = IdStorage() self.recursive_items = list() def preset_id_changed(self, _id: QUuid, item: KnechtItem, add: bool) -> None: """ Preset Ids updated from model """ # -- Remove from Id storage -- if not add: self._presets.remove_item(item) if self.debug_preset: LOGGER.debug( f'Removed Preset {_id.toString()[-5:-1]}[' f'{len(self._presets.items):02d}] - {item.data(0)[:3]}{item.data(1)[:10]} - {self.model}' ) return # -- Add to Id storage -- if is_valid_uuid(_id): self._presets.add(_id, item) if self.debug_preset: LOGGER.debug( f'Added Preset {_id.toString()[-5:-1]}[' f'{len(self._presets.items):02d}] - {item.data(0)[:3]}{item.data(1)[:10]} - {self.model}' ) def reference_id_changed(self, _id: QUuid, item: KnechtItem, add: bool, invalid: bool = False) -> None: """ Reference Ids updated from model """ # -- Add invalid reference -- if invalid and add: self.invalid_references.add(_id, item) if self.debug_ref: LOGGER.debug( f'Adding invalid Reference {_id.toString()[-5:-1]}[' f'{len(self.invalid_references.items):02d}] {item.data(1)[:10]} - {self.model}' ) # -- Remove invalid reference -- elif invalid and not add: self.invalid_references.remove_item(item) if self.debug_ref: LOGGER.debug( f'Removing from invalid References [' f'{len(self.invalid_references.items):02d}] {item.data(1)[:10]} - {self.model}' ) # -- Remove from Id storage -- elif not invalid and not add: self._references.remove_item(item) if self.debug_ref: LOGGER.debug( f'Removed Reference {_id.toString()[-5:-1]}[' f'{len(self._references.items):02d}] {item.data(1)[:10]} - {self.model}' ) # -- Add to Id storage -- elif not invalid and add: self.invalid_references.remove_item(item) self._references.add(_id, item) if self.debug_ref: LOGGER.debug( f'Added Reference {_id.toString()[-5:-1]}[' f'{len(self._references.items):02d}] - {item.data(1)[:10]} - {self.model}' ) def is_item_referenced_preset(self, preset: KnechtItem) -> bool: if self._references.has_id(preset.preset_id): return True return False def is_item_reference(self, reference: KnechtItem) -> bool: if self._references.has_item(reference): return True return False def is_index_referenced_preset(self, index: QModelIndex) -> bool: item = self.model.get_item(index) if item and self._references.has_id(item.preset_id): return True return False def is_index_reference(self, index: QModelIndex): item = self.model.get_item(index) if item and self._references.has_item(item): return True return False def is_id_existing_preset(self, _id: QUuid): return self._presets.has_id(_id) def has_invalid_references(self) -> bool: return self.invalid_references.has_items() def has_recursive_items(self) -> bool: if self.recursive_items: return True return False def iterate_presets(self): return self._presets.item_iterator() def iterate_references(self): return self._references.item_iterator() def iterate_invalid_references(self): return self.invalid_references.item_iterator() def iterate_recursive_items(self): yield from self.recursive_items def validate_reference(self, _id): if not self._presets.get_item(_id): return False return True def get_preset_id_from_index( self, preset_index: QModelIndex) -> Union[QUuid, None]: item = self.model.get_item(preset_index) if item: return item.preset_id def get_reference_id_from_index( self, preset_index: QModelIndex) -> Union[QUuid, None]: item = self.model.get_item(preset_index) if item: return item.reference def get_preset_from_reference_index( self, index: QModelIndex) -> Union[None, KnechtItem]: referenced_id = self.get_reference_id_from_index(index) return self._presets.get_item(referenced_id) def get_references_from_preset_index( self, index: QModelIndex) -> Iterable[KnechtItem]: preset_id = self.get_preset_id_from_index(index) return self._references.get_all_items_by_id(preset_id) def get_references_from_id(self, _id): return self._references.get_all_items_by_id(_id) def get_preset_from_id(self, _id): return self._presets.get_item(_id) def get_invalid_references_indices( self, proxy_model: QSortFilterProxyModel = None): """ Get indices to all invalid references """ return self._convert_items_to_indices( self.iterate_invalid_references(), proxy_model) def get_recursive_indices(self, proxy_model: QSortFilterProxyModel = None): """ Get indices to all recursive references """ return self._convert_items_to_indices(self.iterate_recursive_items(), proxy_model) def get_references_by_indices( self, index_list: Iterable[QModelIndex], proxy_model: QSortFilterProxyModel = None, ) -> Tuple[Iterable[QModelIndex], Iterable[QModelIndex]]: """ Get referenced presets and reference indices. Provide a list of model indices and get two separate lists containing: * all referenced preset items linked from the provided reference indices * all reference items linking to the provided preset indices *IMPORTANT* The returned indices will have their column at 0 :param Iterable[QModelIndex] index_list: the indices to look up :param QSortFilterProxyModel proxy_model: the proxy model the results should be mapped to :rtype Tuple[Iterable[QModelIndex], Iterable[QModelIndex]]: (list(), list()) :returns : Tuple with list of referenced Presets and list of reference indices. """ reference_items = list() referenced_presets = list() # --- Collect referenced items --- for index in index_list: if self.is_index_referenced_preset(index): reference_items += self.get_references_from_preset_index(index) continue if self.is_index_reference(index): referenced_presets.append( self.get_preset_from_reference_index(index)) reference_index_ls = [ idx for idx in self._convert_items_to_indices( reference_items, proxy_model) ] preset_index_ls = [ idx for idx in self._convert_items_to_indices( referenced_presets, proxy_model) ] return preset_index_ls, reference_index_ls def get_all_links_from_index(self, index: QModelIndex): """ Get *all* indices that have the same id as the provided index *IMPORTANT* The returned indices will have their column at 0 :returns Iterable[QModelIndex]: All references and presets with matching id """ linked_items = list() if self.is_index_referenced_preset(index): linked_items += self.get_references_from_preset_index(index) if self.is_index_reference(index): reference_id = self.get_reference_id_from_index(index) linked_items += self.get_references_from_id(reference_id) linked_items.append(self.get_preset_from_id(reference_id)) index_ls = [ idx for idx in self._convert_items_to_indices(linked_items) ] if index in index_ls: index_ls.remove(index) return index_ls def reset_recursive_items(self): self.recursive_items = list() def get_recursive_items(self, preset) -> List[Tuple[KnechtItem, KnechtItem]]: """ Check every know preset in the model for recursive references. :returns [ (KnechtItem, KnechtItem) ]: List containing recursive preset item and child item causing the recursion as pair inside a tuple. """ self.check_recurring_id = preset.preset_id recursive_preset, recursive_child = self._check_preset(preset, 0) if recursive_preset or recursive_child: if recursive_preset not in self.recursive_items: self.recursive_items.append(recursive_preset) if recursive_child not in self.recursive_items: self.recursive_items.append(recursive_child) return self.recursive_items def _check_preset( self, preset: KnechtItem, depth: int = 0 ) -> Union[Tuple[KnechtItem, KnechtItem], Tuple[None, None]]: if depth > 10: return None, None for child in preset.iter_children(): ref_id = child.reference if not isinstance(ref_id, QUuid): continue if ref_id == self.check_recurring_id: return preset, child referenced_preset = self.get_preset_from_id(ref_id) if referenced_preset: depth += 1 recursive_preset, recursive_child = self._check_preset( referenced_preset, depth) if recursive_preset: return recursive_preset, recursive_child return None, None def _convert_items_to_indices( self, items: Iterable[KnechtItem], proxy_model: QSortFilterProxyModel = None ) -> Iterator[QModelIndex]: for item in items: index = self.model.get_index_from_item(item) proxy_index = None if proxy_model: proxy_index = proxy_model.mapFromSource(index) if proxy_index: yield proxy_index continue if index: yield index
def setUp(self): self.original = QUuid("67C8770B-44F1-410A-AB9A-F9B5446F13EE")
def testFromString(self): uuidString = '{fc69b59e-cc34-4436-a43c-ee95d128b8c5}' uuid = QUuid(uuidString) self.assertTrue(not uuid.isNull()) self.assertEqual(uuid.toString(), uuidString)