class PlayerTreeDAO(IPlayerTreeDAO): """ DAO for tree widget """ TABLE_NAME = 'player_tree_structure' DATABASE_DRIVER = "file::memory:?cache=shared" def __init__(self): self.database = Database(self.DATABASE_DRIVER) def get_root_nodes(self, target_type: ObjectType) -> list: """ Get all nodes with parent null :param target_type: Type of object :return: list of root nodes """ data = self.database.select(self.TABLE_NAME, { 'parent_id': None, 'parent_type': target_type.value }) return map_objects(data) def get_nodes_search(self, targetType: ObjectType, text: str): """ Get nodes witch name contain searched text :param targetType: Type of object in node :param text: searching text :return: list of nodes with text included """ data = self.database.select(self.TABLE_NAME, { 'parent_type': targetType.value, 'name': ('like', '%' + text + '%') }) return map_objects(data) def get_node(self, id: int) -> Node: """ Get node by id :param id: id of node :return: node object if exist, None otherwise """ data = self.database.select(self.TABLE_NAME, {'ID': id}) return map_objects(data)[0] if len(data) > 0 else None def get_children_objects(self, parentNodeId: int, contextType: ObjectType) -> list: """ Recursively find all child object of give type, only first level object (folders will be skipped and searching deep :param parentNodeId parent node, where you finding :param contextType object type of tree :return: list of objects in tree """ nodes = self.get_children_nodes(contextType, parentNodeId) objects = [] for node in nodes: if isinstance(node, Folder): objects += self.get_children_nodes(contextType, node.id) else: objects.append(node) return objects def __get_children_objects(self, targetType, nodeId: int, parentType: ObjectType, objects: list = None, direct: bool = False): """ Private function, return all children object of target node :param targetType: Object type :param nodeId: id of target node :param parentType: Context type :param objects: list of object for recursion :param direct: if true, only first level child will be add to object list :return: list of children """ if objects is None: objects = [] children = self.get_children_nodes(parentType, nodeId) for child in children: if direct and isinstance( child, NodeObject) and child.object.object_type is not targetType: continue objects = self.__get_children_objects(targetType, child.id, parentType, objects, direct=direct) if isinstance( child, NodeObject) and child.object.object_type is targetType: objects.append(child.object) return objects def get_children_nodes(self, contextType: ObjectType, parent_id: int) -> list: """ Get all child of parent id :param target_type: target type :param parent_id: parent id :return: list of nodes with parent id, or empty list """ data = self.database.select(self.TABLE_NAME, { 'parent_id': parent_id, 'parent_type': contextType.value }) return map_objects(data) def update_node(self, node: Node): """ Update node data :param node: node """ if isinstance(node, Folder): values = {'parent_id': node.parent_id, 'name': node.name} else: values = { 'target_id': node.object.id, 'parent_id': node.parent_id, 'name': node.name } self.database.update(self.TABLE_NAME, node.id, values) def insert_node(self, node: Node, object_type: ObjectType) -> int: """ Create new node in database :param node: node object :return: id of created node """ if isinstance(node, Folder): values = { 'parent_type': object_type.value, 'parent_id': node.parent_id, 'type': NodeType.FOLDER.value, 'name': node.name } else: values = { 'target_type': node.object.object_type.value, 'parent_type': object_type.value, 'target_id': node.object.id, 'parent_id': node.parent_id, 'type': NodeType.OBJECT.value, 'name': node.name } return self.database.insert(self.TABLE_NAME, values) def delete_node(self, id: int): """ Delete node from database :param id: id of node """ self.database.delete(self.TABLE_NAME, id) def get_node_by_object(self, object: object): """ Return node based on object :param object: object that you finding :return: ObjectNode with object """ data = self.database.select(self.TABLE_NAME, { 'target_id': object.id, 'parent_type': object.object_type.value }) return self.get_node(data[0]['id'])
class MapItemDAO(IMapItemDAO): DATABASE_TABLE = 'Map_item' DATABASE_DRIVER = "file::memory:?cache=shared" TYPE = ObjectType.MAP_ITEM def __init__(self): self.database = Database(self.DATABASE_DRIVER) def create(self, mapItem: MapItem) -> int: """ Create new map item :param mapItem: Map object :return: id of created mapItem """ X = mapItem.coord.x() Y = mapItem.coord.y() values = { 'name' : mapItem.name, 'description': mapItem.description, 'number' : mapItem.number, 'scale' : mapItem.scale, 'positionX' : X, 'positionY' : Y, 'map_id' : mapItem.mapId, 'itemType' : mapItem.itemType.value } id = self.database.insert(self.DATABASE_TABLE, values) return id def update(self, mapItem: MapItem): """ Update map item in database :param mapItem: mapItem object with new data """ X = mapItem.coord.x() Y = mapItem.coord.y() values = { 'name' : mapItem.name, 'description': mapItem.description, 'number' : mapItem.number, 'scale' : mapItem.scale, 'positionX' : X, 'positionY' : Y, } self.database.update(self.DATABASE_TABLE, mapItem.id, values) def delete(self, mapitem_id: int): """ Delete Map item from database and all his translates :param mapitem_id: id of Map item """ self.database.delete(self.DATABASE_TABLE, mapitem_id) def get(self, mapitem_id: int) -> MapItem: """ Get map item from database :param mapitem_id: id of map item :return: Map item object """ data = dict(self.database.select(self.DATABASE_TABLE, {'ID': mapitem_id})[0]) coord = QPointF(data.get('positionX', 0), data.get('positionY', 0)) itemType = MapItemType(data.get('itemType')) mapitem = MapItem(mapitem_id, data.get('name', ''), data.get('description', ''), coord, data.get('scale', 0), data.get('number', 0), None, data.get('map_id'), itemType) return mapitem def get_all(self, lang=None) -> list: """ Get list of map items for selected lang :param lang: lang of map items :return: list of map items """ if lang is None: lang = SettingsDAO().get_value('language', str) lines = self.database.select_all(self.DATABASE_TABLE) mapItems = [] for line in lines: item = self.get(line['ID'], lang) mapItems.append(item) return mapItems
class PartyCharacterDAO(DAO, IPartyCharacterDAO): DATABASE_TABLE = 'PartyCharacter' TYPE = ObjectType.CHARACTER def __init__(self): self.database = Database(self.DATABASE_DRIVER) def create(self, character: PartyCharacter, nodeParentId: int = None, contextType: ObjectType = None) -> int: """ Create new PartyCharacter, if character given, linked with character and create character if character is not given, only party character created and liked with scenario :param character: PartyCharacter object :param nodeParentId: id of parent node in tree :param contextType: Object type of tree, where item is located :return: id of created character """ if not contextType: contextType = self.TYPE if character.character: if type(character.character) is dict: character_id = CharacterDAO().create( character.character.popitem()[1], nodeParentId, contextType) # TODO: default lang else: character_id = CharacterDAO().create( character.character, nodeParentId, contextType) # TODO: default lang else: character_id = None if nodeParentId: scenario = PlayerTreeDAO().get_node(nodeParentId).object else: scenario = None intValues = { 'deviceName': character.deviceName, 'MACAddress': character.MACAddress, 'character_id': character_id, 'scenario_id': scenario.id if scenario else None, 'name': character.name, } id = self.database.insert(self.DATABASE_TABLE, intValues) character.id = id for message in character.messages: message.partyCharacterId = id MessageDAO().create(message) return id def update(self, character: PartyCharacter): """ Update party PartyCharacter in database, update only party character, not Character :param character: PartyCharacter object with new data """ intValues = { 'deviceName': character.deviceName, 'MACAddress': character.MACAddress, 'name': character.name } self.database.update(self.DATABASE_TABLE, character.id, intValues) def delete(self, character_id: int): """ Delete party character from database and all his translates :param character_id: id of party character """ self.database.delete(self.DATABASE_TABLE, character_id) def get(self, character_id: int, lang: str = None, nodeId: int = None, contextType: ObjectType = None) -> PartyCharacter: """ Get Party Character by character id, object transable attributes depends on lang If nodeId and contextType is specified, whole object is returned (with all sub objects) If not specified, only basic attributes are set. :param character_id: id of Party Character :param lang: lang of object :param nodeId: id of node in tree, where object is located :param contextType: object type of tree, where is node :return: Party Character object """ if lang is None: lang = SettingsDAO().get_value('language', str) select = self.database.select(self.DATABASE_TABLE, {'character_id': character_id}) if not select: return None data = dict(select[0]) character = PartyCharacter(data.get('ID'), lang, data['name'], None, data.get('deviceName', ''), data.get('MACAddress')) messages = MessageDAO().get_by_party_character(character.id) character.messages = messages # character.character = CharacterDAO().get(data.get('character_id')) return character def get_by_id(self, partyCharacterId: int, lang: str = None) -> PartyCharacter: """ Get party character by id, without character :param partyCharacterId: party character ID :param lang: lang of object :return: Party character object """ data = dict( self.database.select(self.DATABASE_TABLE, {'ID': partyCharacterId})[0]) character = PartyCharacter(data.get('ID'), lang, data['name'], None, data.get('deviceName', ''), data.get('MACAddress')) return character def get_all(self, lang=None) -> list: """ Get list of all Party Characters from database, only one lang :param lang: lang code :return: list of Party Characters """ if lang is None: lang = SettingsDAO().get_value('language', str) lines = self.database.select_all(self.DATABASE_TABLE) characters = [] for line in lines: character = self.get(line['ID'], lang) characters.append(character) return characters
class MapDAO(DAO, IMapDAO): DATABASE_TABLE = 'Map' TYPE = ObjectType.MAP def __init__(self): self.database = Database(self.DATABASE_DRIVER) self.treeDAO = PlayerTreeDAO() def create(self, map: Map, nodeParentId: int = None, contextType: ObjectType = None) -> int: """ Create new map and create empty map image, because of exporting :param map: Map object :param nodeParentId: id of parent node in tree :param contextType: Object type of tree, where item is located :return: id of created map """ if contextType is None: contextType = self.TYPE values = { 'name': map.name if map.name else '', 'description': map.description if map.description else '', 'map_file': map.mapFile, } id = self.database.insert(self.DATABASE_TABLE, values) map.id = id node = NodeObject(None, map.name, nodeParentId, map) nodeId = self.treeDAO.insert_node(node, contextType) for mapItem in map.mapItems: mapItem.mapId = id MapItemDAO().create(mapItem) self.create_map_image(map) return id def update(self, map: Map): """ Update map in database :param map: Location object with new data """ values = { 'name': map.name, 'description': map.description, 'map_file': map.mapFile, } self.database.set_many(True) for mapItem in map.mapItems: MapItemDAO().update(mapItem) self.database.insert_many_execute() self.database.set_many(False) self.database.update(self.DATABASE_TABLE, map.id, values) def delete(self, map_id: int): """ Delete Map from database and from translate and delete all maps linked with map :param map_id: id of Map """ map = self.get(map_id) self.database.delete(self.DATABASE_TABLE, map_id) os.remove(map.mapFile) os.remove('resources/maps/exportedMap-1.png') def get(self, map_id: int, lang: str = None, nodeId: int = None, contextType: ObjectType = None) -> Map: """ Get Map , object transable attributes depends on lang If nodeId and contextType is specified, whole object is returned (with all sub objects) If not specified, only basic attributes are set. :param map_id: id of Map :param lang: lang of object :param nodeId: id of node in tree, where object is located :param contextType: object type of tree, where is node :return: Map object """ data = self.database.select(self.DATABASE_TABLE, {'ID': map_id}) if not data: return None else: data = dict(data[0]) map = Map(map_id, None, data.get('name', ' '), data.get('description', ' '), data.get('map_file', None)) sql = self.database.select('Map_item', {'map_id': map.id}) map.XMLMap = 'map-{}.png'.format(map_id) mapItems = [] for line in sql: mapItem = MapItemDAO().get(line['ID']) mapItems.append(mapItem) map.mapItems = mapItems return map def get_all(self, lang=None) -> list: """ Get list of maps for selected lang :param lang: lang of maps :return: list of maps """ if lang is None: lang = SettingsDAO().get_value('language', str) lines = self.database.select_all(self.DATABASE_TABLE) maps = [] for line in lines: item = self.get(line['ID'], lang) maps.append(item) return maps def create_map_image(self, map: Map) -> None: """ Create empty image for map, important because of exporting :param map: map object """ from PyQt5.QtWidgets import QGraphicsView from PyQt5.QtWidgets import QGraphicsScene from PyQt5.QtGui import QPainter, QPixmap from PyQt5.QtGui import QImage from presentation.widgets.MapWidget import MapItemDraw grview = QGraphicsView() grview.setRenderHints(grview.renderHints() | QPainter.Antialiasing | QPainter.SmoothPixmapTransform) scene = QGraphicsScene() grview.setScene(scene) if not map.mapFile: mapFile = 'resources/icons/no_map.png' else: mapFile = map.mapFile pixMap = QPixmap(mapFile) sceneMap = scene.addPixmap(pixMap) for num, mapItem in enumerate(map.mapItems): mapItem.number = num + 1 item = MapItemDraw(mapItem, None) scene.addItem(item) # self.map.addMapItemDraws(item) scene.setSceneRect(scene.itemsBoundingRect()) img = QImage(scene.sceneRect().size().toSize(), QImage.Format_ARGB32) painter = QPainter(img) scene.render(painter) name = 'resources/maps/exportedMap-{}.png'.format(map.id) img.save(name) del painter
class MessageDAO(DAO, IMessageDAO): DATABASE_TABLE = 'Message' TYPE = ObjectType.MESSAGE def __init__(self): self.database = Database(self.DATABASE_DRIVER) def create(self, message: Message) -> int: """ Create new message in database :param message: Message object :return: id of autoincrement """ curDate = datetime.strptime(message.date, '%d/%m/%Y %H:%M:%S') if message.date else None if type(message.isMine) is str: isMine = True if message.isMine == 'true' else False else: isMine = message.isMine intValues = { 'text' : message.text, 'date' : curDate.toordinal() if curDate else None, 'isMine' : int(isMine), 'characterId' : message.characterId, 'partyCharacterId': message.partyCharacterId } id = self.database.insert(self.DATABASE_TABLE, intValues) message.id = id return id def update(self, message: Message): """ Update message in database :param message: Message object with new data """ if type(message.isMine) is str: isMine = True if message.isMine == 'true' else False else: isMine = message.isMine intValues = { 'text' : message.text, 'date' : message.date.toordinal(), 'isMine': int(isMine) } self.database.update(self.DATABASE_TABLE, message.id, intValues) def delete(self, message_id: int): """ Delete Message from database and all his translates :param message_id: id of Message """ self.database.delete(self.DATABASE_TABLE, message_id) def get(self, message_id: int, lang: str = None) -> Message: """ Get Message from database :param message_id: id of Message :param lang: lang of spell :return: Message object """ if lang is None: lang = SettingsDAO().get_value('language', str) data = dict(self.database.select(self.DATABASE_TABLE, {'ID': message_id})[0]) curDate = datetime.fromordinal(data.get('date')) if data.get('date') else None message = Message(message_id, data['text'], curDate, bool(data['isMine']), data.get('partyCharacterId'), data.get('characterId')) return message def get_by_party_character(self, partyCharacterId: int) -> list: """ Get all messages for one party character :param partyCharacterId: id of party character :return: list of Messages """ select = self.database.select(self.DATABASE_TABLE, {'partyCharacterId': partyCharacterId}) messages = [] for one in select: data = dict(one) curDate = date.fromordinal(data.get('date')) if data.get('date') else None message = Message(data.get('id'), data.get('text', ''), curDate, bool(data['isMine']), data.get('partyCharacterId'), None) messages.append(message) return messages def get_all(self, lang=None) -> list: """ Get list of all messages from database, only one lang :param lang: lang code :return: list of messages """ if lang is None: lang = SettingsDAO().get_value('language', str) lines = self.database.select_all(self.DATABASE_TABLE) characters = [] for line in lines: character = self.get(line['ID'], lang) characters.append(character) return characters