parent
							
								
									a179ed4fb6
								
							
						
					
					
						commit
						99069ba77d
					
				@ -0,0 +1,376 @@
 | 
				
			|||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from hashlib import md5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5.QtWidgets import QApplication
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.db.db_adapter import DBAdapter
 | 
				
			||||||
 | 
					from ArtNet.file.file_reader import FileReader
 | 
				
			||||||
 | 
					from ArtNet.file.config_reader import ConfigReader
 | 
				
			||||||
 | 
					from ArtNet.gui.window import Window
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.db_connection_dialog.db_dialog import DBDialog
 | 
				
			||||||
 | 
					from ArtNet.web.link_generator import LinkGenerator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ArtNetManager:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, config_location: str = "."):
 | 
				
			||||||
 | 
					        self.config = ConfigReader(config_location, "somePassword")
 | 
				
			||||||
 | 
					        self.db_connection = None
 | 
				
			||||||
 | 
					        self.__app = QApplication(sys.argv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while self.db_connection is None:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                self.db_connection = self.create_db_connection(user=self.config.data["db"]["user"],
 | 
				
			||||||
 | 
					                                                               password=self.config.data["db"]["password"],
 | 
				
			||||||
 | 
					                                                               host=self.config.data["db"]["host"],
 | 
				
			||||||
 | 
					                                                               port=self.config.data["db"]["port"],
 | 
				
			||||||
 | 
					                                                               database=self.config.data["db"]["database"])
 | 
				
			||||||
 | 
					            except ValueError as e:  # db connection didn't work
 | 
				
			||||||
 | 
					                print(e)
 | 
				
			||||||
 | 
					                dialog = DBDialog()
 | 
				
			||||||
 | 
					                prev_db_data = self.get_db_connection_details()
 | 
				
			||||||
 | 
					                dialog.ui.user_line_edit.setText(prev_db_data["user"])
 | 
				
			||||||
 | 
					                dialog.ui.password_line_edit.setText(prev_db_data["password"])
 | 
				
			||||||
 | 
					                dialog.ui.host_line_edit.setText(prev_db_data["host"])
 | 
				
			||||||
 | 
					                dialog.ui.database_line_edit.setText(prev_db_data["database"])
 | 
				
			||||||
 | 
					                dialog.ui.port_line_edit.setText(str(prev_db_data["port"]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                db_data: dict = dialog.exec_()
 | 
				
			||||||
 | 
					                if len(db_data.keys()) == 0:
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					                self.change_db_connection(host=db_data["host"], port=db_data["port"],
 | 
				
			||||||
 | 
					                                                 user=db_data["user"], password=db_data["password"],
 | 
				
			||||||
 | 
					                                                 database=db_data["database"])
 | 
				
			||||||
 | 
					        self.window = Window(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # TODO prompt for overwriting config when password invalid
 | 
				
			||||||
 | 
					        # TODO sane default location
 | 
				
			||||||
 | 
					        # TODO tag editor, don't kill dialog if fields are missing
 | 
				
			||||||
 | 
					        # TODO display Tag Category when searching for tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # TODO remove string limit restrictions on implications & similar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__file_root: str = None
 | 
				
			||||||
 | 
					        self.window.on_artnet_root_change_clicked()
 | 
				
			||||||
 | 
					        self.__file_reader = FileReader(self.__file_root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.curr_image_index: int = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.all_images: list = None
 | 
				
			||||||
 | 
					        self.update_all_images_list()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.window.set_temporary_status_message("Hello o7", 5000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        if len(self.all_images) > 0:
 | 
				
			||||||
 | 
					            self.curr_image_index = 0
 | 
				
			||||||
 | 
					        self.change_image()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.window.show()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sys.exit(self.__app.exec_())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_all_images_list(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Updates the internal list of all images in the artnet root
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        images = []
 | 
				
			||||||
 | 
					        artist_list = self.__file_reader.list_artists()
 | 
				
			||||||
 | 
					        artist_list.sort()
 | 
				
			||||||
 | 
					        for artist in artist_list:
 | 
				
			||||||
 | 
					            for image in self.__file_reader.get_files(artist):
 | 
				
			||||||
 | 
					                images.append(image)
 | 
				
			||||||
 | 
					        self.all_images = images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.known_image_amount = 0
 | 
				
			||||||
 | 
					        for image in self.all_images:
 | 
				
			||||||
 | 
					            if self.db_connection.get_art_by_path(image) is not None:
 | 
				
			||||||
 | 
					                self.known_image_amount += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def scrape_tags(self, file_name: str, art_ID: int, url: str=None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Scrape the tags from the given url and return which one's are new
 | 
				
			||||||
 | 
					        :param file_name:
 | 
				
			||||||
 | 
					        :param art_ID:
 | 
				
			||||||
 | 
					        :param url:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if url is None:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #tags = ArtNet.web.Scrap_Tags.scrap_tags(file_name, url, ArtNet.web.link_generator.predict_domain(file_name))
 | 
				
			||||||
 | 
					        tags = LinkGenerator.get_instance().scrape_tags(url, LinkGenerator.get_instance().predict_domain(file_name))
 | 
				
			||||||
 | 
					        if tags is None:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        already_applied_tags = self.db_connection.get_art_tags_by_ID(art_ID)
 | 
				
			||||||
 | 
					        for i in range(len(already_applied_tags)):
 | 
				
			||||||
 | 
					            already_applied_tags[i] = self.db_connection.get_tag_by_ID(already_applied_tags[i])[0][1].strip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        importable_tags = []
 | 
				
			||||||
 | 
					        importable_artists = []
 | 
				
			||||||
 | 
					        scraped_tags = []
 | 
				
			||||||
 | 
					        for i in tags.values():
 | 
				
			||||||
 | 
					            scraped_tags += i
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in scraped_tags:
 | 
				
			||||||
 | 
					            result = self.db_connection.get_tag_by_name(tag)
 | 
				
			||||||
 | 
					            if len(result) == 0:  # tag does not exist yet
 | 
				
			||||||
 | 
					                if tag in tags['artists']:
 | 
				
			||||||
 | 
					                    importable_artists.append(tag)
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                importable_tags.append(tag)
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if tag in already_applied_tags:  # tag is already applied
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            result = self.db_connection.get_tag_impliers(tag)
 | 
				
			||||||
 | 
					            if len(result) != 0:  # tag is implied by some other tag
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            result = self.db_connection.get_tag_aliases(tag)
 | 
				
			||||||
 | 
					            if len(result) != 0:  # tag is already tagged by an alias
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if tag in tags['artists']:
 | 
				
			||||||
 | 
					                importable_artists.append(tag)
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            importable_tags.append(tag)  # tag must be known and not tagged yet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return importable_tags, importable_artists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def import_tags(self, art_ID: int, tags):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Add a list of given tags to the specified art_ID
 | 
				
			||||||
 | 
					        :param art_ID:
 | 
				
			||||||
 | 
					        :param tags:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        for tag in tags:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if len(self.db_connection.get_tag_by_name(tag)) == 0:  # tag doesn't exist yet
 | 
				
			||||||
 | 
					                result = self.window.force_edit_tag_dialog(name=tag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if result is None:  # tag creation was aborted
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                tag = result['name']  # overwrite with possibly new tag name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            tag = self.db_connection.get_tag_by_name(tag)[0][0]
 | 
				
			||||||
 | 
					            self.window.curr_tags.append(tag)
 | 
				
			||||||
 | 
					            self.window.data_changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_md5_of_image(self, path: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Calculate the md5 hash of the image given by the path.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param path: assumed to be relative e.g. artist_A/image.jpg
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        md5_hash = md5()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            with open(self.get_root() + os.path.sep + path,
 | 
				
			||||||
 | 
					                      "rb") as file:  # read file part by part because of potential memory limits
 | 
				
			||||||
 | 
					                for chunk in iter(lambda: file.read(4096), b""):
 | 
				
			||||||
 | 
					                    md5_hash.update(chunk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return md5_hash.hexdigest()
 | 
				
			||||||
 | 
					        except FileNotFoundError:
 | 
				
			||||||
 | 
					            self.update_all_images_list()
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete_image(self, path: str, delete_instead_of_move: bool = False, trash_bin_folder_path: str = "trash"):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Deletes the image from the root folder
 | 
				
			||||||
 | 
					        :param path:
 | 
				
			||||||
 | 
					        :param delete_instead_of_move:
 | 
				
			||||||
 | 
					        :param trash_bin_folder_path:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        full_art_path = self.get_root() + os.path.sep + path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if delete_instead_of_move:
 | 
				
			||||||
 | 
					            print(f"Deleting the actual file {full_art_path} is disabled for now")
 | 
				
			||||||
 | 
					            #os.remove(full_art_path)
 | 
				
			||||||
 | 
					            #return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        trash_dst = trash_bin_folder_path + os.path.sep + path
 | 
				
			||||||
 | 
					        t_splits = trash_dst.split(os.path.sep)
 | 
				
			||||||
 | 
					        t_path = ""
 | 
				
			||||||
 | 
					        for i in range(len(t_splits)-1):
 | 
				
			||||||
 | 
					            t_path += os.path.sep + t_splits[i]
 | 
				
			||||||
 | 
					        t_path = t_path[1:]
 | 
				
			||||||
 | 
					        if not os.path.exists(t_path):
 | 
				
			||||||
 | 
					            print(f"{t_path} did not exist and will be created!")
 | 
				
			||||||
 | 
					            os.makedirs("."+os.path.sep+t_path)
 | 
				
			||||||
 | 
					        os.rename(full_art_path, trash_dst)
 | 
				
			||||||
 | 
					        print(f"Moving image {full_art_path} to {trash_dst}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.update_all_images_list()
 | 
				
			||||||
 | 
					        while self.curr_image_index >= len(self.all_images):
 | 
				
			||||||
 | 
					            self.curr_image_index -= 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @DeprecationWarning
 | 
				
			||||||
 | 
					    def recalculate_hash_for_known_images(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Calculate and write the md5 hash for every image known to the database.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Important: For migration purposes only
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        for i in range(len(self.all_images)):
 | 
				
			||||||
 | 
					            image_db_result = self.db_connection.get_art_by_path(self.all_images[i])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if image_db_result is None:  # unknown image, skip
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            hash_digest = self.get_md5_of_image(self.all_images[i])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            authors = self.db_connection.get_authors_of_art(path=image_db_result["path"])
 | 
				
			||||||
 | 
					            tag_ids = self.db_connection.get_art_tags_by_ID(art_ID=image_db_result["ID"])
 | 
				
			||||||
 | 
					            tags = []
 | 
				
			||||||
 | 
					            for tag_id in tag_ids:
 | 
				
			||||||
 | 
					                tags.append(self.db_connection.get_tag_by_ID(tag_id)[0][1].strip())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.db_connection.save_image(ID=image_db_result["ID"], path=image_db_result["path"],
 | 
				
			||||||
 | 
					                                          title=image_db_result["title"],
 | 
				
			||||||
 | 
					                                          link=image_db_result["link"], authors=authors, md5_hash=hash_digest,
 | 
				
			||||||
 | 
					                                          tags=tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_next_unknown_image(self) -> int:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search all images for the next image not known to the database in ascending order.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :return: index of the next unknown image, None if there is no unknown image
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        next_unknown: int = None
 | 
				
			||||||
 | 
					        curr_searched_image_index = self.curr_image_index + 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        finished_loop = False
 | 
				
			||||||
 | 
					        while next_unknown is None and not finished_loop:
 | 
				
			||||||
 | 
					            if curr_searched_image_index >= len(self.all_images):  # wrap around to the start
 | 
				
			||||||
 | 
					                curr_searched_image_index = 0
 | 
				
			||||||
 | 
					            if curr_searched_image_index == self.curr_image_index:  # searched all images, nothing unknown
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            image_db_result = self.db_connection.get_art_by_path(self.all_images[curr_searched_image_index])
 | 
				
			||||||
 | 
					            if image_db_result is None:
 | 
				
			||||||
 | 
					                image_db_result = self.db_connection.get_art_by_hash(
 | 
				
			||||||
 | 
					                    self.get_md5_of_image(self.all_images[curr_searched_image_index])
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if image_db_result is None:  # image is unknown to database
 | 
				
			||||||
 | 
					                next_unknown = curr_searched_image_index
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                curr_searched_image_index += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if next_unknown:
 | 
				
			||||||
 | 
					            return curr_searched_image_index
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_prev_unknown_image(self) -> int:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search all images for the next image not known to the databse in descending order.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :return:index of the next unknown image, None if there is no unknown image
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        next_unknown: int = None
 | 
				
			||||||
 | 
					        curr_searched_image_index = self.curr_image_index - 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        finished_loop = False
 | 
				
			||||||
 | 
					        while next_unknown is None and not finished_loop:
 | 
				
			||||||
 | 
					            if curr_searched_image_index <= 0:  # wrap around to the end
 | 
				
			||||||
 | 
					                curr_searched_image_index = len(self.all_images) - 1
 | 
				
			||||||
 | 
					            if curr_searched_image_index == self.curr_image_index:  # searched all images, nothing unknown
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            image_db_result = self.db_connection.get_art_by_path(self.all_images[curr_searched_image_index])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if image_db_result is None:  # image is unknown to database
 | 
				
			||||||
 | 
					                next_unknown = curr_searched_image_index
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                curr_searched_image_index -= 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if next_unknown:
 | 
				
			||||||
 | 
					            return curr_searched_image_index
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def change_image(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Refresh the image display to show the most current data according to the selected image
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.window.setting_up_data = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        image_db_result = self.db_connection.get_art_by_hash(
 | 
				
			||||||
 | 
					            self.get_md5_of_image(self.all_images[self.curr_image_index])
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        #image_db_result = self.db_connection.get_art_by_path(self.all_images[self.curr_image_index])
 | 
				
			||||||
 | 
					        s = self.all_images[self.curr_image_index].split(os.path.sep)
 | 
				
			||||||
 | 
					        if image_db_result is not None:
 | 
				
			||||||
 | 
					            image_title = image_db_result["title"] if len(image_db_result["title"]) > 0 else "-Title Unknown-"
 | 
				
			||||||
 | 
					            image_author = self.db_connection.get_authors_of_art_by_ID(image_db_result["ID"])
 | 
				
			||||||
 | 
					            image_link = image_db_result["link"]
 | 
				
			||||||
 | 
					            art_ID = image_db_result["ID"]
 | 
				
			||||||
 | 
					            if image_author is None or len(image_author) == 0:
 | 
				
			||||||
 | 
					                image_author = [(self.all_images[self.curr_image_index].split(os.path.sep)[0], "(Not in Database)")]
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            art_ID = None
 | 
				
			||||||
 | 
					            image_author = [(s[0], "(Not in Database)")]
 | 
				
			||||||
 | 
					            image_title = s[-1] + " (Not in Database)"
 | 
				
			||||||
 | 
					            image_link = "(Unknown)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print("Displaying", self.all_images[self.curr_image_index])
 | 
				
			||||||
 | 
					        self.window.display_image(image_title, image_author,
 | 
				
			||||||
 | 
					                                  os.path.join(self.__file_root, self.all_images[self.curr_image_index]),
 | 
				
			||||||
 | 
					                                  self.all_images[self.curr_image_index],
 | 
				
			||||||
 | 
					                                  art_ID, image_link, file_name=s[-1])
 | 
				
			||||||
 | 
					        self.window.set_tag_list([self.db_connection.get_tag_by_ID(x)[0][1].strip() for x in self.db_connection.get_art_tags_by_ID(art_ID)])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.window.data_changed = False
 | 
				
			||||||
 | 
					        self.window.setting_up_data = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_db_connection(self, host: str, port: int, database: str, user: str, password: str) -> DBAdapter:
 | 
				
			||||||
 | 
					        print("Changing db connection to ".format(host, port, user, password))
 | 
				
			||||||
 | 
					        return DBAdapter(user=user, password=password, host=host, port=port, database=database)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_root(self) -> str:
 | 
				
			||||||
 | 
					        return self.__file_root
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def change_root(self, path: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Change the Artnet root path and confirm it is working.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Rewrite config there
 | 
				
			||||||
 | 
					        :param path:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if len(path) == 0:
 | 
				
			||||||
 | 
					            exit(0)
 | 
				
			||||||
 | 
					        print("Changing root to", path)
 | 
				
			||||||
 | 
					        self.__file_root = path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_db_connection_details(self) -> dict:
 | 
				
			||||||
 | 
					        return self.config.data["db"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def change_db_connection(self, host: str, port: int, database: str, user: str, password: str):
 | 
				
			||||||
 | 
					        self.config.data["db"]["user"] = user
 | 
				
			||||||
 | 
					        self.config.data["db"]["password"] = password
 | 
				
			||||||
 | 
					        self.config.data["db"]["host"] = host
 | 
				
			||||||
 | 
					        self.config.data["db"]["database"] = database
 | 
				
			||||||
 | 
					        self.config.data["db"]["port"] = str(port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.config.update_config()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db_connection = self.create_db_connection(host, port, database, user, password)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,853 @@
 | 
				
			|||||||
 | 
					import psycopg2
 | 
				
			||||||
 | 
					from psycopg2.errors import *
 | 
				
			||||||
 | 
					from psycopg2.errorcodes import UNIQUE_VIOLATION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DBAdapter:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, user: str, password: str, host: str = "localhost", port: int = 5432, database: str = "artnet"):
 | 
				
			||||||
 | 
					        self.db = None
 | 
				
			||||||
 | 
					        self.db_cursor = None
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.db = psycopg2.connect(host=host, port=port, database=database, user=user, password=password)
 | 
				
			||||||
 | 
					            self.db_cursor = self.db.cursor()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        except psycopg2.OperationalError as e:
 | 
				
			||||||
 | 
					            raise ValueError("Invalid DB credentials!")
 | 
				
			||||||
 | 
					        print("DB connection to {0}:{1}/{2}".format(host, port, database))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_image(self, ID: str, title: str, authors: list, path: str, tags: list, link: str, md5_hash: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Updates or saves the given image data to the DB
 | 
				
			||||||
 | 
					        :param ID:
 | 
				
			||||||
 | 
					        :param title:
 | 
				
			||||||
 | 
					        :param authors:
 | 
				
			||||||
 | 
					        :param path:
 | 
				
			||||||
 | 
					        :param tags:
 | 
				
			||||||
 | 
					        :param link:
 | 
				
			||||||
 | 
					        :param md5_hash: md5 hash as a hex digest
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        print("Saving Image {0}:{1} authors: {2} path: {3} tags: {4} link: {5} hash:{6}"
 | 
				
			||||||
 | 
					              .format(ID, title, authors, path, tags, link, md5_hash))
 | 
				
			||||||
 | 
					        d = {"title": title, "path": path, "id": ID, "link": link, "hash": md5_hash}
 | 
				
			||||||
 | 
					        if self.get_art_by_path(path) is None:
 | 
				
			||||||
 | 
					            if ID is None:
 | 
				
			||||||
 | 
					                self.db_cursor.execute(
 | 
				
			||||||
 | 
					                    "INSERT INTO art (path, title, link, md5_hash) VALUES (%(path)s, %(title)s, %(link)s, %(hash)s)",
 | 
				
			||||||
 | 
					                    d)
 | 
				
			||||||
 | 
					                ID = self.get_art_by_path(path)["ID"]
 | 
				
			||||||
 | 
					                d["id"] = ID
 | 
				
			||||||
 | 
					            elif self.get_tag_by_ID(ID) is None:
 | 
				
			||||||
 | 
					                self.db_cursor.execute(
 | 
				
			||||||
 | 
					                    "INSERT INTO art (path, title, link, md5_hash) VALUES (%(path)s, %(title)s, %(link)s, %(hash)s)", d)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.db_cursor.execute("UPDATE art SET path = %(path)s, title = %(title)s, link = %(link)s, " +
 | 
				
			||||||
 | 
					                                   "md5_hash = %(hash)s WHERE id = %(id)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ID is None:
 | 
				
			||||||
 | 
					            ID = self.get_art_by_path(path)["ID"]
 | 
				
			||||||
 | 
					            assert(ID != None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        old_tags = [self.get_tag_by_ID(x)[0][1].strip() for x in self.get_art_tags_by_ID(ID)]
 | 
				
			||||||
 | 
					        for tag in tags:
 | 
				
			||||||
 | 
					            if tag in old_tags:  # already present
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            d = {"id": ID, "tag": self.get_tag_ID(tag)}
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                self.db_cursor.execute("INSERT INTO art_tag (art_id, tag_ID) VALUES (%(id)s, %(tag)s)", d)
 | 
				
			||||||
 | 
					            except psycopg2.Error as e:
 | 
				
			||||||
 | 
					                if e.pgcode == UNIQUE_VIOLATION:
 | 
				
			||||||
 | 
					                    print(e)
 | 
				
			||||||
 | 
					                    print("Skipping Unique Violation ...")
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    raise e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for old_tag in old_tags:
 | 
				
			||||||
 | 
					            if old_tag not in tags:  # need to remove old tag
 | 
				
			||||||
 | 
					                self.remove_tag_from_image(art_ID=ID, tag_ID=self.get_tag_ID(old_tag))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        old_authors = self.get_authors_of_art_by_ID(ID)
 | 
				
			||||||
 | 
					        for author in authors:
 | 
				
			||||||
 | 
					            if author in old_authors:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            d = {"id": ID, "author_name": author[0], "author_domain": author[1]}
 | 
				
			||||||
 | 
					            self.db_cursor.execute("INSERT INTO art_author (presence_name, presence_domain, art_ID) " +
 | 
				
			||||||
 | 
					                                   "VALUES (%(author_name)s, %(author_domain)s, %(id)s)", d)
 | 
				
			||||||
 | 
					        for old_author_name, old_author_domain in old_authors:
 | 
				
			||||||
 | 
					            if (old_author_name, old_author_domain) not in authors:  # need to remove old author
 | 
				
			||||||
 | 
					                self.remove_artist_from_image(art_ID=ID, presence_name=old_author_name,
 | 
				
			||||||
 | 
					                                              presence_domain=old_author_domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_image(self, hash: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Removes an image completely from the database.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Does not affect tags or artists but removes art-tag, art-artist relations
 | 
				
			||||||
 | 
					        :param hash: md5 hash of the image to be deleted
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        image_data = self.get_art_by_hash(hash)
 | 
				
			||||||
 | 
					        art_ID = image_data["ID"]
 | 
				
			||||||
 | 
					        print(f"Deleting image #{art_ID} {image_data['title']}")
 | 
				
			||||||
 | 
					        tags = self.get_art_tags_by_ID(art_ID)
 | 
				
			||||||
 | 
					        for tag_ID in tags:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					            #self.remove_tag_from_image(art_ID=art_ID, tag_ID=tag_ID)
 | 
				
			||||||
 | 
					        authors = self.get_authors_of_art_by_ID(art_ID)
 | 
				
			||||||
 | 
					        for presence_name, presence_domain in authors:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					            #self.remove_artist_from_image(art_ID=art_ID, presence_name=presence_name, presence_domain=presence_domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        #self.db_cursor.execute("DELETE FROM art WHERE md5_hash = %(hash)s", {"hash": hash})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_artist_from_image(self, art_ID, presence_name, presence_domain):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Removes the relationship between an artist and the image
 | 
				
			||||||
 | 
					        :param art_ID:
 | 
				
			||||||
 | 
					        :param presence_name:
 | 
				
			||||||
 | 
					        :param presence_domain:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"name": presence_name, "domain": presence_domain, "id": art_ID}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("DELETE FROM art_author " +
 | 
				
			||||||
 | 
					                               "WHERE presence_name = %(name)s and " +
 | 
				
			||||||
 | 
					                               "presence_domain = %(domain)s and art_ID = %(id)s",
 | 
				
			||||||
 | 
					                               d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_tag_from_image(self, art_ID, tag_ID):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Remove the relationship between a tag and the image
 | 
				
			||||||
 | 
					        :param art_ID:
 | 
				
			||||||
 | 
					        :param tag_ID:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"id": art_ID, "tag": tag_ID}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("DELETE FROM art_tag WHERE art_id = %(id)s and tag_id = %(tag)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_presence(self, name: str, domain: str, artist_ID: int, link: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Save the presence entry with the given data.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If it doesn't exist a new one will be created.
 | 
				
			||||||
 | 
					        If the artist ID is unknown an exception will be thrown
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :param artist_ID:
 | 
				
			||||||
 | 
					        :param link:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        print("Saving Presence {0}:{1} Artist: {2} Link: {3}".format(name, domain, artist_ID, link))
 | 
				
			||||||
 | 
					        artist = self.get_artist(artist_ID)
 | 
				
			||||||
 | 
					        if artist is None or len(artist) == 0:
 | 
				
			||||||
 | 
					            raise Exception("Unknown Artist to create/update Presence with!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        presence = self.get_presence(name, domain)
 | 
				
			||||||
 | 
					        d = {"name": name, "domain": domain, "artist": artist_ID, "link": link}
 | 
				
			||||||
 | 
					        if len(presence) == 0:  # presence does not exist yet
 | 
				
			||||||
 | 
					            self.db_cursor.execute("INSERT INTO presence (name, domain, artist, link) " +
 | 
				
			||||||
 | 
					                                   "VALUES (%(name)s, %(domain)s, %(artist)s, %(link)s)", d)
 | 
				
			||||||
 | 
					        else:  # presence exists, update it
 | 
				
			||||||
 | 
					            self.db_cursor.execute("UPDATE presence SET artist = %(artist)s, link = %(link)s" +
 | 
				
			||||||
 | 
					                                   "WHERE name = %(name)s and domain = %(domain)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_presence(self, name: str, domain: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Remove a presence from the database
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        print("Removing Presence {0}:{1}".format(name, domain))
 | 
				
			||||||
 | 
					        d = {"name": name, "domain": domain}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("DELETE FROM presence WHERE name = %(name)s and domain = %(domain)s", d)
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_presence(self, name: str, domain: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Queries the database for the presence and returns the result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"name": name, "domain": domain}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT name, domain, artist, link FROM presence " +
 | 
				
			||||||
 | 
					                               "WHERE name = %(name)s and domain = %(domain)s",
 | 
				
			||||||
 | 
					                               d)
 | 
				
			||||||
 | 
					        rows = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					        new_rows = []
 | 
				
			||||||
 | 
					        for row in rows:
 | 
				
			||||||
 | 
					            new_rows.append((row[0].strip(), row[1].strip(), row[2], row[3]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new_rows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_artist(self, ID: int, description: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Save (or update if ID is already taken) an artist to the DB
 | 
				
			||||||
 | 
					        :param ID:
 | 
				
			||||||
 | 
					        :param description:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        print("Saving artist {0}:{1}".format(ID, description))
 | 
				
			||||||
 | 
					        d = {"id": ID, "description": description}
 | 
				
			||||||
 | 
					        if ID is None:  # no ID given, auto generate it
 | 
				
			||||||
 | 
					            self.db_cursor.execute("INSERT INTO artist (description) VALUES (%(description)s)", d)
 | 
				
			||||||
 | 
					        elif len(self.get_artist(ID)) != 0:  # artist exists already:
 | 
				
			||||||
 | 
					            self.db_cursor.execute("UPDATE artist SET description = %(description)s WHERE id = %(id)s", d)
 | 
				
			||||||
 | 
					        else:  # artist needs to be created
 | 
				
			||||||
 | 
					            self.db_cursor.execute("INSERT INTO artist (id, description) VALUES (%(id)s, %(description)s)", d)
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_artist(self, ID: int):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Deletes the artist from the DB
 | 
				
			||||||
 | 
					        :param ID:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        print("Deleting artist {0}".format(ID))
 | 
				
			||||||
 | 
					        d = {"id": ID}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("DELETE FROM Artist WHERE ID = %(id)s", d)
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_category(self, name: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Save the category to the DB.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Does not check if the category already exists
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        print("Saving category {0}!".format(name))
 | 
				
			||||||
 | 
					        d = {"name": name}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("INSERT INTO tag_category (name) VALUES (%(name)s)", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_category(self, name: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Remove the category from the DB.
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"name": name}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("DELETE FROM tag_category WHERE name = %(name)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_artist(self, ID: int):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Queries the database for the artist (not presence) and returns the result
 | 
				
			||||||
 | 
					        :param ID:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"id": ID}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT id, description FROM artist WHERE id = %(id)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_artist_presences(self, id: int):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Queries the databse for all presences associated with the artist and returns the result
 | 
				
			||||||
 | 
					        :param id:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"id": id}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT name, domain, artist FROM Presence WHERE artist = %(id)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_all_artists(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Lists all available artists (not presences) and returns the result
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT id, description FROM artist")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_art_by_hash(self, file_hash: str) -> dict:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Queries the database for the art via its hash and returns it if available.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Currently uses an md5 hash
 | 
				
			||||||
 | 
					        :param file_hash:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"hash": file_hash}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT id, path, title, link, md5_hash FROM art where md5_hash = %(hash)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(result) == 0:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            result = result[0]
 | 
				
			||||||
 | 
					            image_data = {
 | 
				
			||||||
 | 
					                "ID": result[0],
 | 
				
			||||||
 | 
					                "path": result[1],
 | 
				
			||||||
 | 
					                "title": result[2],
 | 
				
			||||||
 | 
					                "link": result[3],
 | 
				
			||||||
 | 
					                "md5_hash": result[4],
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return image_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_art_by_path(self, path: str) -> dict:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Queries the database for the art via its path and returns it if available.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Otherwise None
 | 
				
			||||||
 | 
					        :param path:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"path": path}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT id, path, title, link, md5_hash FROM art where path = %(path)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(result) == 0:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            result = result[0]
 | 
				
			||||||
 | 
					            image_data = {
 | 
				
			||||||
 | 
					                "ID": result[0],
 | 
				
			||||||
 | 
					                "path": result[1],
 | 
				
			||||||
 | 
					                "title": result[2],
 | 
				
			||||||
 | 
					                "link": result[3],
 | 
				
			||||||
 | 
					                "md5_hash": result[4],
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return image_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @DeprecationWarning
 | 
				
			||||||
 | 
					    def get_authors_of_art(self, path: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Get the authors (presence and author) of the given art.
 | 
				
			||||||
 | 
					        :param path:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        art_data = self.get_art_by_path(path)
 | 
				
			||||||
 | 
					        art_id: int = None
 | 
				
			||||||
 | 
					        if art_data is not None:
 | 
				
			||||||
 | 
					            art_id = art_data["ID"]
 | 
				
			||||||
 | 
					        if art_id is None:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        d = {"id": art_id}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT presence_name, presence_domain FROM art_author WHERE art_ID = %(id)s", d)
 | 
				
			||||||
 | 
					        presences = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = []
 | 
				
			||||||
 | 
					        for name, domain in presences:
 | 
				
			||||||
 | 
					            result.append((name.strip(), domain.strip()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_authors_of_art_by_ID(self, id: int):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Get the authors (presence and author) of the given art.
 | 
				
			||||||
 | 
					        :param id:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"id": id}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT presence_name, presence_domain FROM art_author WHERE art_ID = %(id)s", d)
 | 
				
			||||||
 | 
					        presences = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = []
 | 
				
			||||||
 | 
					        for name, domain in presences:
 | 
				
			||||||
 | 
					            result.append((name.strip(), domain.strip()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_art_tags_by_ID(self, art_ID: int):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query the database for all tags associated with a given art ID
 | 
				
			||||||
 | 
					        :param art_ID:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"id": art_ID}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT tag_ID FROM art_tag WHERE art_id = %(id)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					        new_rows = []
 | 
				
			||||||
 | 
					        for row in rows:
 | 
				
			||||||
 | 
					            new_rows.append(row[0])
 | 
				
			||||||
 | 
					        return new_rows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def search_fuzzy_presence(self, name: str, domain: str, all_if_empty: bool = False):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search a list of presences fitting the (name, domain) fuzzy.
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :param all_if_empty:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if all_if_empty and (name is None or len(name) == 0) and (domain is None or len(domain) == 0):
 | 
				
			||||||
 | 
					            self.db_cursor.execute("SELECT name, domain, artist FROM presence")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.db_cursor.execute("SELECT name, domain, artist FROM presence WHERE LOWER(name) LIKE LOWER('%{0}%')".format(name) +
 | 
				
			||||||
 | 
					                                   " AND domain LIKE '%{0}%'".format(domain))
 | 
				
			||||||
 | 
					        rows = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = []
 | 
				
			||||||
 | 
					        for row in rows:
 | 
				
			||||||
 | 
					            result.append((row[0].strip(), row[1].strip()))
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_presences_art(self, name, domain):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query a list of all art that includes the given presence as their author
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"name": name, "domain": domain}
 | 
				
			||||||
 | 
					        self.db_cursor.execute(
 | 
				
			||||||
 | 
					            "SELECT art_ID FROM Art_Author WHERE presence_name = %(name)s and presence_domain = %(domain)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_all_categories(self) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Return all categories in the database.
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT name FROM tag_category")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows = []
 | 
				
			||||||
 | 
					        for row in self.db_cursor.fetchall():
 | 
				
			||||||
 | 
					            rows.append(row[0].strip())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return rows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def search_fuzzy_categories(self, search: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search a list of categories fitting search fuzzy.
 | 
				
			||||||
 | 
					        :param search:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT name FROM tag_category WHERE LOWER(name) LIKE LOWER('%{0}%')".format(search))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows = []
 | 
				
			||||||
 | 
					        for row in self.db_cursor.fetchall():
 | 
				
			||||||
 | 
					            rows.append(row[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return rows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def search_fuzzy_tag(self, name: str, all_if_empty: bool = False) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search a list of tags fitting name fuzzy.
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param all_if_empty:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if all_if_empty and len(name) == 0:
 | 
				
			||||||
 | 
					            self.db_cursor.execute("SELECT name, description, category FROM tag")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.db_cursor.execute("SELECT name, description, category FROM tag WHERE LOWER(name) LIKE LOWER('%{0}%')".format(name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					        new_rows = []
 | 
				
			||||||
 | 
					        for i in range(len(rows)):
 | 
				
			||||||
 | 
					            new_rows.append([])
 | 
				
			||||||
 | 
					            for j in range(len(rows[i])):
 | 
				
			||||||
 | 
					                if rows[i][j] is None:
 | 
				
			||||||
 | 
					                    new_rows[i].append("")
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    new_rows[i].append(rows[i][j].strip())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new_rows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def search_fuzzy_artists(self, ID: int, description: str, all_if_empty: bool = False):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search a list of fitting artists fuzzy.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If ID is None it will search using the description
 | 
				
			||||||
 | 
					        :param ID:
 | 
				
			||||||
 | 
					        :param description:
 | 
				
			||||||
 | 
					        :param all_if_empty:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if ID is not None:
 | 
				
			||||||
 | 
					            self.db_cursor.execute("SELECT id, description FROM artist WHERE id = %(id)s", {"id": ID})
 | 
				
			||||||
 | 
					        elif all_if_empty and ID is None and len(description) == 0:
 | 
				
			||||||
 | 
					            self.db_cursor.execute("SELECT id, description FROM artist")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.db_cursor.execute("SELECT id, description FROM artist WHERE LOWER(description) LIKE LOWER('%{0}%')"
 | 
				
			||||||
 | 
					                                   .format(description))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_tag(self, name: str, description: str, aliases: list, implications: list, category: str = None):
 | 
				
			||||||
 | 
					        name = name.strip()
 | 
				
			||||||
 | 
					        if aliases is None:
 | 
				
			||||||
 | 
					            aliases = []
 | 
				
			||||||
 | 
					        if implications is None:
 | 
				
			||||||
 | 
					            implications = []
 | 
				
			||||||
 | 
					        d = {"name": name, "description": description, "category": category}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("INSERT INTO tag (name, description, category) " +
 | 
				
			||||||
 | 
					                               "VALUES (LOWER(%(name)s), %(description)s, %(category)s)", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for alias in aliases:
 | 
				
			||||||
 | 
					            self.add_alias(name, alias)
 | 
				
			||||||
 | 
					        for implicant in implications:
 | 
				
			||||||
 | 
					            self.add_implication(name, implicant)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def edit_tag(self, name: str, description: str, aliases: list=None, implications: list=None, category: str = None,
 | 
				
			||||||
 | 
					                 old_tag: str = None):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Edit a tag with the new given data
 | 
				
			||||||
 | 
					        :param name: unique tag name to apply edits to (distinct from old_tag)
 | 
				
			||||||
 | 
					        :param description: new description to apply, set to None to omit
 | 
				
			||||||
 | 
					        :param aliases: list of tag names to be the alias of this tag, set to None to omit
 | 
				
			||||||
 | 
					        :param implications: list of tag names to be implied by this tag, set to None to omit
 | 
				
			||||||
 | 
					        :param category:
 | 
				
			||||||
 | 
					        :param old_tag: old tag name from which to transfer all data
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        name = name.strip().lower()
 | 
				
			||||||
 | 
					        d = {
 | 
				
			||||||
 | 
					            "name": name,
 | 
				
			||||||
 | 
					            "description": description,
 | 
				
			||||||
 | 
					            "alias": aliases,
 | 
				
			||||||
 | 
					            "implications": implications,
 | 
				
			||||||
 | 
					            "category": category,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if old_tag is not None and len(old_tag) > 0:
 | 
				
			||||||
 | 
					            # tag name changed, need to transfer all data and remove old tag
 | 
				
			||||||
 | 
					            old_tag = self.get_tag_by_name(old_tag)
 | 
				
			||||||
 | 
					            d["ID"] = old_tag[0][-1]
 | 
				
			||||||
 | 
					            self.db_cursor.execute("UPDATE tag SET name = %(name)s WHERE tag_ID = %(ID)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if description is not None:
 | 
				
			||||||
 | 
					            self.db_cursor.execute("UPDATE tag SET description = %(description)s, category = %(category)s " +
 | 
				
			||||||
 | 
					                                   "WHERE name = %(name)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if aliases is not None:
 | 
				
			||||||
 | 
					            old_aliases = self.get_tag_aliases(name)
 | 
				
			||||||
 | 
					            for alias in aliases:
 | 
				
			||||||
 | 
					                if alias in old_aliases:  # is this already set?
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                self.add_alias(name, alias)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for old_alias in old_aliases:
 | 
				
			||||||
 | 
					                if old_alias not in aliases:  # got to delete an alias?
 | 
				
			||||||
 | 
					                    self.remove_alias(name, old_alias)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if implications is not None:
 | 
				
			||||||
 | 
					            old_implicants = self.get_tag_implications(name)
 | 
				
			||||||
 | 
					            for implicant in implications:
 | 
				
			||||||
 | 
					                if implicant in old_implicants:  # is this already set?
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                self.add_implication(name, implicant)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for old_implicant in old_implicants:
 | 
				
			||||||
 | 
					                if old_implicant not in implications:  # got to delete an implicant?
 | 
				
			||||||
 | 
					                    self.remove_implication(name, old_implicant)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_alias(self, name: str, alias: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Add the alias pair to the database
 | 
				
			||||||
 | 
					        :param name: 
 | 
				
			||||||
 | 
					        :param alias: 
 | 
				
			||||||
 | 
					        :return: 
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {
 | 
				
			||||||
 | 
					            "name": self.get_tag_ID(name),
 | 
				
			||||||
 | 
					            "alias": self.get_tag_ID(alias)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.db_cursor.execute("INSERT INTO tag_alias (tag1, tag2) VALUES (%(name)s, %(alias)s)", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_alias(self, name: str, alias: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Remove alias pair from the database
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param alias:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {
 | 
				
			||||||
 | 
					            "ID": self.get_tag_ID(name),
 | 
				
			||||||
 | 
					            "alias": self.get_tag_ID(alias)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.db_cursor.execute("DELETE FROM tag_alias WHERE (tag1 = %(ID)s and tag2 = %(alias)s) " +
 | 
				
			||||||
 | 
					                               "or (tag1 = %(alias)s and tag2 = %(ID)s)", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_implication(self, name: str, implicant: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Add the implication to the database
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param implicant:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {
 | 
				
			||||||
 | 
					            "name": self.get_tag_ID(name),
 | 
				
			||||||
 | 
					            "implicant": self.get_tag_ID(implicant)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.db_cursor.execute("INSERT INTO tag_implication (root_tag, implicate) VALUES (%(name)s, %(implicant)s)",
 | 
				
			||||||
 | 
					                               d)
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_implication(self, name: str, implicant: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Remove the implication pair from the database
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param implicant:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"name": self.get_tag_ID(name),
 | 
				
			||||||
 | 
					             "implicant": self.get_tag_ID(implicant)}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("DELETE FROM tag_implication WHERE root_tag = %(name)s " +
 | 
				
			||||||
 | 
					                               "and implicate = %(implicant)s", d)
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_tag(self, name: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Remove the given tag from the database
 | 
				
			||||||
 | 
					        :param str:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"name": name}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("DELETE FROM tag WHERE name = %(name)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db.commit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_ID(self, name: str) -> int:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Get the tag ID by querying it by its unique name
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"name": name}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT tag_ID, name FROM tag where LOWER(name) = LOWER(%(name)s)", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows = []
 | 
				
			||||||
 | 
					        for row in self.db_cursor.fetchall():
 | 
				
			||||||
 | 
					            rows.append(row[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(rows) > 1:
 | 
				
			||||||
 | 
					            exit(1)  # something went horribly horribly wrong!
 | 
				
			||||||
 | 
					        elif len(rows) == 0:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return rows[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_by_name(self, name: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search the tag in the DB via its name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Note: name is constrained to be unique by the DB
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return: Returns the tag's name, description, category, tag ID
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"name": name}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT name, description, category, tag_ID FROM tag where LOWER(name) = LOWER(%(name)s)", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows = []
 | 
				
			||||||
 | 
					        for row in self.db_cursor.fetchall():
 | 
				
			||||||
 | 
					            new_row = []
 | 
				
			||||||
 | 
					            for value in row:
 | 
				
			||||||
 | 
					                if value is None:
 | 
				
			||||||
 | 
					                    new_row.append("")
 | 
				
			||||||
 | 
					                elif type(value) == str:
 | 
				
			||||||
 | 
					                    new_row.append(value.strip())
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    new_row.append(value)
 | 
				
			||||||
 | 
					            rows.append(new_row)
 | 
				
			||||||
 | 
					        return rows
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_by_ID(self, ID: int) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search the tag in the DB via its ID.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Note: name is constrained to be unique by the DB
 | 
				
			||||||
 | 
					        :param ID:
 | 
				
			||||||
 | 
					        :return: Returns the tag's ID, name, description, category
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"ID": ID}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT tag_ID, name, description, category FROM tag where tag_ID = %(ID)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_aliases(self, name: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search for the tag's aliases and the tag's aliases
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return: List of tag Names that are aliases of this one
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        aliases = self.get_tag_aliases_by_ID(self.get_tag_ID(name))
 | 
				
			||||||
 | 
					        result = []
 | 
				
			||||||
 | 
					        for alias in aliases:
 | 
				
			||||||
 | 
					            tag_data = self.get_tag_by_ID(alias)
 | 
				
			||||||
 | 
					            if len(tag_data) > 0:
 | 
				
			||||||
 | 
					                result.append(tag_data[0][1].strip())
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_aliases_by_ID(self, tag_ID: int) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search for the tag's aliases and the tag's aliases
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return: List of tag IDs that are aliases of this one
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        marked = []
 | 
				
			||||||
 | 
					        to_search = [tag_ID]
 | 
				
			||||||
 | 
					        while len(to_search) != 0:
 | 
				
			||||||
 | 
					            curr_alias = to_search.pop()
 | 
				
			||||||
 | 
					            found_aliases = self.__get_tag_aliases_no_recurse(curr_alias)
 | 
				
			||||||
 | 
					            marked.append(curr_alias)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for found_alias in found_aliases:
 | 
				
			||||||
 | 
					                if found_alias not in marked:
 | 
				
			||||||
 | 
					                    to_search.append(found_alias)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        marked.remove(tag_ID)
 | 
				
			||||||
 | 
					        return marked
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_all_tag_implications(self, name: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search for the tag's implications and those that are implied by them.
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        root_ID = self.get_tag_ID(name)
 | 
				
			||||||
 | 
					        collected_tags = self.get_tag_implications_by_ID(root_ID)
 | 
				
			||||||
 | 
					        collected_tags.append(root_ID)
 | 
				
			||||||
 | 
					        to_search = self.get_tag_implications_by_ID(root_ID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while len(to_search) != 0:
 | 
				
			||||||
 | 
					            curr_tag = to_search.pop()
 | 
				
			||||||
 | 
					            found_implications = self.get_tag_implications_by_ID(curr_tag)
 | 
				
			||||||
 | 
					            for found in found_implications:
 | 
				
			||||||
 | 
					                if found in collected_tags:
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    collected_tags.append(found)
 | 
				
			||||||
 | 
					                    to_search.append(found)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        collected_tags.remove(root_ID)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = []
 | 
				
			||||||
 | 
					        for tag_ID in collected_tags:
 | 
				
			||||||
 | 
					            tag_data = self.get_tag_by_ID(tag_ID)
 | 
				
			||||||
 | 
					            if len(tag_data) != 0:
 | 
				
			||||||
 | 
					                result.append(tag_data[0][1].strip())
 | 
				
			||||||
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_implications_by_ID(self, ID: int) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search for the tag's implications
 | 
				
			||||||
 | 
					        :param ID: ID of the tag
 | 
				
			||||||
 | 
					        :return: returns a list of IDs that are implied
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"ID": ID}
 | 
				
			||||||
 | 
					        if d["ID"] is None:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT root_tag, implicate FROM Tag_Implication WHERE root_tag = %(ID)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					        if len(rows) == 0:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        r = []
 | 
				
			||||||
 | 
					        for row in rows:
 | 
				
			||||||
 | 
					            r.append(row[1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_implications(self, name: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search for the tag's implications
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param output_ID: Don't resolve the tag ids into names in the resulting list
 | 
				
			||||||
 | 
					        :return: List of tag names
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"ID": self.get_tag_ID(name)}
 | 
				
			||||||
 | 
					        if d["ID"] is None:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT root_tag, implicate FROM Tag_Implication WHERE root_tag = %(ID)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					        if len(rows) == 0:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        r = []
 | 
				
			||||||
 | 
					        for row in rows:
 | 
				
			||||||
 | 
					            r.append(row[1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = [self.get_tag_by_ID(v) for v in r]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        r = []
 | 
				
			||||||
 | 
					        for value in result:
 | 
				
			||||||
 | 
					            r.append(value[0][1].strip())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_impliers(self, name: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search for tags that imply this one.
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"ID": self.get_tag_ID(name)}
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT root_tag, implicate FROM Tag_Implication WHERE implicate = %(ID)s", d)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rows = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					        r = []
 | 
				
			||||||
 | 
					        for row in rows:
 | 
				
			||||||
 | 
					            r.append(row[0])
 | 
				
			||||||
 | 
					        return r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __get_tag_aliases_no_recurse(self, tag_id: int) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Search for the tag's aliases
 | 
				
			||||||
 | 
					        :param tag_id:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        d = {"ID": tag_id}
 | 
				
			||||||
 | 
					        if d["ID"] is None:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.db_cursor.execute("SELECT tag1, tag2 FROM Tag_Alias "
 | 
				
			||||||
 | 
					                               "WHERE tag1 = %(ID)s or tag2 = %(ID)s", d)
 | 
				
			||||||
 | 
					        rows = self.db_cursor.fetchall()
 | 
				
			||||||
 | 
					        r = []
 | 
				
			||||||
 | 
					        for row in rows:
 | 
				
			||||||
 | 
					            if row[0] == tag_id:
 | 
				
			||||||
 | 
					                r.append(row[1])
 | 
				
			||||||
 | 
					            elif row[1] == tag_id:
 | 
				
			||||||
 | 
					                r.append(row[0])
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise Exception("Something went terribly wrong!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    db = DBAdapter(user="artnet_editor", password="G606Rm9sFEXe6wfTLxVu",
 | 
				
			||||||
 | 
					                   database="artnet", host="localhost", port=5432)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    search = 'Ajin/66699b4e41f533982db1766e8f72494a.gif2222'
 | 
				
			||||||
 | 
					    print("Art search result:", search, db.get_art_by_path('Ajin/66699b4e41f533982db1766e8f72494a.gif'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    search = "tag"
 | 
				
			||||||
 | 
					    print("Fuzzy Search Result:", search, db.search_fuzzy_tag(search))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    search = "tag1"
 | 
				
			||||||
 | 
					    print("Search Result:", search, db.get_tag_by_name(search))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    search = "tag1"
 | 
				
			||||||
 | 
					    print("Alias Search Result:", search, db.get_tag_aliases(search))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    search = "tag1"
 | 
				
			||||||
 | 
					    print("Implication Search Result:", search, db.get_tag_implications(search))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    target = "tag1"
 | 
				
			||||||
 | 
					    db.edit_tag(target, "new description! ;D", aliases=["tag1_alias"], implications=["tag1_implicated"])
 | 
				
			||||||
 | 
					    print("Editing:", target, db.get_tag_by_name(target), db.get_tag_aliases(target), db.get_tag_implications(target))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,135 @@
 | 
				
			|||||||
 | 
					import os
 | 
				
			||||||
 | 
					import base64
 | 
				
			||||||
 | 
					import copy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import yaml
 | 
				
			||||||
 | 
					from cryptography.exceptions import AlreadyFinalized
 | 
				
			||||||
 | 
					from cryptography.exceptions import InvalidTag
 | 
				
			||||||
 | 
					from cryptography.exceptions import UnsupportedAlgorithm
 | 
				
			||||||
 | 
					from cryptography.hazmat.backends import default_backend
 | 
				
			||||||
 | 
					from cryptography.hazmat.primitives import hashes
 | 
				
			||||||
 | 
					from cryptography.hazmat.primitives.ciphers.aead import AESGCM
 | 
				
			||||||
 | 
					from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigReader:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    kdf = None
 | 
				
			||||||
 | 
					    nonce = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, root_folder: str, password: str):
 | 
				
			||||||
 | 
					        if root_folder is None:
 | 
				
			||||||
 | 
					            raise Exception("No root folder was defined!")
 | 
				
			||||||
 | 
					        self.__key = None
 | 
				
			||||||
 | 
					        self.__aesgcm = None
 | 
				
			||||||
 | 
					        self.data = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__password = password
 | 
				
			||||||
 | 
					        self.__config_location = os.path.join(root_folder, ".artnet", "artnet.config")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ConfigReader.__create_kdf()
 | 
				
			||||||
 | 
					        self.__key = ConfigReader.kdf.derive(bytes(password.encode('utf-8')))
 | 
				
			||||||
 | 
					        self.__aesgcm = AESGCM(self.__key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if os.path.exists(self.__config_location) and os.path.isfile(self.__config_location):
 | 
				
			||||||
 | 
					            self.read_config()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if not os.path.exists(os.path.join(root_folder, ".artnet")):
 | 
				
			||||||
 | 
					                os.mkdir(os.path.join(root_folder, ".artnet"))
 | 
				
			||||||
 | 
					            self.create_default_config()
 | 
				
			||||||
 | 
					            self.read_config()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_config(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Update the written config with the local settings
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        file = open(self.__config_location, "w")
 | 
				
			||||||
 | 
					        yaml.dump(stream=file, data=self.encrypt_sensitive_data(copy.deepcopy(self.data)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def read_config(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Read the config from file and overwrite local settings
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        print(os.path.isfile(self.__config_location))
 | 
				
			||||||
 | 
					        print(os.path.join(os.getcwd(), self.__config_location))
 | 
				
			||||||
 | 
					        file = open(self.__config_location, "r")
 | 
				
			||||||
 | 
					        data = yaml.safe_load(stream=file)
 | 
				
			||||||
 | 
					        self.data = self.decrypt_sensitive_data(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def encrypt_sensitive_data(self, data: dict) -> dict:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Encrypts the sensitive portions of the data
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        new_data = data
 | 
				
			||||||
 | 
					        new_data["db"]["password"] = self.encrypt_text(data["db"]["password"])
 | 
				
			||||||
 | 
					        new_data["db"]["user"] = self.encrypt_text(data["db"]["user"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def decrypt_sensitive_data(self, data: dict) -> dict:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Decrypts the sensitive portions of the data
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        new_data = data
 | 
				
			||||||
 | 
					        new_data["db"]["password"] = self.decrypt_text(data["db"]["password"])
 | 
				
			||||||
 | 
					        new_data["db"]["user"] = self.decrypt_text(data["db"]["user"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return new_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_default_config(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Create a default config, overwrites all settings and generates a new key
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.data = {
 | 
				
			||||||
 | 
					            "db": {
 | 
				
			||||||
 | 
					                "host": "localhost",
 | 
				
			||||||
 | 
					                "port": 5432,
 | 
				
			||||||
 | 
					                "database": "artnet",
 | 
				
			||||||
 | 
					                "user": "your_user",
 | 
				
			||||||
 | 
					                "password": "enter_password_via_gui"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.update_config()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def __create_kdf():
 | 
				
			||||||
 | 
					        ConfigReader.kdf = PBKDF2HMAC(algorithm=hashes.SHA512(),
 | 
				
			||||||
 | 
					                                      length=32,
 | 
				
			||||||
 | 
					                                      salt=bytes("ArtN3t.WhatElse?".encode('utf-8')),
 | 
				
			||||||
 | 
					                                      iterations=10000,
 | 
				
			||||||
 | 
					                                      backend=default_backend()
 | 
				
			||||||
 | 
					                                      )
 | 
				
			||||||
 | 
					        ConfigReader.nonce = bytes("qt34nvßn".encode('utf-8'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def encrypt_text(self, text: str) -> str:
 | 
				
			||||||
 | 
					        cipher_text_bytes = self.__aesgcm.encrypt(data=text.encode('utf-8'),
 | 
				
			||||||
 | 
					                                           associated_data=None,
 | 
				
			||||||
 | 
					                                           nonce=ConfigReader.nonce
 | 
				
			||||||
 | 
					                                           )
 | 
				
			||||||
 | 
					        return base64.urlsafe_b64encode(cipher_text_bytes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def decrypt_text(self, cipher: str) -> str:
 | 
				
			||||||
 | 
					        if ConfigReader.kdf is None:
 | 
				
			||||||
 | 
					            ConfigReader.__create_kdf()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            decrypted_cipher_text_bytes = self.__aesgcm.decrypt(
 | 
				
			||||||
 | 
					                nonce=ConfigReader.nonce,
 | 
				
			||||||
 | 
					                data=base64.urlsafe_b64decode(cipher),
 | 
				
			||||||
 | 
					                associated_data=None
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        except InvalidTag:
 | 
				
			||||||
 | 
					            raise Exception("Could not decrypt Text! Wrong Password?")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return decrypted_cipher_text_bytes.decode('utf-8')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    cr = ConfigReader(password="MySuperDuperKey", root_folder=".")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    print(cr.data)
 | 
				
			||||||
@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FileReader:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, root: str):
 | 
				
			||||||
 | 
					        if not os.path.isdir(root):
 | 
				
			||||||
 | 
					            raise Exception("Root was not a valid directory! {0}".format(root))
 | 
				
			||||||
 | 
					        self.__root = root
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def list_artists(self) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        List all Artists within the root folder
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        l = [os.path.basename(x) for x in os.listdir(self.__root)]
 | 
				
			||||||
 | 
					        if ".artnet" in l:
 | 
				
			||||||
 | 
					            l.remove(".artnet")
 | 
				
			||||||
 | 
					        return l
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_files(self, artist: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        List all files within the given artists directory with their relative path (to the root).
 | 
				
			||||||
 | 
					        :param artist:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        l = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        root = os.path.join(self.__root)
 | 
				
			||||||
 | 
					        dirs = [artist]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while len(dirs) != 0:
 | 
				
			||||||
 | 
					            curr_dir = dirs.pop()
 | 
				
			||||||
 | 
					            curr_full_dir = os.path.join(root, curr_dir)
 | 
				
			||||||
 | 
					            l += [os.path.join(curr_dir, f) for f in os.listdir(curr_full_dir) if os.path.isfile(os.path.join(curr_full_dir, f))]
 | 
				
			||||||
 | 
					            for d in [x for x in os.listdir(curr_full_dir) if os.path.isdir(os.path.join(curr_full_dir, x))]:
 | 
				
			||||||
 | 
					                dirs.append(os.path.join(curr_dir, d))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return l
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    fr = FileReader("/home/peery/Software_Projects/ArtNet/App/Fake_Other_Artists")
 | 
				
			||||||
 | 
					    print(fr.list_artists())
 | 
				
			||||||
 | 
					    print(fr.get_files("AkuDrache"))
 | 
				
			||||||
@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.artist_modify_dialog.artist_modify_dialog import Ui_Artist_Mod_Dialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ArtistModDialog(QtWidgets.QDialog):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None, create_artist: bool = False):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.parent = parent
 | 
				
			||||||
 | 
					        self.ui = Ui_Artist_Mod_Dialog()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data = {"id": None,
 | 
				
			||||||
 | 
					                     "description": None}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not create_artist:
 | 
				
			||||||
 | 
					            self.set_available_artists(self.parent.parent.parent.get_all_artists())
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.ui.id_list = QtWidgets.QLineEdit(self)
 | 
				
			||||||
 | 
					            self.ui.id_spinbox.setParent(None)
 | 
				
			||||||
 | 
					            self.ui.id_spinbox.destroy()
 | 
				
			||||||
 | 
					            self.ui.id_layout.addWidget(self.ui.id_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.description_line.textChanged.connect(self.on_description_changed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_available_artists(self, artists: list):
 | 
				
			||||||
 | 
					        if artists is None:
 | 
				
			||||||
 | 
					            self.ui.id_spinbox.setParent(None)
 | 
				
			||||||
 | 
					            self.ui.id_spinbox.destroy()
 | 
				
			||||||
 | 
					            self.ui.id_label.setText("Artist ID (auto-generated)")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.id_spinbox.setMinimum(0)
 | 
				
			||||||
 | 
					        self.ui.id_spinbox.setMaximum(len(artists))
 | 
				
			||||||
 | 
					        self.ui.id_spinbox.valueChanged.connect(self.on_id_spinbox_changed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_id_spinbox_changed(self):
 | 
				
			||||||
 | 
					        id = self.ui.id_spinbox.value()
 | 
				
			||||||
 | 
					        artist = self.parent.parent.parent.get_artist(id)
 | 
				
			||||||
 | 
					        if len(artist) != 0:
 | 
				
			||||||
 | 
					            self.ui.description_line.setText(artist[0][1])
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.ui.description_line.setText("Warning! unknown Artist ID!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data["id"] = id
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_description_changed(self):
 | 
				
			||||||
 | 
					        self.data["description"] = self.ui.description_line.text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exec_(self):
 | 
				
			||||||
 | 
					        result = super(ArtistModDialog, self).exec_()
 | 
				
			||||||
 | 
					        if result == QtWidgets.QDialog.Rejected:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.data
 | 
				
			||||||
@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'dialogs/artist_modify_dialog/artist_modify_dialog.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_Artist_Mod_Dialog(object):
 | 
				
			||||||
 | 
					    def setupUi(self, Artist_Mod_Dialog):
 | 
				
			||||||
 | 
					        Artist_Mod_Dialog.setObjectName("Artist_Mod_Dialog")
 | 
				
			||||||
 | 
					        Artist_Mod_Dialog.resize(311, 205)
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(Artist_Mod_Dialog)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.dialog_frame = QtWidgets.QFrame(Artist_Mod_Dialog)
 | 
				
			||||||
 | 
					        self.dialog_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.dialog_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.dialog_frame.setObjectName("dialog_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.dialog_topic = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.dialog_topic.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.dialog_topic.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(11)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.dialog_topic.setFont(font)
 | 
				
			||||||
 | 
					        self.dialog_topic.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.dialog_topic.setObjectName("dialog_topic")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.dialog_topic)
 | 
				
			||||||
 | 
					        self.frame = QtWidgets.QFrame(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame.setObjectName("frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_5.setObjectName("verticalLayout_5")
 | 
				
			||||||
 | 
					        self.id_label = QtWidgets.QLabel(self.frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.id_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.id_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.id_label.setObjectName("id_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_5.addWidget(self.id_label)
 | 
				
			||||||
 | 
					        self.id_layout = QtWidgets.QVBoxLayout()
 | 
				
			||||||
 | 
					        self.id_layout.setObjectName("id_layout")
 | 
				
			||||||
 | 
					        self.id_spinbox = QtWidgets.QDoubleSpinBox(self.frame)
 | 
				
			||||||
 | 
					        self.id_spinbox.setDecimals(0)
 | 
				
			||||||
 | 
					        self.id_spinbox.setMaximum(10000.0)
 | 
				
			||||||
 | 
					        self.id_spinbox.setObjectName("id_spinbox")
 | 
				
			||||||
 | 
					        self.id_layout.addWidget(self.id_spinbox)
 | 
				
			||||||
 | 
					        self.verticalLayout_5.addLayout(self.id_layout)
 | 
				
			||||||
 | 
					        self.description_label = QtWidgets.QLabel(self.frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.description_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.description_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.description_label.setObjectName("description_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_5.addWidget(self.description_label)
 | 
				
			||||||
 | 
					        self.description_line = QtWidgets.QLineEdit(self.frame)
 | 
				
			||||||
 | 
					        self.description_line.setObjectName("description_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_5.addWidget(self.description_line)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.frame)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.buttonBox = QtWidgets.QDialogButtonBox(Artist_Mod_Dialog)
 | 
				
			||||||
 | 
					        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
 | 
				
			||||||
 | 
					        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 | 
				
			||||||
 | 
					        self.buttonBox.setObjectName("buttonBox")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.buttonBox)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(Artist_Mod_Dialog)
 | 
				
			||||||
 | 
					        self.buttonBox.accepted.connect(Artist_Mod_Dialog.accept)
 | 
				
			||||||
 | 
					        self.buttonBox.rejected.connect(Artist_Mod_Dialog.reject)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(Artist_Mod_Dialog)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, Artist_Mod_Dialog):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        Artist_Mod_Dialog.setWindowTitle(_translate("Artist_Mod_Dialog", "Dialog"))
 | 
				
			||||||
 | 
					        self.dialog_topic.setText(_translate("Artist_Mod_Dialog", "Artist Topic"))
 | 
				
			||||||
 | 
					        self.id_label.setText(_translate("Artist_Mod_Dialog", "Artist ID:"))
 | 
				
			||||||
 | 
					        self.description_label.setText(_translate("Artist_Mod_Dialog", "Artist Description:"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    Artist_Mod_Dialog = QtWidgets.QDialog()
 | 
				
			||||||
 | 
					    ui = Ui_Artist_Mod_Dialog()
 | 
				
			||||||
 | 
					    ui.setupUi(Artist_Mod_Dialog)
 | 
				
			||||||
 | 
					    Artist_Mod_Dialog.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,154 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>Artist_Mod_Dialog</class>
 | 
				
			||||||
 | 
					 <widget class="QDialog" name="Artist_Mod_Dialog">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>311</width>
 | 
				
			||||||
 | 
					    <height>205</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>Dialog</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="dialog_frame">
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="dialog_topic">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>11</pointsize>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Artist Topic</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="frame">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="verticalLayout_5">
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="id_label">
 | 
				
			||||||
 | 
					           <property name="sizePolicy">
 | 
				
			||||||
 | 
					            <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					             <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					             <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					            </sizepolicy>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Artist ID:</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <layout class="QVBoxLayout" name="id_layout">
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QDoubleSpinBox" name="id_spinbox">
 | 
				
			||||||
 | 
					             <property name="decimals">
 | 
				
			||||||
 | 
					              <number>0</number>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="maximum">
 | 
				
			||||||
 | 
					              <double>10000.000000000000000</double>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					          </layout>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="description_label">
 | 
				
			||||||
 | 
					           <property name="sizePolicy">
 | 
				
			||||||
 | 
					            <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					             <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					             <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					            </sizepolicy>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Artist Description:</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLineEdit" name="description_line"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					     <property name="orientation">
 | 
				
			||||||
 | 
					      <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="standardButtons">
 | 
				
			||||||
 | 
					      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>accepted()</signal>
 | 
				
			||||||
 | 
					   <receiver>Artist_Mod_Dialog</receiver>
 | 
				
			||||||
 | 
					   <slot>accept()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>248</x>
 | 
				
			||||||
 | 
					     <y>254</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>157</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>rejected()</signal>
 | 
				
			||||||
 | 
					   <receiver>Artist_Mod_Dialog</receiver>
 | 
				
			||||||
 | 
					   <slot>reject()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>316</x>
 | 
				
			||||||
 | 
					     <y>260</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>286</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					 </connections>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt
 | 
				
			||||||
 | 
					from PyQt5.QtGui import QStandardItem, QStandardItemModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.category_modify_dialog.category_modify_dialog import Ui_category_modify_dialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CategoryModDialog(QtWidgets.QDialog):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None, delete_category: bool = False):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.parent = parent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui = Ui_category_modify_dialog()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					        self.name_valid: bool = False
 | 
				
			||||||
 | 
					        self.all_categories: list = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.default_style = self.ui.category_name_line.styleSheet()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.delete_mode: bool = delete_category
 | 
				
			||||||
 | 
					        if delete_category:
 | 
				
			||||||
 | 
					            self.ui.dialog_topic.setText("Delete Category")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.ui.dialog_topic.setText("Create Category")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.category_name_line.textChanged.connect(self.on_category_name_change)
 | 
				
			||||||
 | 
					        self.set_all_categories()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_all_categories(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Populate the category list with all categories if name line is empty.
 | 
				
			||||||
 | 
					        Otherwise fuzzy search for fitting categories
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.all_categories = self.parent.get_categories(self.ui.category_name_line.text(), all_if_empty=True)
 | 
				
			||||||
 | 
					        categories = []
 | 
				
			||||||
 | 
					        for i in range(len(self.all_categories)):
 | 
				
			||||||
 | 
					            categories.append(self.all_categories[i])
 | 
				
			||||||
 | 
					        self.all_categories = categories
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.other_categories_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for category in self.all_categories:
 | 
				
			||||||
 | 
					            item = QStandardItem(category)
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.other_categories_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_category_name_change(self):
 | 
				
			||||||
 | 
					        # TODO mark input red if it is a taken name (or if it isn't in deletion mode)
 | 
				
			||||||
 | 
					        self.set_all_categories()
 | 
				
			||||||
 | 
					        self.ui.category_name_line.setStyleSheet(self.default_style)
 | 
				
			||||||
 | 
					        self.name_valid = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.delete_mode:
 | 
				
			||||||
 | 
					            if self.ui.category_name_line.text() not in self.all_categories:
 | 
				
			||||||
 | 
					                self.ui.category_name_line.setStyleSheet("color: red")
 | 
				
			||||||
 | 
					                self.name_valid = False
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if self.ui.category_name_line.text() in self.all_categories:
 | 
				
			||||||
 | 
					                self.ui.category_name_line.setStyleSheet("color: red")
 | 
				
			||||||
 | 
					                self.name_valid = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exec_(self) -> dict:
 | 
				
			||||||
 | 
					        if super(CategoryModDialog, self).exec_() == QtWidgets.QDialog.Rejected or not self.name_valid:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {"name": self.ui.category_name_line.text()}
 | 
				
			||||||
@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'dialogs/category_modify_dialog/category_modify_dialog.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_category_modify_dialog(object):
 | 
				
			||||||
 | 
					    def setupUi(self, category_modify_dialog):
 | 
				
			||||||
 | 
					        category_modify_dialog.setObjectName("category_modify_dialog")
 | 
				
			||||||
 | 
					        category_modify_dialog.resize(398, 298)
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(category_modify_dialog)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.frame = QtWidgets.QFrame(category_modify_dialog)
 | 
				
			||||||
 | 
					        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame.setObjectName("frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.dialog_topic = QtWidgets.QLabel(self.frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.dialog_topic.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.dialog_topic.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(12)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.dialog_topic.setFont(font)
 | 
				
			||||||
 | 
					        self.dialog_topic.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.dialog_topic.setObjectName("dialog_topic")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.dialog_topic)
 | 
				
			||||||
 | 
					        self.frame_2 = QtWidgets.QFrame(self.frame)
 | 
				
			||||||
 | 
					        self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame_2.setObjectName("frame_2")
 | 
				
			||||||
 | 
					        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_2)
 | 
				
			||||||
 | 
					        self.verticalLayout_3.setObjectName("verticalLayout_3")
 | 
				
			||||||
 | 
					        self.category_name_label = QtWidgets.QLabel(self.frame_2)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.category_name_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.category_name_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.category_name_label.setFont(font)
 | 
				
			||||||
 | 
					        self.category_name_label.setObjectName("category_name_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.category_name_label)
 | 
				
			||||||
 | 
					        self.category_name_line = QtWidgets.QLineEdit(self.frame_2)
 | 
				
			||||||
 | 
					        self.category_name_line.setObjectName("category_name_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.category_name_line)
 | 
				
			||||||
 | 
					        self.other_categories_list = QtWidgets.QListView(self.frame_2)
 | 
				
			||||||
 | 
					        self.other_categories_list.setObjectName("other_categories_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.other_categories_list)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.frame_2)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.frame)
 | 
				
			||||||
 | 
					        self.buttonBox = QtWidgets.QDialogButtonBox(category_modify_dialog)
 | 
				
			||||||
 | 
					        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
 | 
				
			||||||
 | 
					        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 | 
				
			||||||
 | 
					        self.buttonBox.setObjectName("buttonBox")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.buttonBox)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(category_modify_dialog)
 | 
				
			||||||
 | 
					        self.buttonBox.accepted.connect(category_modify_dialog.accept)
 | 
				
			||||||
 | 
					        self.buttonBox.rejected.connect(category_modify_dialog.reject)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(category_modify_dialog)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, category_modify_dialog):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        category_modify_dialog.setWindowTitle(_translate("category_modify_dialog", "Dialog"))
 | 
				
			||||||
 | 
					        self.dialog_topic.setText(_translate("category_modify_dialog", "Category Topic"))
 | 
				
			||||||
 | 
					        self.category_name_label.setText(_translate("category_modify_dialog", "Category Name:"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    category_modify_dialog = QtWidgets.QDialog()
 | 
				
			||||||
 | 
					    ui = Ui_category_modify_dialog()
 | 
				
			||||||
 | 
					    ui.setupUi(category_modify_dialog)
 | 
				
			||||||
 | 
					    category_modify_dialog.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>category_modify_dialog</class>
 | 
				
			||||||
 | 
					 <widget class="QDialog" name="category_modify_dialog">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>398</width>
 | 
				
			||||||
 | 
					    <height>298</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>Dialog</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="frame">
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="dialog_topic">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>12</pointsize>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Category Topic</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="frame_2">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="category_name_label">
 | 
				
			||||||
 | 
					           <property name="sizePolicy">
 | 
				
			||||||
 | 
					            <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					             <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					             <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					            </sizepolicy>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Category Name:</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLineEdit" name="category_name_line"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QListView" name="other_categories_list"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					     <property name="orientation">
 | 
				
			||||||
 | 
					      <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="standardButtons">
 | 
				
			||||||
 | 
					      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>accepted()</signal>
 | 
				
			||||||
 | 
					   <receiver>category_modify_dialog</receiver>
 | 
				
			||||||
 | 
					   <slot>accept()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>248</x>
 | 
				
			||||||
 | 
					     <y>254</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>157</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>rejected()</signal>
 | 
				
			||||||
 | 
					   <receiver>category_modify_dialog</receiver>
 | 
				
			||||||
 | 
					   <slot>reject()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>316</x>
 | 
				
			||||||
 | 
					     <y>260</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>286</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					 </connections>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,147 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'dialogs/db_connection_dialog/db_connection_dialog.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_DBConnection(object):
 | 
				
			||||||
 | 
					    def setupUi(self, DBConnection):
 | 
				
			||||||
 | 
					        DBConnection.setObjectName("DBConnection")
 | 
				
			||||||
 | 
					        DBConnection.resize(328, 262)
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(DBConnection)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.dialog_frame = QtWidgets.QFrame(DBConnection)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.dialog_frame.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.dialog_frame.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.dialog_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.dialog_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.dialog_frame.setObjectName("dialog_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.title_label = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.title_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.title_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.title_label.setFont(font)
 | 
				
			||||||
 | 
					        self.title_label.setLayoutDirection(QtCore.Qt.LeftToRight)
 | 
				
			||||||
 | 
					        self.title_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.title_label.setObjectName("title_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.title_label)
 | 
				
			||||||
 | 
					        self.host_label = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.host_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.host_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.host_label.setFont(font)
 | 
				
			||||||
 | 
					        self.host_label.setObjectName("host_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.host_label)
 | 
				
			||||||
 | 
					        self.host_line_edit = QtWidgets.QLineEdit(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.host_line_edit.setObjectName("host_line_edit")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.host_line_edit)
 | 
				
			||||||
 | 
					        self.port_label = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.port_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.port_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.port_label.setFont(font)
 | 
				
			||||||
 | 
					        self.port_label.setObjectName("port_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.port_label)
 | 
				
			||||||
 | 
					        self.port_line_edit = QtWidgets.QLineEdit(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.port_line_edit.setObjectName("port_line_edit")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.port_line_edit)
 | 
				
			||||||
 | 
					        self.database_label = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.database_label.setFont(font)
 | 
				
			||||||
 | 
					        self.database_label.setObjectName("database_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.database_label)
 | 
				
			||||||
 | 
					        self.database_line_edit = QtWidgets.QLineEdit(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.database_line_edit.setObjectName("database_line_edit")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.database_line_edit)
 | 
				
			||||||
 | 
					        self.user_label = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.user_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.user_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.user_label.setFont(font)
 | 
				
			||||||
 | 
					        self.user_label.setObjectName("user_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.user_label)
 | 
				
			||||||
 | 
					        self.user_line_edit = QtWidgets.QLineEdit(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.user_line_edit.setObjectName("user_line_edit")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.user_line_edit)
 | 
				
			||||||
 | 
					        self.password_label = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.password_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.password_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.password_label.setFont(font)
 | 
				
			||||||
 | 
					        self.password_label.setObjectName("password_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.password_label)
 | 
				
			||||||
 | 
					        self.password_line_edit = QtWidgets.QLineEdit(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.password_line_edit.setEchoMode(QtWidgets.QLineEdit.Password)
 | 
				
			||||||
 | 
					        self.password_line_edit.setObjectName("password_line_edit")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.password_line_edit)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.buttonBox = QtWidgets.QDialogButtonBox(DBConnection)
 | 
				
			||||||
 | 
					        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
 | 
				
			||||||
 | 
					        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 | 
				
			||||||
 | 
					        self.buttonBox.setObjectName("buttonBox")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.buttonBox)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(DBConnection)
 | 
				
			||||||
 | 
					        self.buttonBox.accepted.connect(DBConnection.accept)
 | 
				
			||||||
 | 
					        self.buttonBox.rejected.connect(DBConnection.reject)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(DBConnection)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, DBConnection):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        DBConnection.setWindowTitle(_translate("DBConnection", "Dialog"))
 | 
				
			||||||
 | 
					        self.title_label.setText(_translate("DBConnection", "Edit PostgreSQL Connection"))
 | 
				
			||||||
 | 
					        self.host_label.setText(_translate("DBConnection", "Host:"))
 | 
				
			||||||
 | 
					        self.port_label.setText(_translate("DBConnection", "Port:"))
 | 
				
			||||||
 | 
					        self.database_label.setText(_translate("DBConnection", "Database:"))
 | 
				
			||||||
 | 
					        self.user_label.setText(_translate("DBConnection", "User:"))
 | 
				
			||||||
 | 
					        self.password_label.setText(_translate("DBConnection", "Password:"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    DBConnection = QtWidgets.QDialog()
 | 
				
			||||||
 | 
					    ui = Ui_DBConnection()
 | 
				
			||||||
 | 
					    ui.setupUi(DBConnection)
 | 
				
			||||||
 | 
					    DBConnection.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,216 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>DBConnection</class>
 | 
				
			||||||
 | 
					 <widget class="QDialog" name="DBConnection">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>328</width>
 | 
				
			||||||
 | 
					    <height>262</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>Dialog</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="dialog_frame">
 | 
				
			||||||
 | 
					     <property name="sizePolicy">
 | 
				
			||||||
 | 
					      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					       <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					       <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					      </sizepolicy>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="title_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="layoutDirection">
 | 
				
			||||||
 | 
					         <enum>Qt::LeftToRight</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Edit PostgreSQL Connection</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="host_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Host:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLineEdit" name="host_line_edit"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="port_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Port:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLineEdit" name="port_line_edit"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="database_label">
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Database:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLineEdit" name="database_line_edit"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="user_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>User:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLineEdit" name="user_line_edit"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="password_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Password:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLineEdit" name="password_line_edit">
 | 
				
			||||||
 | 
					        <property name="echoMode">
 | 
				
			||||||
 | 
					         <enum>QLineEdit::Password</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					     <property name="orientation">
 | 
				
			||||||
 | 
					      <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="standardButtons">
 | 
				
			||||||
 | 
					      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>accepted()</signal>
 | 
				
			||||||
 | 
					   <receiver>DBConnection</receiver>
 | 
				
			||||||
 | 
					   <slot>accept()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>248</x>
 | 
				
			||||||
 | 
					     <y>254</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>157</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>rejected()</signal>
 | 
				
			||||||
 | 
					   <receiver>DBConnection</receiver>
 | 
				
			||||||
 | 
					   <slot>reject()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>316</x>
 | 
				
			||||||
 | 
					     <y>260</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>286</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					 </connections>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.db_connection_dialog.db_connection_dialog import Ui_DBConnection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DBDialog(QtWidgets.QDialog):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.ui = Ui_DBConnection()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					        self.data = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.buttonBox.accepted.connect(self.getConnectionDetails)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getConnectionDetails(self):
 | 
				
			||||||
 | 
					        self.data = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data["host"] = self.ui.host_line_edit.text()
 | 
				
			||||||
 | 
					        self.data["port"] = self.ui.port_line_edit.text()
 | 
				
			||||||
 | 
					        self.data["database"] = self.ui.database_line_edit.text()
 | 
				
			||||||
 | 
					        self.data["user"] = self.ui.user_line_edit.text()
 | 
				
			||||||
 | 
					        self.data["password"] = self.ui.password_line_edit.text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.accept()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exec_(self) -> dict:
 | 
				
			||||||
 | 
					        if super(DBDialog, self).exec_() == QtWidgets.QDialog.Rejected:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        return self.data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,200 @@
 | 
				
			|||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt
 | 
				
			||||||
 | 
					from PyQt5.QtGui import QStandardItem, QStandardItemModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.presence_modify_dialog.presence_modify_dialog import Ui_PresenceModDialog
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.artist_modify_dialog.artist_mod_dialog import ArtistModDialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PresenceModDialog(QtWidgets.QDialog):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None, edit_presence: bool = False):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.parent = parent
 | 
				
			||||||
 | 
					        self.ui = Ui_PresenceModDialog()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.curr_artist: tuple = None
 | 
				
			||||||
 | 
					        self.__curr_searched_artists: list = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data: dict = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if edit_presence:
 | 
				
			||||||
 | 
					            self.ui.dialog_topic_label.setText("Edit Presence")
 | 
				
			||||||
 | 
					            self.ui.presence_domain_line.setReadOnly(True)
 | 
				
			||||||
 | 
					            self.ui.presence_name_line.setReadOnly(True)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.ui.dialog_topic_label.setText("Create Presence")
 | 
				
			||||||
 | 
					            self.ui.presence_domain_line.setReadOnly(False)
 | 
				
			||||||
 | 
					            self.ui.presence_name_line.setReadOnly(False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.artist_search_line.textChanged.connect(self.on_artist_search_changed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.create_artist_button.clicked.connect(self.on_create_artist_clicked)
 | 
				
			||||||
 | 
					        self.ui.edit_artist_button.clicked.connect(self.on_edit_artist_clicked)
 | 
				
			||||||
 | 
					        self.ui.delete_artist_button.clicked.connect(self.on_delete_artist_clicked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_presence_name(self, name: str):
 | 
				
			||||||
 | 
					        self.ui.presence_name_line.setText(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_presence_domain(self, name: str):
 | 
				
			||||||
 | 
					        self.ui.presence_domain_line.setText(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_create_artist_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked Create artist!")
 | 
				
			||||||
 | 
					        dialog = ArtistModDialog(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data = dialog.exec_()
 | 
				
			||||||
 | 
					        if data is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.parent.parent.create_artist(ID=data["id"], description=data["description"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_edit_artist_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked Edit artist!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_delete_artist_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked Delete artist!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.curr_artist is None:
 | 
				
			||||||
 | 
					            QtWidgets.QMessageBox.information(self, "No Artist Selected", "There is no artist selected to delete!")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        answer = QtWidgets.QMessageBox.question(self, "Delete this Artist?",
 | 
				
			||||||
 | 
					                                                "Do you really want to delete the Artist \"{0}\"?"
 | 
				
			||||||
 | 
					                                                .format(self.curr_artist[1]))
 | 
				
			||||||
 | 
					        if answer == QtWidgets.QMessageBox.Yes:
 | 
				
			||||||
 | 
					            pass  # TODO check if presences are associated & warn
 | 
				
			||||||
 | 
					            presences = self.parent.parent.get_artist_presences(self.curr_artist[0])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            msg = ""
 | 
				
			||||||
 | 
					            affected_art = 0
 | 
				
			||||||
 | 
					            for presence in presences:
 | 
				
			||||||
 | 
					                msg += presence[0]+":"+presence[1] + "\n"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                arts = self.parent.parent.get_presences_art(presence[0], presence[1])
 | 
				
			||||||
 | 
					                affected_art += len(arts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            answer = QtWidgets.QMessageBox.question(self, "Are you sure?",
 | 
				
			||||||
 | 
					                                                    ("Do you really wish to delete the Artist \"{0}\"?\n" +
 | 
				
			||||||
 | 
					                                                     "following Presences are associated with " +
 | 
				
			||||||
 | 
					                                                     "it and deleted also:\n\n" +
 | 
				
			||||||
 | 
					                                                     "{1}\n" +
 | 
				
			||||||
 | 
					                                                     "This will also remove this presence from following " +
 | 
				
			||||||
 | 
					                                                     "amount of art pieces:" +
 | 
				
			||||||
 | 
					                                                     "\n{2}\n")
 | 
				
			||||||
 | 
					                                                    .format(self.curr_artist[1], msg, affected_art)
 | 
				
			||||||
 | 
					                                                    )
 | 
				
			||||||
 | 
					            if answer == QtWidgets.QMessageBox.Yes:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                self.parent.parent.remove_artist(self.curr_artist[0])
 | 
				
			||||||
 | 
					                for presence in presences:
 | 
				
			||||||
 | 
					                    self.parent.parent.remove_presence(presence[0], presence[1])
 | 
				
			||||||
 | 
					                self.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_artist_search_changed(self):
 | 
				
			||||||
 | 
					        if len(self.ui.artist_search_line.text()) == 0:  # nothing to search for
 | 
				
			||||||
 | 
					            self.set_artist_result_list([])
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        artists = self.parent.parent.get_artists(self.ui.artist_search_line.text())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = []
 | 
				
			||||||
 | 
					        for ID, desc in artists:
 | 
				
			||||||
 | 
					            result.append(str(ID)+":"+desc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_artist_result_list(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_artist_result_list(self, artists: list):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the list of search result artists.
 | 
				
			||||||
 | 
					        :param artists: [(id, desc)]
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.artist_result_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__curr_searched_artists = []
 | 
				
			||||||
 | 
					        for artist in artists:
 | 
				
			||||||
 | 
					            self.__curr_searched_artists.append(artist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item = QStandardItem(artist)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if self.curr_artist is not None:
 | 
				
			||||||
 | 
					                curr_artist = str(self.curr_artist[0]) + ":" + self.curr_artist[1]
 | 
				
			||||||
 | 
					                if artist == curr_artist:
 | 
				
			||||||
 | 
					                    item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_search_artist_item_changed)
 | 
				
			||||||
 | 
					        self.ui.artist_result_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_artist_selected_list(self, artist: tuple):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the list of selected artist
 | 
				
			||||||
 | 
					        :param artists: [(id, desc)]
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if artist is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.artist_selection_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item = QStandardItem(str(artist[0])+":"+artist[1])
 | 
				
			||||||
 | 
					        item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					        item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					        item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_selected_artist_item_changed)
 | 
				
			||||||
 | 
					        self.ui.artist_selection_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_search_artist_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        artist = item.text().split(":")
 | 
				
			||||||
 | 
					        artist = (artist[0], artist[1])
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Checked:
 | 
				
			||||||
 | 
					            self.curr_artist = artist
 | 
				
			||||||
 | 
					        elif item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            self.curr_artist = None
 | 
				
			||||||
 | 
					        self.set_artist_result_list(self.__curr_searched_artists)
 | 
				
			||||||
 | 
					        self.set_artist_selected_list(self.curr_artist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_selected_artist_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        artist = item.text().split(":")
 | 
				
			||||||
 | 
					        artist = (artist[0].strip(), artist[1].strip())
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Checked:
 | 
				
			||||||
 | 
					            self.curr_artist = artist
 | 
				
			||||||
 | 
					        elif item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            self.curr_artist = artist
 | 
				
			||||||
 | 
					        self.set_artist_result_list(self.__curr_searched_artists)
 | 
				
			||||||
 | 
					        self.set_artist_selected_list(self.curr_artist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def collect_presence_details(self):
 | 
				
			||||||
 | 
					        self.data = {
 | 
				
			||||||
 | 
					            "name": self.ui.presence_name_line.text(),
 | 
				
			||||||
 | 
					            "domain": self.ui.presence_domain_line.text(),
 | 
				
			||||||
 | 
					            "artist": self.curr_artist,
 | 
				
			||||||
 | 
					            "link": self.ui.presence_link_list.text(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        is_null = True
 | 
				
			||||||
 | 
					        for value in self.data.values():
 | 
				
			||||||
 | 
					            if value is not None and len(value) != 0:
 | 
				
			||||||
 | 
					                is_null = False
 | 
				
			||||||
 | 
					        if is_null:
 | 
				
			||||||
 | 
					            self.data = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exec_(self) -> dict:
 | 
				
			||||||
 | 
					        if super(PresenceModDialog, self).exec_() == QtWidgets.QDialog.Rejected:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        self.collect_presence_details()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.data
 | 
				
			||||||
@ -0,0 +1,149 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'dialogs/presence_modify_dialog/presence_modify_dialog.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_PresenceModDialog(object):
 | 
				
			||||||
 | 
					    def setupUi(self, PresenceModDialog):
 | 
				
			||||||
 | 
					        PresenceModDialog.setObjectName("PresenceModDialog")
 | 
				
			||||||
 | 
					        PresenceModDialog.resize(376, 405)
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(PresenceModDialog)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.frame = QtWidgets.QFrame(PresenceModDialog)
 | 
				
			||||||
 | 
					        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame.setObjectName("frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.dialog_topic_label = QtWidgets.QLabel(self.frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.dialog_topic_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.dialog_topic_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(11)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.dialog_topic_label.setFont(font)
 | 
				
			||||||
 | 
					        self.dialog_topic_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.dialog_topic_label.setObjectName("dialog_topic_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.dialog_topic_label)
 | 
				
			||||||
 | 
					        self.frame_2 = QtWidgets.QFrame(self.frame)
 | 
				
			||||||
 | 
					        self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame_2.setObjectName("frame_2")
 | 
				
			||||||
 | 
					        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_2)
 | 
				
			||||||
 | 
					        self.verticalLayout_3.setSpacing(5)
 | 
				
			||||||
 | 
					        self.verticalLayout_3.setObjectName("verticalLayout_3")
 | 
				
			||||||
 | 
					        self.presence_name_label = QtWidgets.QLabel(self.frame_2)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.presence_name_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.presence_name_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.presence_name_label.setFont(font)
 | 
				
			||||||
 | 
					        self.presence_name_label.setObjectName("presence_name_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.presence_name_label)
 | 
				
			||||||
 | 
					        self.presence_name_line = QtWidgets.QLineEdit(self.frame_2)
 | 
				
			||||||
 | 
					        self.presence_name_line.setObjectName("presence_name_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.presence_name_line)
 | 
				
			||||||
 | 
					        self.presence_domain_label = QtWidgets.QLabel(self.frame_2)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.presence_domain_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.presence_domain_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.presence_domain_label.setFont(font)
 | 
				
			||||||
 | 
					        self.presence_domain_label.setObjectName("presence_domain_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.presence_domain_label)
 | 
				
			||||||
 | 
					        self.presence_domain_line = QtWidgets.QLineEdit(self.frame_2)
 | 
				
			||||||
 | 
					        self.presence_domain_line.setObjectName("presence_domain_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.presence_domain_line)
 | 
				
			||||||
 | 
					        self.presence_link_label = QtWidgets.QLabel(self.frame_2)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.presence_link_label.setFont(font)
 | 
				
			||||||
 | 
					        self.presence_link_label.setObjectName("presence_link_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.presence_link_label)
 | 
				
			||||||
 | 
					        self.presence_link_list = QtWidgets.QLineEdit(self.frame_2)
 | 
				
			||||||
 | 
					        self.presence_link_list.setObjectName("presence_link_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.presence_link_list)
 | 
				
			||||||
 | 
					        self.artist_label = QtWidgets.QLabel(self.frame_2)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.artist_label.setFont(font)
 | 
				
			||||||
 | 
					        self.artist_label.setObjectName("artist_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.artist_label)
 | 
				
			||||||
 | 
					        self.artist_search_line = QtWidgets.QLineEdit(self.frame_2)
 | 
				
			||||||
 | 
					        self.artist_search_line.setObjectName("artist_search_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.artist_search_line)
 | 
				
			||||||
 | 
					        self.artist_result_list = QtWidgets.QListView(self.frame_2)
 | 
				
			||||||
 | 
					        self.artist_result_list.setObjectName("artist_result_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.artist_result_list)
 | 
				
			||||||
 | 
					        self.artist_selection_list = QtWidgets.QListView(self.frame_2)
 | 
				
			||||||
 | 
					        self.artist_selection_list.setObjectName("artist_selection_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.artist_selection_list)
 | 
				
			||||||
 | 
					        self.artist_edit_layout = QtWidgets.QHBoxLayout()
 | 
				
			||||||
 | 
					        self.artist_edit_layout.setObjectName("artist_edit_layout")
 | 
				
			||||||
 | 
					        self.create_artist_button = QtWidgets.QPushButton(self.frame_2)
 | 
				
			||||||
 | 
					        self.create_artist_button.setObjectName("create_artist_button")
 | 
				
			||||||
 | 
					        self.artist_edit_layout.addWidget(self.create_artist_button)
 | 
				
			||||||
 | 
					        self.edit_artist_button = QtWidgets.QPushButton(self.frame_2)
 | 
				
			||||||
 | 
					        self.edit_artist_button.setObjectName("edit_artist_button")
 | 
				
			||||||
 | 
					        self.artist_edit_layout.addWidget(self.edit_artist_button)
 | 
				
			||||||
 | 
					        self.delete_artist_button = QtWidgets.QPushButton(self.frame_2)
 | 
				
			||||||
 | 
					        self.delete_artist_button.setObjectName("delete_artist_button")
 | 
				
			||||||
 | 
					        self.artist_edit_layout.addWidget(self.delete_artist_button)
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addLayout(self.artist_edit_layout)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.frame_2)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.frame)
 | 
				
			||||||
 | 
					        self.buttonBox = QtWidgets.QDialogButtonBox(PresenceModDialog)
 | 
				
			||||||
 | 
					        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
 | 
				
			||||||
 | 
					        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 | 
				
			||||||
 | 
					        self.buttonBox.setObjectName("buttonBox")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.buttonBox)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(PresenceModDialog)
 | 
				
			||||||
 | 
					        self.buttonBox.accepted.connect(PresenceModDialog.accept)
 | 
				
			||||||
 | 
					        self.buttonBox.rejected.connect(PresenceModDialog.reject)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(PresenceModDialog)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, PresenceModDialog):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        PresenceModDialog.setWindowTitle(_translate("PresenceModDialog", "Dialog"))
 | 
				
			||||||
 | 
					        self.dialog_topic_label.setText(_translate("PresenceModDialog", "Presence Topic"))
 | 
				
			||||||
 | 
					        self.presence_name_label.setText(_translate("PresenceModDialog", "Presence Name:"))
 | 
				
			||||||
 | 
					        self.presence_domain_label.setText(_translate("PresenceModDialog", "Presence Domain:"))
 | 
				
			||||||
 | 
					        self.presence_link_label.setText(_translate("PresenceModDialog", "Presence Link:"))
 | 
				
			||||||
 | 
					        self.artist_label.setText(_translate("PresenceModDialog", "Artist:"))
 | 
				
			||||||
 | 
					        self.create_artist_button.setText(_translate("PresenceModDialog", "Create Artist"))
 | 
				
			||||||
 | 
					        self.edit_artist_button.setText(_translate("PresenceModDialog", "Edit Artist"))
 | 
				
			||||||
 | 
					        self.delete_artist_button.setText(_translate("PresenceModDialog", "Delete Artist"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    PresenceModDialog = QtWidgets.QDialog()
 | 
				
			||||||
 | 
					    ui = Ui_PresenceModDialog()
 | 
				
			||||||
 | 
					    ui.setupUi(PresenceModDialog)
 | 
				
			||||||
 | 
					    PresenceModDialog.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,222 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>PresenceModDialog</class>
 | 
				
			||||||
 | 
					 <widget class="QDialog" name="PresenceModDialog">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>376</width>
 | 
				
			||||||
 | 
					    <height>405</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>Dialog</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="frame">
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="dialog_topic_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>11</pointsize>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Presence Topic</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="frame_2">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
				
			||||||
 | 
					         <property name="spacing">
 | 
				
			||||||
 | 
					          <number>5</number>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="presence_name_label">
 | 
				
			||||||
 | 
					           <property name="sizePolicy">
 | 
				
			||||||
 | 
					            <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					             <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					             <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					            </sizepolicy>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Presence Name:</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLineEdit" name="presence_name_line"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="presence_domain_label">
 | 
				
			||||||
 | 
					           <property name="sizePolicy">
 | 
				
			||||||
 | 
					            <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					             <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					             <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					            </sizepolicy>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Presence Domain:</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLineEdit" name="presence_domain_line"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="presence_link_label">
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Presence Link:</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLineEdit" name="presence_link_list"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="artist_label">
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Artist:</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLineEdit" name="artist_search_line"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QListView" name="artist_result_list"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QListView" name="artist_selection_list"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <layout class="QHBoxLayout" name="artist_edit_layout">
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QPushButton" name="create_artist_button">
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Create Artist</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QPushButton" name="edit_artist_button">
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Edit Artist</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QPushButton" name="delete_artist_button">
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Delete Artist</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					          </layout>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					     <property name="orientation">
 | 
				
			||||||
 | 
					      <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="standardButtons">
 | 
				
			||||||
 | 
					      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>accepted()</signal>
 | 
				
			||||||
 | 
					   <receiver>PresenceModDialog</receiver>
 | 
				
			||||||
 | 
					   <slot>accept()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>248</x>
 | 
				
			||||||
 | 
					     <y>254</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>157</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>rejected()</signal>
 | 
				
			||||||
 | 
					   <receiver>PresenceModDialog</receiver>
 | 
				
			||||||
 | 
					   <slot>reject()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>316</x>
 | 
				
			||||||
 | 
					     <y>260</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>286</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					 </connections>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt
 | 
				
			||||||
 | 
					from PyQt5.QtGui import QStandardItem, QStandardItemModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.presence_selection_dialog.presence_selection_dialog import Ui_presence_selection_dialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PresenceSelectDialog(QtWidgets.QDialog):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.parent = parent
 | 
				
			||||||
 | 
					        self.ui = Ui_presence_selection_dialog()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__curr_presence: list = None
 | 
				
			||||||
 | 
					        self.__curr_search_result: list = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.presence_name_search_line.textChanged.connect(self.on_search_change)
 | 
				
			||||||
 | 
					        self.ui.presence_domain_search_line.textChanged.connect(self.on_search_change)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_search_result_list(self, result: list):
 | 
				
			||||||
 | 
					        self.__curr_search_result = result
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.presence_search_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for presence in result:
 | 
				
			||||||
 | 
					            item = QStandardItem(presence)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if self.__curr_presence is not None:
 | 
				
			||||||
 | 
					                curr_presence = self.__curr_presence[0] + ":" + self.__curr_presence[1]
 | 
				
			||||||
 | 
					                if presence == curr_presence:
 | 
				
			||||||
 | 
					                    item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_search_presence_item_changed)
 | 
				
			||||||
 | 
					        self.ui.presence_search_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_search_change(self):
 | 
				
			||||||
 | 
					        name = self.ui.presence_name_search_line.text()
 | 
				
			||||||
 | 
					        domain = self.ui.presence_domain_search_line.text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(name) == 0 and len(domain) == 0:  # nothing to search for
 | 
				
			||||||
 | 
					            self.set_search_result_list([])
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        presences = self.parent.parent.get_authors(name, domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = []
 | 
				
			||||||
 | 
					        for ID, desc in presences:
 | 
				
			||||||
 | 
					            result.append(ID+":"+desc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_search_result_list(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_search_presence_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        name, domain = item.text().split(":")
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Checked:
 | 
				
			||||||
 | 
					            self.__curr_presence = self.parent.parent.get_presence(name, domain)
 | 
				
			||||||
 | 
					            if self.__curr_presence is not None:
 | 
				
			||||||
 | 
					                self.__curr_presence = self.__curr_presence[0]  # unpack from list
 | 
				
			||||||
 | 
					        elif item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            self.__curr_presence = None
 | 
				
			||||||
 | 
					        self.set_search_result_list(self.__curr_search_result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exec_(self) -> list:
 | 
				
			||||||
 | 
					        if super(PresenceSelectDialog, self).exec_() == QtWidgets.QDialog.Rejected:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.__curr_presence
 | 
				
			||||||
@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'dialogs/presence_selection_dialog/presence_selection_dialog.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_presence_selection_dialog(object):
 | 
				
			||||||
 | 
					    def setupUi(self, presence_selection_dialog):
 | 
				
			||||||
 | 
					        presence_selection_dialog.setObjectName("presence_selection_dialog")
 | 
				
			||||||
 | 
					        presence_selection_dialog.resize(330, 260)
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(presence_selection_dialog)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.frame = QtWidgets.QFrame(presence_selection_dialog)
 | 
				
			||||||
 | 
					        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame.setObjectName("frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.label = QtWidgets.QLabel(self.frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(11)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label.setFont(font)
 | 
				
			||||||
 | 
					        self.label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.label.setObjectName("label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.label)
 | 
				
			||||||
 | 
					        self.frame_2 = QtWidgets.QFrame(self.frame)
 | 
				
			||||||
 | 
					        self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame_2.setObjectName("frame_2")
 | 
				
			||||||
 | 
					        self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame_2)
 | 
				
			||||||
 | 
					        self.horizontalLayout.setObjectName("horizontalLayout")
 | 
				
			||||||
 | 
					        self.verticalLayout_4 = QtWidgets.QVBoxLayout()
 | 
				
			||||||
 | 
					        self.verticalLayout_4.setObjectName("verticalLayout_4")
 | 
				
			||||||
 | 
					        self.label_2 = QtWidgets.QLabel(self.frame_2)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label_2.setFont(font)
 | 
				
			||||||
 | 
					        self.label_2.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
 | 
				
			||||||
 | 
					        self.label_2.setObjectName("label_2")
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.label_2)
 | 
				
			||||||
 | 
					        self.presence_name_search_line = QtWidgets.QLineEdit(self.frame_2)
 | 
				
			||||||
 | 
					        self.presence_name_search_line.setObjectName("presence_name_search_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.presence_name_search_line)
 | 
				
			||||||
 | 
					        self.horizontalLayout.addLayout(self.verticalLayout_4)
 | 
				
			||||||
 | 
					        self.verticalLayout_3 = QtWidgets.QVBoxLayout()
 | 
				
			||||||
 | 
					        self.verticalLayout_3.setObjectName("verticalLayout_3")
 | 
				
			||||||
 | 
					        self.label_3 = QtWidgets.QLabel(self.frame_2)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label_3.setFont(font)
 | 
				
			||||||
 | 
					        self.label_3.setObjectName("label_3")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.label_3)
 | 
				
			||||||
 | 
					        self.presence_domain_search_line = QtWidgets.QLineEdit(self.frame_2)
 | 
				
			||||||
 | 
					        self.presence_domain_search_line.setObjectName("presence_domain_search_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.presence_domain_search_line)
 | 
				
			||||||
 | 
					        self.horizontalLayout.addLayout(self.verticalLayout_3)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.frame_2)
 | 
				
			||||||
 | 
					        self.presence_search_list = QtWidgets.QListView(self.frame)
 | 
				
			||||||
 | 
					        self.presence_search_list.setObjectName("presence_search_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.presence_search_list)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.frame)
 | 
				
			||||||
 | 
					        self.buttonBox = QtWidgets.QDialogButtonBox(presence_selection_dialog)
 | 
				
			||||||
 | 
					        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
 | 
				
			||||||
 | 
					        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 | 
				
			||||||
 | 
					        self.buttonBox.setObjectName("buttonBox")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.buttonBox)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(presence_selection_dialog)
 | 
				
			||||||
 | 
					        self.buttonBox.accepted.connect(presence_selection_dialog.accept)
 | 
				
			||||||
 | 
					        self.buttonBox.rejected.connect(presence_selection_dialog.reject)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(presence_selection_dialog)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, presence_selection_dialog):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        presence_selection_dialog.setWindowTitle(_translate("presence_selection_dialog", "Dialog"))
 | 
				
			||||||
 | 
					        self.label.setText(_translate("presence_selection_dialog", "Select Presence"))
 | 
				
			||||||
 | 
					        self.label_2.setText(_translate("presence_selection_dialog", "Name:"))
 | 
				
			||||||
 | 
					        self.label_3.setText(_translate("presence_selection_dialog", "Domain:"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    presence_selection_dialog = QtWidgets.QDialog()
 | 
				
			||||||
 | 
					    ui = Ui_presence_selection_dialog()
 | 
				
			||||||
 | 
					    ui.setupUi(presence_selection_dialog)
 | 
				
			||||||
 | 
					    presence_selection_dialog.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,153 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>presence_selection_dialog</class>
 | 
				
			||||||
 | 
					 <widget class="QDialog" name="presence_selection_dialog">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>330</width>
 | 
				
			||||||
 | 
					    <height>260</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>Dialog</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="frame">
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="label">
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>11</pointsize>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Select Presence</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="frame_2">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QHBoxLayout" name="horizontalLayout">
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <layout class="QVBoxLayout" name="verticalLayout_4">
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QLabel" name="label_2">
 | 
				
			||||||
 | 
					             <property name="font">
 | 
				
			||||||
 | 
					              <font>
 | 
				
			||||||
 | 
					               <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					               <weight>75</weight>
 | 
				
			||||||
 | 
					               <bold>true</bold>
 | 
				
			||||||
 | 
					              </font>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Name:</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="alignment">
 | 
				
			||||||
 | 
					              <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QLineEdit" name="presence_name_search_line"/>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					          </layout>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QLabel" name="label_3">
 | 
				
			||||||
 | 
					             <property name="font">
 | 
				
			||||||
 | 
					              <font>
 | 
				
			||||||
 | 
					               <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					               <weight>75</weight>
 | 
				
			||||||
 | 
					               <bold>true</bold>
 | 
				
			||||||
 | 
					              </font>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Domain:</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QLineEdit" name="presence_domain_search_line"/>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					          </layout>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QListView" name="presence_search_list"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					     <property name="orientation">
 | 
				
			||||||
 | 
					      <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="standardButtons">
 | 
				
			||||||
 | 
					      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>accepted()</signal>
 | 
				
			||||||
 | 
					   <receiver>presence_selection_dialog</receiver>
 | 
				
			||||||
 | 
					   <slot>accept()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>248</x>
 | 
				
			||||||
 | 
					     <y>254</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>157</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>rejected()</signal>
 | 
				
			||||||
 | 
					   <receiver>presence_selection_dialog</receiver>
 | 
				
			||||||
 | 
					   <slot>reject()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>316</x>
 | 
				
			||||||
 | 
					     <y>260</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>286</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					 </connections>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					from PyQt5.QtGui import QStandardItemModel, QStandardItem
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.tag_import_dialog.tag_import_dialog import Ui_Dialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TagImportDialog(QtWidgets.QDialog):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent=parent)
 | 
				
			||||||
 | 
					        self.parent = parent
 | 
				
			||||||
 | 
					        self.ui = Ui_Dialog()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					        self.ui.import_all_button.clicked.connect(self.on_import_all_clicked)
 | 
				
			||||||
 | 
					        self.ui.remove_all_button.clicked.connect(self.on_remove_all_clicked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.to_import = []
 | 
				
			||||||
 | 
					        self.not_import = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_import_tag_list(self, tags: list):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the tags in the imported list
 | 
				
			||||||
 | 
					        :param tags:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        set_checked = True
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.import_list)
 | 
				
			||||||
 | 
					        self.data = tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in tags:
 | 
				
			||||||
 | 
					            item = QStandardItem(tag)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					            if set_checked:
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_import_item_changed)
 | 
				
			||||||
 | 
					        self.ui.import_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_detected_artists(self, artists: list):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the label for detected artists
 | 
				
			||||||
 | 
					        :param artists:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        s = ""
 | 
				
			||||||
 | 
					        for artist in artists:
 | 
				
			||||||
 | 
					            s += artist + " | "
 | 
				
			||||||
 | 
					        s = s[:-3]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.detected_artists_label.setText(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_used_link(self, link: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the label to display the predicted link
 | 
				
			||||||
 | 
					        :param link:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.ui.used_link_label.setText(link)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_ignore_tag_list(self, tags: list):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the tags in the ignore list
 | 
				
			||||||
 | 
					        :param tags:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        set_checked = False
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.ignored_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in tags:
 | 
				
			||||||
 | 
					            item = QStandardItem(tag)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					            if set_checked:
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_ignore_item_changed)
 | 
				
			||||||
 | 
					        self.ui.ignored_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_ignore_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Checked:
 | 
				
			||||||
 | 
					            tag = item.text()
 | 
				
			||||||
 | 
					            self.to_import.append(tag)
 | 
				
			||||||
 | 
					            self.not_import.remove(tag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_import_tag_list(self.to_import)
 | 
				
			||||||
 | 
					        self.set_ignore_tag_list(self.not_import)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_import_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            tag = item.text()
 | 
				
			||||||
 | 
					            self.to_import.remove(tag)
 | 
				
			||||||
 | 
					            self.not_import.append(tag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_import_tag_list(self.to_import)
 | 
				
			||||||
 | 
					        self.set_ignore_tag_list(self.not_import)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_import_all_clicked(self):
 | 
				
			||||||
 | 
					        self.to_import += self.not_import
 | 
				
			||||||
 | 
					        self.not_import = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_import_tag_list(self.to_import)
 | 
				
			||||||
 | 
					        self.set_ignore_tag_list(self.not_import)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_remove_all_clicked(self):
 | 
				
			||||||
 | 
					        self.not_import += self.to_import
 | 
				
			||||||
 | 
					        self.to_import = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_import_tag_list(self.to_import)
 | 
				
			||||||
 | 
					        self.set_ignore_tag_list(self.not_import)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exec_(self) -> int:
 | 
				
			||||||
 | 
					        if super(TagImportDialog, self).exec_() == QtWidgets.QDialog.Rejected:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        return self.data
 | 
				
			||||||
@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'dialogs/tag_import_dialog/tag_import_dialog.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_Dialog(object):
 | 
				
			||||||
 | 
					    def setupUi(self, Dialog):
 | 
				
			||||||
 | 
					        Dialog.setObjectName("Dialog")
 | 
				
			||||||
 | 
					        Dialog.resize(775, 300)
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.label = QtWidgets.QLabel(Dialog)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(12)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label.setFont(font)
 | 
				
			||||||
 | 
					        self.label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.label.setObjectName("label")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.label)
 | 
				
			||||||
 | 
					        self.frame_4 = QtWidgets.QFrame(Dialog)
 | 
				
			||||||
 | 
					        self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame_4.setObjectName("frame_4")
 | 
				
			||||||
 | 
					        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_4)
 | 
				
			||||||
 | 
					        self.verticalLayout_4.setObjectName("verticalLayout_4")
 | 
				
			||||||
 | 
					        self.label_4 = QtWidgets.QLabel(self.frame_4)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(9)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label_4.setFont(font)
 | 
				
			||||||
 | 
					        self.label_4.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.label_4.setObjectName("label_4")
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.label_4)
 | 
				
			||||||
 | 
					        self.detected_artists_label = QtWidgets.QLabel(self.frame_4)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(8)
 | 
				
			||||||
 | 
					        self.detected_artists_label.setFont(font)
 | 
				
			||||||
 | 
					        self.detected_artists_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.detected_artists_label.setObjectName("detected_artists_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.detected_artists_label)
 | 
				
			||||||
 | 
					        self.used_link_label = QtWidgets.QLabel(self.frame_4)
 | 
				
			||||||
 | 
					        self.used_link_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.used_link_label.setObjectName("used_link_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.used_link_label)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.frame_4)
 | 
				
			||||||
 | 
					        self.frame = QtWidgets.QFrame(Dialog)
 | 
				
			||||||
 | 
					        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame.setObjectName("frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout.setObjectName("horizontalLayout")
 | 
				
			||||||
 | 
					        self.frame_2 = QtWidgets.QFrame(self.frame)
 | 
				
			||||||
 | 
					        self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame_2.setObjectName("frame_2")
 | 
				
			||||||
 | 
					        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_2)
 | 
				
			||||||
 | 
					        self.verticalLayout_3.setObjectName("verticalLayout_3")
 | 
				
			||||||
 | 
					        self.label_2 = QtWidgets.QLabel(self.frame_2)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label_2.setFont(font)
 | 
				
			||||||
 | 
					        self.label_2.setObjectName("label_2")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.label_2)
 | 
				
			||||||
 | 
					        self.import_list = QtWidgets.QListView(self.frame_2)
 | 
				
			||||||
 | 
					        self.import_list.setMinimumSize(QtCore.QSize(300, 0))
 | 
				
			||||||
 | 
					        self.import_list.setObjectName("import_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.import_list)
 | 
				
			||||||
 | 
					        self.remove_all_button = QtWidgets.QPushButton(self.frame_2)
 | 
				
			||||||
 | 
					        self.remove_all_button.setObjectName("remove_all_button")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.remove_all_button)
 | 
				
			||||||
 | 
					        self.horizontalLayout.addWidget(self.frame_2)
 | 
				
			||||||
 | 
					        self.frame_3 = QtWidgets.QFrame(self.frame)
 | 
				
			||||||
 | 
					        self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame_3.setObjectName("frame_3")
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_3)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.label_3 = QtWidgets.QLabel(self.frame_3)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label_3.setFont(font)
 | 
				
			||||||
 | 
					        self.label_3.setObjectName("label_3")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.label_3)
 | 
				
			||||||
 | 
					        self.ignored_list = QtWidgets.QListView(self.frame_3)
 | 
				
			||||||
 | 
					        self.ignored_list.setMinimumSize(QtCore.QSize(300, 0))
 | 
				
			||||||
 | 
					        self.ignored_list.setObjectName("ignored_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.ignored_list)
 | 
				
			||||||
 | 
					        self.import_all_button = QtWidgets.QPushButton(self.frame_3)
 | 
				
			||||||
 | 
					        self.import_all_button.setObjectName("import_all_button")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.import_all_button)
 | 
				
			||||||
 | 
					        self.horizontalLayout.addWidget(self.frame_3)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.frame)
 | 
				
			||||||
 | 
					        self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
 | 
				
			||||||
 | 
					        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
 | 
				
			||||||
 | 
					        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 | 
				
			||||||
 | 
					        self.buttonBox.setObjectName("buttonBox")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.buttonBox)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(Dialog)
 | 
				
			||||||
 | 
					        self.buttonBox.accepted.connect(Dialog.accept)
 | 
				
			||||||
 | 
					        self.buttonBox.rejected.connect(Dialog.reject)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(Dialog)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, Dialog):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
 | 
				
			||||||
 | 
					        self.label.setText(_translate("Dialog", "Detected Tags"))
 | 
				
			||||||
 | 
					        self.label_4.setText(_translate("Dialog", "Detected Artists"))
 | 
				
			||||||
 | 
					        self.detected_artists_label.setText(_translate("Dialog", "(None)"))
 | 
				
			||||||
 | 
					        self.used_link_label.setText(_translate("Dialog", "-No Link Used-"))
 | 
				
			||||||
 | 
					        self.label_2.setText(_translate("Dialog", "To be Imported:"))
 | 
				
			||||||
 | 
					        self.remove_all_button.setText(_translate("Dialog", "Remove All"))
 | 
				
			||||||
 | 
					        self.label_3.setText(_translate("Dialog", "To Be Ignored:"))
 | 
				
			||||||
 | 
					        self.import_all_button.setText(_translate("Dialog", "Import All"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    Dialog = QtWidgets.QDialog()
 | 
				
			||||||
 | 
					    ui = Ui_Dialog()
 | 
				
			||||||
 | 
					    ui.setupUi(Dialog)
 | 
				
			||||||
 | 
					    Dialog.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,239 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>Dialog</class>
 | 
				
			||||||
 | 
					 <widget class="QDialog" name="Dialog">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>775</width>
 | 
				
			||||||
 | 
					    <height>300</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>Dialog</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QLabel" name="label">
 | 
				
			||||||
 | 
					     <property name="sizePolicy">
 | 
				
			||||||
 | 
					      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					       <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					       <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					      </sizepolicy>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="font">
 | 
				
			||||||
 | 
					      <font>
 | 
				
			||||||
 | 
					       <pointsize>12</pointsize>
 | 
				
			||||||
 | 
					       <weight>75</weight>
 | 
				
			||||||
 | 
					       <bold>true</bold>
 | 
				
			||||||
 | 
					      </font>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="text">
 | 
				
			||||||
 | 
					      <string>Detected Tags</string>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="alignment">
 | 
				
			||||||
 | 
					      <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="frame_4">
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout_4">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="label_4">
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>9</pointsize>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Detected Artists</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="detected_artists_label">
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>8</pointsize>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>(None)</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="used_link_label">
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>-No Link Used-</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="frame">
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QHBoxLayout" name="horizontalLayout">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="frame_2">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="label_2">
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>To be Imported:</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QListView" name="import_list">
 | 
				
			||||||
 | 
					           <property name="minimumSize">
 | 
				
			||||||
 | 
					            <size>
 | 
				
			||||||
 | 
					             <width>300</width>
 | 
				
			||||||
 | 
					             <height>0</height>
 | 
				
			||||||
 | 
					            </size>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QPushButton" name="remove_all_button">
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Remove All</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="frame_3">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="label_3">
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>To Be Ignored:</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QListView" name="ignored_list">
 | 
				
			||||||
 | 
					           <property name="minimumSize">
 | 
				
			||||||
 | 
					            <size>
 | 
				
			||||||
 | 
					             <width>300</width>
 | 
				
			||||||
 | 
					             <height>0</height>
 | 
				
			||||||
 | 
					            </size>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QPushButton" name="import_all_button">
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Import All</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					     <property name="orientation">
 | 
				
			||||||
 | 
					      <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="standardButtons">
 | 
				
			||||||
 | 
					      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>accepted()</signal>
 | 
				
			||||||
 | 
					   <receiver>Dialog</receiver>
 | 
				
			||||||
 | 
					   <slot>accept()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>248</x>
 | 
				
			||||||
 | 
					     <y>254</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>157</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>rejected()</signal>
 | 
				
			||||||
 | 
					   <receiver>Dialog</receiver>
 | 
				
			||||||
 | 
					   <slot>reject()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>316</x>
 | 
				
			||||||
 | 
					     <y>260</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>286</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					 </connections>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,285 @@
 | 
				
			|||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					from PyQt5.QtGui import QStandardItemModel, QStandardItem
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.tag_modify_dialog.tag_modify_dialog import Ui_TagModify
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TagModifyDialog(QtWidgets.QDialog):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None, create_tag: bool = True):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.parent = parent
 | 
				
			||||||
 | 
					        self.ui = Ui_TagModify()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data = dict()
 | 
				
			||||||
 | 
					        self.original_tag_name: str = None
 | 
				
			||||||
 | 
					        self.create_tag = create_tag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.alias_selection: list = None
 | 
				
			||||||
 | 
					        self.implication_selection: list = None
 | 
				
			||||||
 | 
					        self.tag_alias_search_result: list = None
 | 
				
			||||||
 | 
					        self.tag_implication_search_result: list = None
 | 
				
			||||||
 | 
					        self.category_selection: str = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if create_tag:
 | 
				
			||||||
 | 
					            self.ui.dialog_topic.setText("Create Tag")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.ui.dialog_topic.setText("Edit Tag")
 | 
				
			||||||
 | 
					            self.ui.tag_name_line.setReadOnly(False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.buttonBox.accepted.connect(self.getTagDetails)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.tag_alias_search_line.textChanged.connect(self.on_tag_alias_search_line_changed)
 | 
				
			||||||
 | 
					        self.ui.tag_implication_search_line.textChanged.connect(self.on_tag_implication_search_line_changed)
 | 
				
			||||||
 | 
					        self.set_all_categories()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_search_alias_tags(self, aliases: list, set_checked: bool = False):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the tags in the search result list to tags
 | 
				
			||||||
 | 
					        :param aliases:
 | 
				
			||||||
 | 
					        :param set_checked:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if aliases is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.tag_alias_search_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in aliases:
 | 
				
			||||||
 | 
					            tag = tag[0].strip()
 | 
				
			||||||
 | 
					            if tag == self.ui.tag_name_line.text():
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            item = QStandardItem(tag)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if set_checked:
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_search_alias_tag_item_changed)
 | 
				
			||||||
 | 
					        self.ui.tag_alias_search_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_search_implicated_tags(self, implications: list, set_checked: bool=False):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the tags in the search result list to tags
 | 
				
			||||||
 | 
					        :param implications:
 | 
				
			||||||
 | 
					        :param set_checked:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.tag_implication_search_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in implications:
 | 
				
			||||||
 | 
					            tag = tag[0].strip()
 | 
				
			||||||
 | 
					            if tag == self.ui.tag_name_line.text():
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            item = QStandardItem(tag)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					            if set_checked:
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_search_implicated_tag_item_changed)
 | 
				
			||||||
 | 
					        self.ui.tag_implication_search_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_all_categories(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Populate the categories list and only check the one selection
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        categories = self.parent.get_categories("", all_if_empty=True)
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.category_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for category in categories:
 | 
				
			||||||
 | 
					            category = category.strip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item = QStandardItem(category)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if category == self.category_selection:
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_category_item_changed)
 | 
				
			||||||
 | 
					        self.ui.category_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_selected_alias_tags(self, aliases: list, set_checked: bool=False):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the tags in the search result list to tags
 | 
				
			||||||
 | 
					        :param aliases:
 | 
				
			||||||
 | 
					        :param set_checked:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.tag_alias_selection_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in aliases:
 | 
				
			||||||
 | 
					            tag = tag.strip()
 | 
				
			||||||
 | 
					            if tag == self.ui.tag_name_line.text():
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            item = QStandardItem(tag)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if set_checked:
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_selected_alias_tag_item_changed)
 | 
				
			||||||
 | 
					        self.ui.tag_alias_selection_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_selected_implicated_tags(self, implications: list, set_checked: bool=False):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the tags in the search result list to tags
 | 
				
			||||||
 | 
					        :param implications:
 | 
				
			||||||
 | 
					        :param set_checked:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.tag_implication_search_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in implications:
 | 
				
			||||||
 | 
					            tag = tag.strip()
 | 
				
			||||||
 | 
					            if tag == self.ui.tag_name_line.text():
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            item = QStandardItem(tag)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					            if set_checked:
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_selected_implicated_tag_item_changed)
 | 
				
			||||||
 | 
					        self.ui.tag_implication_selection_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_tag_alias_search_line_changed(self):
 | 
				
			||||||
 | 
					        search_text = self.ui.tag_alias_search_line.text()
 | 
				
			||||||
 | 
					        if len(search_text) == 0:
 | 
				
			||||||
 | 
					            tags = []
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            tags = self.parent.get_tag_search_result(search_text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if tags is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.tag_alias_search_result = tags
 | 
				
			||||||
 | 
					        self.set_search_alias_tags(tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_tag_implication_search_line_changed(self):
 | 
				
			||||||
 | 
					        search_text = self.ui.tag_implication_search_line.text()
 | 
				
			||||||
 | 
					        if len(search_text) == 0:
 | 
				
			||||||
 | 
					            tags = []
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            tags = self.parent.get_tag_search_result(search_text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if tags is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.tag_implication_search_result = tags
 | 
				
			||||||
 | 
					        self.set_search_implicated_tags(tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_search_implicated_tag_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Checked:
 | 
				
			||||||
 | 
					            if self.implication_selection is None:
 | 
				
			||||||
 | 
					                self.implication_selection = []
 | 
				
			||||||
 | 
					            self.implication_selection.append(item.text())
 | 
				
			||||||
 | 
					        elif item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            if item.text() in self.implication_selection:
 | 
				
			||||||
 | 
					                self.implication_selection.remove(item.text())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_selected_implicated_tags(self.implication_selection, set_checked=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_search_alias_tag_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Checked:
 | 
				
			||||||
 | 
					            if self.alias_selection is None:
 | 
				
			||||||
 | 
					                self.alias_selection = []
 | 
				
			||||||
 | 
					            self.alias_selection.append(item.text())
 | 
				
			||||||
 | 
					        elif item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            if item.text() in self.alias_selection:
 | 
				
			||||||
 | 
					                self.alias_selection.remove(item.text())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_selected_alias_tags(self.alias_selection, set_checked=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_selected_implicated_tag_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if self.implication_selection is None:
 | 
				
			||||||
 | 
					            self.implication_selection = []
 | 
				
			||||||
 | 
					        self.implication_selection.remove(item.text())
 | 
				
			||||||
 | 
					        self.set_selected_implicated_tags(self.implication_selection, set_checked=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.tag_implication_search_result is not None:
 | 
				
			||||||
 | 
					            self.set_search_implicated_tags(self.tag_implication_search_result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_selected_alias_tag_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if self.alias_selection is None:
 | 
				
			||||||
 | 
					            self.alias_selection = []
 | 
				
			||||||
 | 
					        self.alias_selection.remove(item.text())
 | 
				
			||||||
 | 
					        self.set_selected_alias_tags(self.alias_selection, set_checked=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_search_alias_tags(self.tag_alias_search_result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_category_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if self.category_selection is None:
 | 
				
			||||||
 | 
					            self.category_selection = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Checked:
 | 
				
			||||||
 | 
					            self.category_selection = item.text()
 | 
				
			||||||
 | 
					        elif item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            self.category_selection = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_all_categories()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def has_critical_info(self) -> bool:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Checks if all required fields are filled
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        ok = True
 | 
				
			||||||
 | 
					        if len(self.ui.tag_name_line.text()) == 0:
 | 
				
			||||||
 | 
					            ok = False
 | 
				
			||||||
 | 
					        if self.category_selection is None:
 | 
				
			||||||
 | 
					            ok = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not ok:
 | 
				
			||||||
 | 
					            msg = QtWidgets.QMessageBox()
 | 
				
			||||||
 | 
					            msg.setWindowTitle("Missing Fields")
 | 
				
			||||||
 | 
					            msg.setIcon(QtWidgets.QMessageBox.Critical)
 | 
				
			||||||
 | 
					            msg.setInformativeText(
 | 
				
			||||||
 | 
					                "Either the tag name or the category selection is empty! Can't save the tag this way!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            msg.exec_()
 | 
				
			||||||
 | 
					        return ok
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getTagDetails(self):
 | 
				
			||||||
 | 
					        self.data = dict()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data["name"] = self.ui.tag_name_line.text()
 | 
				
			||||||
 | 
					        self.data["description"] = self.ui.tag_description_area.toPlainText()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data["aliases"] = self.alias_selection
 | 
				
			||||||
 | 
					        self.data["implications"] = self.implication_selection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data["category"] = self.category_selection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not self.has_critical_info():
 | 
				
			||||||
 | 
					            self.data = None
 | 
				
			||||||
 | 
					            self.reject()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.accept()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exec_(self) -> dict:
 | 
				
			||||||
 | 
					        self.original_tag_name = self.ui.tag_name_line.text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if super(TagModifyDialog, self).exec_() == QtWidgets.QDialog.Rejected:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not self.create_tag:
 | 
				
			||||||
 | 
					            if self.data["name"] != self.original_tag_name:
 | 
				
			||||||
 | 
					                self.data["old_tag_name"] = self.original_tag_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.data
 | 
				
			||||||
@ -0,0 +1,226 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'dialogs/tag_modify_dialog/tag_modify_dialog.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_TagModify(object):
 | 
				
			||||||
 | 
					    def setupUi(self, TagModify):
 | 
				
			||||||
 | 
					        TagModify.setObjectName("TagModify")
 | 
				
			||||||
 | 
					        TagModify.resize(587, 846)
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(TagModify)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.dialog_frame = QtWidgets.QFrame(TagModify)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.dialog_frame.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.dialog_frame.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.dialog_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.dialog_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.dialog_frame.setObjectName("dialog_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.dialog_topic = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.dialog_topic.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.dialog_topic.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.dialog_topic.setFont(font)
 | 
				
			||||||
 | 
					        self.dialog_topic.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.dialog_topic.setObjectName("dialog_topic")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.dialog_topic)
 | 
				
			||||||
 | 
					        self.tag_name_label = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.tag_name_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.tag_name_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.tag_name_label.setFont(font)
 | 
				
			||||||
 | 
					        self.tag_name_label.setObjectName("tag_name_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.tag_name_label)
 | 
				
			||||||
 | 
					        self.tag_name_line = QtWidgets.QLineEdit(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.tag_name_line.setObjectName("tag_name_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.tag_name_line)
 | 
				
			||||||
 | 
					        self.tag_description_label = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.tag_description_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.tag_description_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.tag_description_label.setObjectName("tag_description_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.tag_description_label)
 | 
				
			||||||
 | 
					        self.tag_description_area = QtWidgets.QTextEdit(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.tag_description_area.setMaximumSize(QtCore.QSize(16777215, 100))
 | 
				
			||||||
 | 
					        self.tag_description_area.setObjectName("tag_description_area")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.tag_description_area)
 | 
				
			||||||
 | 
					        self.category_label = QtWidgets.QLabel(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.category_label.setObjectName("category_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.category_label)
 | 
				
			||||||
 | 
					        self.category_list = QtWidgets.QListView(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.category_list.setMaximumSize(QtCore.QSize(16777215, 100))
 | 
				
			||||||
 | 
					        self.category_list.setObjectName("category_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.category_list)
 | 
				
			||||||
 | 
					        self.tag_alias_frame = QtWidgets.QFrame(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.tag_alias_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.tag_alias_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.tag_alias_frame.setObjectName("tag_alias_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tag_alias_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_3.setObjectName("verticalLayout_3")
 | 
				
			||||||
 | 
					        self.tag_alias_label = QtWidgets.QLabel(self.tag_alias_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.tag_alias_label.setFont(font)
 | 
				
			||||||
 | 
					        self.tag_alias_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.tag_alias_label.setObjectName("tag_alias_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.tag_alias_label)
 | 
				
			||||||
 | 
					        self.tag_alias_search_line = QtWidgets.QLineEdit(self.tag_alias_frame)
 | 
				
			||||||
 | 
					        self.tag_alias_search_line.setObjectName("tag_alias_search_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.tag_alias_search_line)
 | 
				
			||||||
 | 
					        self.tag_alias_label_frame = QtWidgets.QFrame(self.tag_alias_frame)
 | 
				
			||||||
 | 
					        self.tag_alias_label_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.tag_alias_label_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.tag_alias_label_frame.setObjectName("tag_alias_label_frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.tag_alias_label_frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
 | 
				
			||||||
 | 
					        self.tag_alias_search_label = QtWidgets.QLabel(self.tag_alias_label_frame)
 | 
				
			||||||
 | 
					        self.tag_alias_search_label.setObjectName("tag_alias_search_label")
 | 
				
			||||||
 | 
					        self.horizontalLayout_2.addWidget(self.tag_alias_search_label)
 | 
				
			||||||
 | 
					        self.tag_alias_selection_label = QtWidgets.QLabel(self.tag_alias_label_frame)
 | 
				
			||||||
 | 
					        self.tag_alias_selection_label.setObjectName("tag_alias_selection_label")
 | 
				
			||||||
 | 
					        self.horizontalLayout_2.addWidget(self.tag_alias_selection_label)
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.tag_alias_label_frame)
 | 
				
			||||||
 | 
					        self.tag_alias_list_frame = QtWidgets.QFrame(self.tag_alias_frame)
 | 
				
			||||||
 | 
					        self.tag_alias_list_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.tag_alias_list_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.tag_alias_list_frame.setObjectName("tag_alias_list_frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout = QtWidgets.QHBoxLayout(self.tag_alias_list_frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout.setObjectName("horizontalLayout")
 | 
				
			||||||
 | 
					        self.tag_alias_search_list = QtWidgets.QListView(self.tag_alias_list_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.tag_alias_search_list.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.tag_alias_search_list.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.tag_alias_search_list.setMaximumSize(QtCore.QSize(16777215, 100))
 | 
				
			||||||
 | 
					        self.tag_alias_search_list.setObjectName("tag_alias_search_list")
 | 
				
			||||||
 | 
					        self.horizontalLayout.addWidget(self.tag_alias_search_list)
 | 
				
			||||||
 | 
					        self.tag_alias_selection_list = QtWidgets.QListView(self.tag_alias_list_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.tag_alias_selection_list.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.tag_alias_selection_list.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.tag_alias_selection_list.setMaximumSize(QtCore.QSize(16777215, 100))
 | 
				
			||||||
 | 
					        self.tag_alias_selection_list.setObjectName("tag_alias_selection_list")
 | 
				
			||||||
 | 
					        self.horizontalLayout.addWidget(self.tag_alias_selection_list)
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.tag_alias_list_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.tag_alias_frame)
 | 
				
			||||||
 | 
					        self.tag_implication_frame = QtWidgets.QFrame(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.tag_implication_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.tag_implication_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.tag_implication_frame.setObjectName("tag_implication_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.tag_implication_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_4.setObjectName("verticalLayout_4")
 | 
				
			||||||
 | 
					        self.tag_implication_label = QtWidgets.QLabel(self.tag_implication_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.tag_implication_label.setFont(font)
 | 
				
			||||||
 | 
					        self.tag_implication_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.tag_implication_label.setObjectName("tag_implication_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.tag_implication_label)
 | 
				
			||||||
 | 
					        self.tag_implication_search_line = QtWidgets.QLineEdit(self.tag_implication_frame)
 | 
				
			||||||
 | 
					        self.tag_implication_search_line.setObjectName("tag_implication_search_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.tag_implication_search_line)
 | 
				
			||||||
 | 
					        self.tag_implication_label_frame = QtWidgets.QFrame(self.tag_implication_frame)
 | 
				
			||||||
 | 
					        self.tag_implication_label_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.tag_implication_label_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.tag_implication_label_frame.setObjectName("tag_implication_label_frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.tag_implication_label_frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
 | 
				
			||||||
 | 
					        self.tag_implication_search_label = QtWidgets.QLabel(self.tag_implication_label_frame)
 | 
				
			||||||
 | 
					        self.tag_implication_search_label.setObjectName("tag_implication_search_label")
 | 
				
			||||||
 | 
					        self.horizontalLayout_3.addWidget(self.tag_implication_search_label)
 | 
				
			||||||
 | 
					        self.tag_implication_selection_label = QtWidgets.QLabel(self.tag_implication_label_frame)
 | 
				
			||||||
 | 
					        self.tag_implication_selection_label.setObjectName("tag_implication_selection_label")
 | 
				
			||||||
 | 
					        self.horizontalLayout_3.addWidget(self.tag_implication_selection_label)
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.tag_implication_label_frame)
 | 
				
			||||||
 | 
					        self.tag_implication_list_frame = QtWidgets.QFrame(self.tag_implication_frame)
 | 
				
			||||||
 | 
					        self.tag_implication_list_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.tag_implication_list_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.tag_implication_list_frame.setObjectName("tag_implication_list_frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.tag_implication_list_frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
 | 
				
			||||||
 | 
					        self.tag_implication_search_list = QtWidgets.QListView(self.tag_implication_list_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.tag_implication_search_list.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.tag_implication_search_list.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.tag_implication_search_list.setMaximumSize(QtCore.QSize(16777215, 100))
 | 
				
			||||||
 | 
					        self.tag_implication_search_list.setObjectName("tag_implication_search_list")
 | 
				
			||||||
 | 
					        self.horizontalLayout_4.addWidget(self.tag_implication_search_list)
 | 
				
			||||||
 | 
					        self.tag_implication_selection_list = QtWidgets.QListView(self.tag_implication_list_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.tag_implication_selection_list.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.tag_implication_selection_list.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.tag_implication_selection_list.setMinimumSize(QtCore.QSize(0, 0))
 | 
				
			||||||
 | 
					        self.tag_implication_selection_list.setMaximumSize(QtCore.QSize(16777215, 100))
 | 
				
			||||||
 | 
					        self.tag_implication_selection_list.setObjectName("tag_implication_selection_list")
 | 
				
			||||||
 | 
					        self.horizontalLayout_4.addWidget(self.tag_implication_selection_list)
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.tag_implication_list_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.tag_implication_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.dialog_frame)
 | 
				
			||||||
 | 
					        self.buttonBox = QtWidgets.QDialogButtonBox(TagModify)
 | 
				
			||||||
 | 
					        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
 | 
				
			||||||
 | 
					        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 | 
				
			||||||
 | 
					        self.buttonBox.setObjectName("buttonBox")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.buttonBox)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(TagModify)
 | 
				
			||||||
 | 
					        self.buttonBox.accepted.connect(TagModify.accept)
 | 
				
			||||||
 | 
					        self.buttonBox.rejected.connect(TagModify.reject)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(TagModify)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, TagModify):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        TagModify.setWindowTitle(_translate("TagModify", "Dialog"))
 | 
				
			||||||
 | 
					        self.dialog_topic.setText(_translate("TagModify", "Tag Topic"))
 | 
				
			||||||
 | 
					        self.tag_name_label.setText(_translate("TagModify", "Tag Name:"))
 | 
				
			||||||
 | 
					        self.tag_description_label.setText(_translate("TagModify", "Description:"))
 | 
				
			||||||
 | 
					        self.category_label.setText(_translate("TagModify", "Category:"))
 | 
				
			||||||
 | 
					        self.tag_alias_label.setText(_translate("TagModify", "Tag Aliases"))
 | 
				
			||||||
 | 
					        self.tag_alias_search_label.setText(_translate("TagModify", "Search Result:"))
 | 
				
			||||||
 | 
					        self.tag_alias_selection_label.setText(_translate("TagModify", "Selection:"))
 | 
				
			||||||
 | 
					        self.tag_implication_label.setText(_translate("TagModify", "Tag Implications"))
 | 
				
			||||||
 | 
					        self.tag_implication_search_label.setText(_translate("TagModify", "Search Result:"))
 | 
				
			||||||
 | 
					        self.tag_implication_selection_label.setText(_translate("TagModify", "Selection:"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    TagModify = QtWidgets.QDialog()
 | 
				
			||||||
 | 
					    ui = Ui_TagModify()
 | 
				
			||||||
 | 
					    ui.setupUi(TagModify)
 | 
				
			||||||
 | 
					    TagModify.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,375 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>TagModify</class>
 | 
				
			||||||
 | 
					 <widget class="QDialog" name="TagModify">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>587</width>
 | 
				
			||||||
 | 
					    <height>846</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>Dialog</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="dialog_frame">
 | 
				
			||||||
 | 
					     <property name="sizePolicy">
 | 
				
			||||||
 | 
					      <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
 | 
				
			||||||
 | 
					       <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					       <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					      </sizepolicy>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="dialog_topic">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Tag Topic</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="tag_name_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Tag Name:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLineEdit" name="tag_name_line"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="tag_description_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Description:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QTextEdit" name="tag_description_area">
 | 
				
			||||||
 | 
					        <property name="maximumSize">
 | 
				
			||||||
 | 
					         <size>
 | 
				
			||||||
 | 
					          <width>16777215</width>
 | 
				
			||||||
 | 
					          <height>100</height>
 | 
				
			||||||
 | 
					         </size>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="category_label">
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Category:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QListView" name="category_list">
 | 
				
			||||||
 | 
					        <property name="maximumSize">
 | 
				
			||||||
 | 
					         <size>
 | 
				
			||||||
 | 
					          <width>16777215</width>
 | 
				
			||||||
 | 
					          <height>100</height>
 | 
				
			||||||
 | 
					         </size>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="tag_alias_frame">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="tag_alias_label">
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Tag Aliases</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="alignment">
 | 
				
			||||||
 | 
					            <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLineEdit" name="tag_alias_search_line"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QFrame" name="tag_alias_label_frame">
 | 
				
			||||||
 | 
					           <property name="frameShape">
 | 
				
			||||||
 | 
					            <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="frameShadow">
 | 
				
			||||||
 | 
					            <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <layout class="QHBoxLayout" name="horizontalLayout_2">
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QLabel" name="tag_alias_search_label">
 | 
				
			||||||
 | 
					              <property name="text">
 | 
				
			||||||
 | 
					               <string>Search Result:</string>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QLabel" name="tag_alias_selection_label">
 | 
				
			||||||
 | 
					              <property name="text">
 | 
				
			||||||
 | 
					               <string>Selection:</string>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					           </layout>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QFrame" name="tag_alias_list_frame">
 | 
				
			||||||
 | 
					           <property name="frameShape">
 | 
				
			||||||
 | 
					            <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="frameShadow">
 | 
				
			||||||
 | 
					            <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <layout class="QHBoxLayout" name="horizontalLayout">
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QListView" name="tag_alias_search_list">
 | 
				
			||||||
 | 
					              <property name="sizePolicy">
 | 
				
			||||||
 | 
					               <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
 | 
				
			||||||
 | 
					                <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					                <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					               </sizepolicy>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					              <property name="maximumSize">
 | 
				
			||||||
 | 
					               <size>
 | 
				
			||||||
 | 
					                <width>16777215</width>
 | 
				
			||||||
 | 
					                <height>100</height>
 | 
				
			||||||
 | 
					               </size>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QListView" name="tag_alias_selection_list">
 | 
				
			||||||
 | 
					              <property name="sizePolicy">
 | 
				
			||||||
 | 
					               <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
 | 
				
			||||||
 | 
					                <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					                <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					               </sizepolicy>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					              <property name="maximumSize">
 | 
				
			||||||
 | 
					               <size>
 | 
				
			||||||
 | 
					                <width>16777215</width>
 | 
				
			||||||
 | 
					                <height>100</height>
 | 
				
			||||||
 | 
					               </size>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					           </layout>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="tag_implication_frame">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="verticalLayout_4">
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="tag_implication_label">
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Tag Implications</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="alignment">
 | 
				
			||||||
 | 
					            <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLineEdit" name="tag_implication_search_line"/>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QFrame" name="tag_implication_label_frame">
 | 
				
			||||||
 | 
					           <property name="frameShape">
 | 
				
			||||||
 | 
					            <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="frameShadow">
 | 
				
			||||||
 | 
					            <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <layout class="QHBoxLayout" name="horizontalLayout_3">
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QLabel" name="tag_implication_search_label">
 | 
				
			||||||
 | 
					              <property name="text">
 | 
				
			||||||
 | 
					               <string>Search Result:</string>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QLabel" name="tag_implication_selection_label">
 | 
				
			||||||
 | 
					              <property name="text">
 | 
				
			||||||
 | 
					               <string>Selection:</string>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					           </layout>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QFrame" name="tag_implication_list_frame">
 | 
				
			||||||
 | 
					           <property name="frameShape">
 | 
				
			||||||
 | 
					            <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="frameShadow">
 | 
				
			||||||
 | 
					            <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <layout class="QHBoxLayout" name="horizontalLayout_4">
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QListView" name="tag_implication_search_list">
 | 
				
			||||||
 | 
					              <property name="sizePolicy">
 | 
				
			||||||
 | 
					               <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
 | 
				
			||||||
 | 
					                <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					                <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					               </sizepolicy>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					              <property name="maximumSize">
 | 
				
			||||||
 | 
					               <size>
 | 
				
			||||||
 | 
					                <width>16777215</width>
 | 
				
			||||||
 | 
					                <height>100</height>
 | 
				
			||||||
 | 
					               </size>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QListView" name="tag_implication_selection_list">
 | 
				
			||||||
 | 
					              <property name="sizePolicy">
 | 
				
			||||||
 | 
					               <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
 | 
				
			||||||
 | 
					                <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					                <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					               </sizepolicy>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					              <property name="minimumSize">
 | 
				
			||||||
 | 
					               <size>
 | 
				
			||||||
 | 
					                <width>0</width>
 | 
				
			||||||
 | 
					                <height>0</height>
 | 
				
			||||||
 | 
					               </size>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					              <property name="maximumSize">
 | 
				
			||||||
 | 
					               <size>
 | 
				
			||||||
 | 
					                <width>16777215</width>
 | 
				
			||||||
 | 
					                <height>100</height>
 | 
				
			||||||
 | 
					               </size>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					           </layout>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					     <property name="orientation">
 | 
				
			||||||
 | 
					      <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="standardButtons">
 | 
				
			||||||
 | 
					      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>accepted()</signal>
 | 
				
			||||||
 | 
					   <receiver>TagModify</receiver>
 | 
				
			||||||
 | 
					   <slot>accept()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>248</x>
 | 
				
			||||||
 | 
					     <y>254</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>157</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>rejected()</signal>
 | 
				
			||||||
 | 
					   <receiver>TagModify</receiver>
 | 
				
			||||||
 | 
					   <slot>reject()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>316</x>
 | 
				
			||||||
 | 
					     <y>260</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>286</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					 </connections>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					from PyQt5.QtGui import QStandardItemModel, QStandardItem
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.tag_select_dialog.tag_selection_dialog import Ui_TagSelection
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TagSelectDialog(QtWidgets.QDialog):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None, delete_tag: bool=False):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.parent = parent
 | 
				
			||||||
 | 
					        self.ui = Ui_TagSelection()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if delete_tag:
 | 
				
			||||||
 | 
					            self.ui.select_tag_label.setText("Select Tag to delete")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.selected_item: QStandardItem = None
 | 
				
			||||||
 | 
					        self.selection: str = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.buttonBox.accepted.connect(self.getTagSelection)
 | 
				
			||||||
 | 
					        self.ui.tag_search_line.textChanged.connect(self.getSearchResult)
 | 
				
			||||||
 | 
					        self.getSearchResult()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getSearchResult(self):
 | 
				
			||||||
 | 
					        search_text = self.ui.tag_search_line.text()
 | 
				
			||||||
 | 
					        tags = self.parent.get_tag_search_result(search_text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if tags is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.set_search_result_list(tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getTagSelection(self) -> str:
 | 
				
			||||||
 | 
					        if self.selected_item is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.selection = self.selected_item.text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_tag_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if self.selected_item is not None:
 | 
				
			||||||
 | 
					            self.selected_item.setCheckState(Qt.Unchecked)
 | 
				
			||||||
 | 
					        self.selected_item = item
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_search_result_list(self, tags: list):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the tags in the search result list to tags
 | 
				
			||||||
 | 
					        :param tags:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.search_result_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in tags:
 | 
				
			||||||
 | 
					            item = QStandardItem(tag[0])
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_tag_item_changed)
 | 
				
			||||||
 | 
					        self.ui.search_result_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def exec_(self) -> dict:
 | 
				
			||||||
 | 
					        if super(TagSelectDialog, self).exec_() == QtWidgets.QDialog.Rejected:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.selection is None:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        tag = self.parent.get_tag(self.selection)[0]
 | 
				
			||||||
 | 
					        tag_data = {
 | 
				
			||||||
 | 
					            "ID": tag[3],
 | 
				
			||||||
 | 
					            "name": tag[0],
 | 
				
			||||||
 | 
					            "description": tag[1],
 | 
				
			||||||
 | 
					            "aliases": self.parent.get_tag_aliases(tag[0]),
 | 
				
			||||||
 | 
					            "implications": self.parent.get_tag_implications(tag[0]),
 | 
				
			||||||
 | 
					            "category": tag[2]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return tag_data
 | 
				
			||||||
@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'dialogs/tag_select_dialog/tag_selection_dialog.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_TagSelection(object):
 | 
				
			||||||
 | 
					    def setupUi(self, TagSelection):
 | 
				
			||||||
 | 
					        TagSelection.setObjectName("TagSelection")
 | 
				
			||||||
 | 
					        TagSelection.resize(400, 300)
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(TagSelection)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.top_frame = QtWidgets.QFrame(TagSelection)
 | 
				
			||||||
 | 
					        self.top_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.top_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.top_frame.setObjectName("top_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(self.top_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.select_tag_label = QtWidgets.QLabel(self.top_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.select_tag_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.select_tag_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.select_tag_label.setFont(font)
 | 
				
			||||||
 | 
					        self.select_tag_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.select_tag_label.setObjectName("select_tag_label")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.select_tag_label)
 | 
				
			||||||
 | 
					        self.tag_search_line = QtWidgets.QLineEdit(self.top_frame)
 | 
				
			||||||
 | 
					        self.tag_search_line.setObjectName("tag_search_line")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.tag_search_line)
 | 
				
			||||||
 | 
					        self.search_result_list = QtWidgets.QListView(self.top_frame)
 | 
				
			||||||
 | 
					        self.search_result_list.setObjectName("search_result_list")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.search_result_list)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.top_frame)
 | 
				
			||||||
 | 
					        self.buttonBox = QtWidgets.QDialogButtonBox(TagSelection)
 | 
				
			||||||
 | 
					        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
 | 
				
			||||||
 | 
					        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
 | 
				
			||||||
 | 
					        self.buttonBox.setObjectName("buttonBox")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.buttonBox)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(TagSelection)
 | 
				
			||||||
 | 
					        self.buttonBox.accepted.connect(TagSelection.accept)
 | 
				
			||||||
 | 
					        self.buttonBox.rejected.connect(TagSelection.reject)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(TagSelection)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, TagSelection):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        TagSelection.setWindowTitle(_translate("TagSelection", "Dialog"))
 | 
				
			||||||
 | 
					        self.select_tag_label.setText(_translate("TagSelection", "Select Tag"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    TagSelection = QtWidgets.QDialog()
 | 
				
			||||||
 | 
					    ui = Ui_TagSelection()
 | 
				
			||||||
 | 
					    ui.setupUi(TagSelection)
 | 
				
			||||||
 | 
					    TagSelection.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,104 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>TagSelection</class>
 | 
				
			||||||
 | 
					 <widget class="QDialog" name="TagSelection">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>400</width>
 | 
				
			||||||
 | 
					    <height>300</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>Dialog</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="top_frame">
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="select_tag_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Select Tag</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLineEdit" name="tag_search_line"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QListView" name="search_result_list"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QDialogButtonBox" name="buttonBox">
 | 
				
			||||||
 | 
					     <property name="orientation">
 | 
				
			||||||
 | 
					      <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="standardButtons">
 | 
				
			||||||
 | 
					      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>accepted()</signal>
 | 
				
			||||||
 | 
					   <receiver>TagSelection</receiver>
 | 
				
			||||||
 | 
					   <slot>accept()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>248</x>
 | 
				
			||||||
 | 
					     <y>254</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>157</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					  <connection>
 | 
				
			||||||
 | 
					   <sender>buttonBox</sender>
 | 
				
			||||||
 | 
					   <signal>rejected()</signal>
 | 
				
			||||||
 | 
					   <receiver>TagSelection</receiver>
 | 
				
			||||||
 | 
					   <slot>reject()</slot>
 | 
				
			||||||
 | 
					   <hints>
 | 
				
			||||||
 | 
					    <hint type="sourcelabel">
 | 
				
			||||||
 | 
					     <x>316</x>
 | 
				
			||||||
 | 
					     <y>260</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					    <hint type="destinationlabel">
 | 
				
			||||||
 | 
					     <x>286</x>
 | 
				
			||||||
 | 
					     <y>274</y>
 | 
				
			||||||
 | 
					    </hint>
 | 
				
			||||||
 | 
					   </hints>
 | 
				
			||||||
 | 
					  </connection>
 | 
				
			||||||
 | 
					 </connections>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,146 @@
 | 
				
			|||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					from PyQt5.QtGui import QStandardItem, QStandardItemModel
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.dockers.presence.presence_docker import Ui_presence_docker
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.presence_modify_dialog.presence_mod_dialog import PresenceModDialog
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.presence_selection_dialog.presence_select_dialog import PresenceSelectDialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PresenceDocker(QtWidgets.QFrame):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					        self.parent = parent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui = Ui_presence_docker()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.name_line.textChanged.connect(self.on_search_bar_change)
 | 
				
			||||||
 | 
					        self.ui.domain_line.textChanged.connect(self.on_search_bar_change)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.create_presence_button.clicked.connect(self.on_create_presence_clicked)
 | 
				
			||||||
 | 
					        self.ui.edit_presence_button.clicked.connect(self.on_edit_presence_clicked)
 | 
				
			||||||
 | 
					        self.ui.delete_presence_button.clicked.connect(self.on_delete_presence_clicked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.on_search_bar_change()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_presence_list(self, presences: list):
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.search_author_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for name, domain in presences:
 | 
				
			||||||
 | 
					            item = QStandardItem(name+":"+domain)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					            if (name, domain) in self.parent.get_current_presences():
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_presence_item_change)
 | 
				
			||||||
 | 
					        self.ui.search_author_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_selected_presences_list(self, presences: list):
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.selected_presence_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for name, domain in presences:
 | 
				
			||||||
 | 
					            item = QStandardItem(name + ":" + domain)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if domain == "(Not in Database)":
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					            if (name, domain) in self.parent.get_current_presences():
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_selected_presence_item_change)
 | 
				
			||||||
 | 
					        self.ui.selected_presence_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_search_bar_change(self):
 | 
				
			||||||
 | 
					        authors = self.parent.get_authors(self.ui.name_line.text(), self.ui.domain_line.text())
 | 
				
			||||||
 | 
					        self.set_presence_list(authors)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_presence_item_change(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Checked:
 | 
				
			||||||
 | 
					            s = item.text().split(":")
 | 
				
			||||||
 | 
					            s = (s[0], s[1])
 | 
				
			||||||
 | 
					            if self.parent.get_current_presences() is None:
 | 
				
			||||||
 | 
					                self.parent.set_current_presences([s])
 | 
				
			||||||
 | 
					                self.set_selected_presences_list([s])
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.parent.set_current_presences(self.parent.get_current_presences() + [s])
 | 
				
			||||||
 | 
					                self.set_selected_presences_list(self.parent.get_current_presences())
 | 
				
			||||||
 | 
					        elif item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            presences = self.parent.get_current_presences()
 | 
				
			||||||
 | 
					            if presences is None:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            s = item.text().split(":")
 | 
				
			||||||
 | 
					            s = (s[0], s[1])
 | 
				
			||||||
 | 
					            presences.remove(s)
 | 
				
			||||||
 | 
					            self.parent.set_current_presences(presences)
 | 
				
			||||||
 | 
					            self.set_selected_presences_list(presences)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_selected_presence_item_change(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        item_presence = item.text().split(":")
 | 
				
			||||||
 | 
					        item_presence = (item_presence[0], item_presence[1])
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            presences = self.parent.get_current_presences()
 | 
				
			||||||
 | 
					            presences.remove(item_presence)
 | 
				
			||||||
 | 
					            self.parent.set_current_presences(presences)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.set_selected_presences_list(presences)
 | 
				
			||||||
 | 
					            self.on_search_bar_change()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_create_presence_clicked(self):
 | 
				
			||||||
 | 
					        dialog = PresenceModDialog(self, edit_presence=False)
 | 
				
			||||||
 | 
					        data = dialog.exec_()
 | 
				
			||||||
 | 
					        if data is None:  # canceled?
 | 
				
			||||||
 | 
					            self.on_search_bar_change()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.parent.create_presence(name=data["name"], domain=data["domain"], artist=data["artist"],
 | 
				
			||||||
 | 
					                                    link=data["link"])
 | 
				
			||||||
 | 
					        self.on_search_bar_change()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_edit_presence_clicked(self):
 | 
				
			||||||
 | 
					        select_dialog = PresenceSelectDialog(self)
 | 
				
			||||||
 | 
					        selected_presence = select_dialog.exec_()
 | 
				
			||||||
 | 
					        if selected_presence is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dialog = PresenceModDialog(self, edit_presence=True)
 | 
				
			||||||
 | 
					        dialog.ui.presence_name_line.setText(selected_presence[0])
 | 
				
			||||||
 | 
					        dialog.ui.presence_domain_line.setText(selected_presence[1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(selected_presence) > 2:
 | 
				
			||||||
 | 
					            if len(selected_presence) >= 4:
 | 
				
			||||||
 | 
					                if selected_presence[3] is not None:
 | 
				
			||||||
 | 
					                    dialog.ui.presence_link_list.setText(selected_presence[3])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            artist = self.parent.get_artists(selected_presence[2])[0]
 | 
				
			||||||
 | 
					            dialog.curr_artist = artist
 | 
				
			||||||
 | 
					            dialog.set_artist_selected_list(dialog.curr_artist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data = dialog.exec_()
 | 
				
			||||||
 | 
					        if data is None:
 | 
				
			||||||
 | 
					            self.on_search_bar_change()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.parent.create_presence(name=data["name"], domain=data["domain"], artist=data["artist"], link=data["link"])
 | 
				
			||||||
 | 
					        self.parent.set_temporary_status_message("Saved Presence {0}:{1} Artist:{2} link:{3} to DB!"
 | 
				
			||||||
 | 
					                                                 .format(data["name"], data["domain"], data["artist"], data["link"]),
 | 
				
			||||||
 | 
					                                                 3000)
 | 
				
			||||||
 | 
					        self.on_search_bar_change()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_delete_presence_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked delete presence button!")
 | 
				
			||||||
 | 
					        select_dialog = PresenceSelectDialog(self)
 | 
				
			||||||
 | 
					        selected_presence = select_dialog.exec_()
 | 
				
			||||||
 | 
					        if selected_presence is None:
 | 
				
			||||||
 | 
					            self.on_search_bar_change()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.parent.remove_presence(selected_presence[0], selected_presence[1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.on_search_bar_change()
 | 
				
			||||||
@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'dockers/presence/presence_docker.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_presence_docker(object):
 | 
				
			||||||
 | 
					    def setupUi(self, presence_docker):
 | 
				
			||||||
 | 
					        presence_docker.setObjectName("presence_docker")
 | 
				
			||||||
 | 
					        presence_docker.resize(338, 576)
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(presence_docker)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.frame = QtWidgets.QFrame(presence_docker)
 | 
				
			||||||
 | 
					        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame.setObjectName("frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.docker_topic_label = QtWidgets.QLabel(self.frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.docker_topic_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.docker_topic_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(13)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.docker_topic_label.setFont(font)
 | 
				
			||||||
 | 
					        self.docker_topic_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.docker_topic_label.setObjectName("docker_topic_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.docker_topic_label)
 | 
				
			||||||
 | 
					        self.search_author_label = QtWidgets.QLabel(self.frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.search_author_label.setFont(font)
 | 
				
			||||||
 | 
					        self.search_author_label.setObjectName("search_author_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.search_author_label)
 | 
				
			||||||
 | 
					        self.search_frame = QtWidgets.QFrame(self.frame)
 | 
				
			||||||
 | 
					        self.search_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.search_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.search_frame.setObjectName("search_frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.search_frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
 | 
				
			||||||
 | 
					        self.name_frame = QtWidgets.QFrame(self.search_frame)
 | 
				
			||||||
 | 
					        self.name_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.name_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.name_frame.setObjectName("name_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.name_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_3.setObjectName("verticalLayout_3")
 | 
				
			||||||
 | 
					        self.name_label = QtWidgets.QLabel(self.name_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.name_label.setFont(font)
 | 
				
			||||||
 | 
					        self.name_label.setObjectName("name_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.name_label)
 | 
				
			||||||
 | 
					        self.name_line = QtWidgets.QLineEdit(self.name_frame)
 | 
				
			||||||
 | 
					        self.name_line.setObjectName("name_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_3.addWidget(self.name_line)
 | 
				
			||||||
 | 
					        self.horizontalLayout_3.addWidget(self.name_frame)
 | 
				
			||||||
 | 
					        self.domain_frame = QtWidgets.QFrame(self.search_frame)
 | 
				
			||||||
 | 
					        self.domain_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.domain_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.domain_frame.setObjectName("domain_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.domain_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_4.setObjectName("verticalLayout_4")
 | 
				
			||||||
 | 
					        self.domain_label = QtWidgets.QLabel(self.domain_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.domain_label.setFont(font)
 | 
				
			||||||
 | 
					        self.domain_label.setObjectName("domain_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.domain_label)
 | 
				
			||||||
 | 
					        self.domain_line = QtWidgets.QLineEdit(self.domain_frame)
 | 
				
			||||||
 | 
					        self.domain_line.setObjectName("domain_line")
 | 
				
			||||||
 | 
					        self.verticalLayout_4.addWidget(self.domain_line)
 | 
				
			||||||
 | 
					        self.horizontalLayout_3.addWidget(self.domain_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.search_frame)
 | 
				
			||||||
 | 
					        self.search_author_list = QtWidgets.QListView(self.frame)
 | 
				
			||||||
 | 
					        self.search_author_list.setObjectName("search_author_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.search_author_list)
 | 
				
			||||||
 | 
					        self.selected_presence_label = QtWidgets.QLabel(self.frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.selected_presence_label.setFont(font)
 | 
				
			||||||
 | 
					        self.selected_presence_label.setObjectName("selected_presence_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.selected_presence_label)
 | 
				
			||||||
 | 
					        self.selected_presence_list = QtWidgets.QListView(self.frame)
 | 
				
			||||||
 | 
					        self.selected_presence_list.setObjectName("selected_presence_list")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.selected_presence_list)
 | 
				
			||||||
 | 
					        self.presence_docker_button_frame = QtWidgets.QFrame(self.frame)
 | 
				
			||||||
 | 
					        self.presence_docker_button_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.presence_docker_button_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.presence_docker_button_frame.setObjectName("presence_docker_button_frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout = QtWidgets.QHBoxLayout(self.presence_docker_button_frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout.setObjectName("horizontalLayout")
 | 
				
			||||||
 | 
					        self.create_presence_button = QtWidgets.QPushButton(self.presence_docker_button_frame)
 | 
				
			||||||
 | 
					        self.create_presence_button.setObjectName("create_presence_button")
 | 
				
			||||||
 | 
					        self.horizontalLayout.addWidget(self.create_presence_button)
 | 
				
			||||||
 | 
					        self.edit_presence_button = QtWidgets.QPushButton(self.presence_docker_button_frame)
 | 
				
			||||||
 | 
					        self.edit_presence_button.setObjectName("edit_presence_button")
 | 
				
			||||||
 | 
					        self.horizontalLayout.addWidget(self.edit_presence_button)
 | 
				
			||||||
 | 
					        self.delete_presence_button = QtWidgets.QPushButton(self.presence_docker_button_frame)
 | 
				
			||||||
 | 
					        self.delete_presence_button.setObjectName("delete_presence_button")
 | 
				
			||||||
 | 
					        self.horizontalLayout.addWidget(self.delete_presence_button)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.presence_docker_button_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.frame)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(presence_docker)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(presence_docker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, presence_docker):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        presence_docker.setWindowTitle(_translate("presence_docker", "Form"))
 | 
				
			||||||
 | 
					        self.docker_topic_label.setText(_translate("presence_docker", "Author (Presence)"))
 | 
				
			||||||
 | 
					        self.search_author_label.setText(_translate("presence_docker", "Search Authors:"))
 | 
				
			||||||
 | 
					        self.name_label.setText(_translate("presence_docker", "Name:"))
 | 
				
			||||||
 | 
					        self.domain_label.setText(_translate("presence_docker", "Domain:"))
 | 
				
			||||||
 | 
					        self.selected_presence_label.setText(_translate("presence_docker", "Selected Presences:"))
 | 
				
			||||||
 | 
					        self.create_presence_button.setText(_translate("presence_docker", "Create Presence"))
 | 
				
			||||||
 | 
					        self.edit_presence_button.setText(_translate("presence_docker", "Edit Presence"))
 | 
				
			||||||
 | 
					        self.delete_presence_button.setText(_translate("presence_docker", "Delete Presence"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    presence_docker = QtWidgets.QWidget()
 | 
				
			||||||
 | 
					    ui = Ui_presence_docker()
 | 
				
			||||||
 | 
					    ui.setupUi(presence_docker)
 | 
				
			||||||
 | 
					    presence_docker.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,190 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>presence_docker</class>
 | 
				
			||||||
 | 
					 <widget class="QWidget" name="presence_docker">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>338</width>
 | 
				
			||||||
 | 
					    <height>576</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>Form</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					   <item>
 | 
				
			||||||
 | 
					    <widget class="QFrame" name="frame">
 | 
				
			||||||
 | 
					     <property name="frameShape">
 | 
				
			||||||
 | 
					      <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <property name="frameShadow">
 | 
				
			||||||
 | 
					      <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					     </property>
 | 
				
			||||||
 | 
					     <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="docker_topic_label">
 | 
				
			||||||
 | 
					        <property name="sizePolicy">
 | 
				
			||||||
 | 
					         <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
 | 
				
			||||||
 | 
					          <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					          <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					         </sizepolicy>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>13</pointsize>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Author (Presence)</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="alignment">
 | 
				
			||||||
 | 
					         <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="search_author_label">
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Search Authors:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="search_frame">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QHBoxLayout" name="horizontalLayout_3">
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QFrame" name="name_frame">
 | 
				
			||||||
 | 
					           <property name="frameShape">
 | 
				
			||||||
 | 
					            <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="frameShadow">
 | 
				
			||||||
 | 
					            <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QLabel" name="name_label">
 | 
				
			||||||
 | 
					              <property name="font">
 | 
				
			||||||
 | 
					               <font>
 | 
				
			||||||
 | 
					                <weight>75</weight>
 | 
				
			||||||
 | 
					                <bold>true</bold>
 | 
				
			||||||
 | 
					               </font>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					              <property name="text">
 | 
				
			||||||
 | 
					               <string>Name:</string>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QLineEdit" name="name_line"/>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					           </layout>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QFrame" name="domain_frame">
 | 
				
			||||||
 | 
					           <property name="frameShape">
 | 
				
			||||||
 | 
					            <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="frameShadow">
 | 
				
			||||||
 | 
					            <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <layout class="QVBoxLayout" name="verticalLayout_4">
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QLabel" name="domain_label">
 | 
				
			||||||
 | 
					              <property name="font">
 | 
				
			||||||
 | 
					               <font>
 | 
				
			||||||
 | 
					                <weight>75</weight>
 | 
				
			||||||
 | 
					                <bold>true</bold>
 | 
				
			||||||
 | 
					               </font>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					              <property name="text">
 | 
				
			||||||
 | 
					               <string>Domain:</string>
 | 
				
			||||||
 | 
					              </property>
 | 
				
			||||||
 | 
					             </widget>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					            <item>
 | 
				
			||||||
 | 
					             <widget class="QLineEdit" name="domain_line"/>
 | 
				
			||||||
 | 
					            </item>
 | 
				
			||||||
 | 
					           </layout>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QListView" name="search_author_list"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QLabel" name="selected_presence_label">
 | 
				
			||||||
 | 
					        <property name="font">
 | 
				
			||||||
 | 
					         <font>
 | 
				
			||||||
 | 
					          <weight>75</weight>
 | 
				
			||||||
 | 
					          <bold>true</bold>
 | 
				
			||||||
 | 
					         </font>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="text">
 | 
				
			||||||
 | 
					         <string>Selected Presences:</string>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QListView" name="selected_presence_list"/>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					      <item>
 | 
				
			||||||
 | 
					       <widget class="QFrame" name="presence_docker_button_frame">
 | 
				
			||||||
 | 
					        <property name="frameShape">
 | 
				
			||||||
 | 
					         <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <property name="frameShadow">
 | 
				
			||||||
 | 
					         <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					        </property>
 | 
				
			||||||
 | 
					        <layout class="QHBoxLayout" name="horizontalLayout">
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QPushButton" name="create_presence_button">
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Create Presence</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QPushButton" name="edit_presence_button">
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Edit Presence</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QPushButton" name="delete_presence_button">
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Delete Presence</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </widget>
 | 
				
			||||||
 | 
					      </item>
 | 
				
			||||||
 | 
					     </layout>
 | 
				
			||||||
 | 
					    </widget>
 | 
				
			||||||
 | 
					   </item>
 | 
				
			||||||
 | 
					  </layout>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections/>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,104 @@
 | 
				
			|||||||
 | 
					from PyQt5.QtWidgets import QMainWindow, QWidget, QLabel, QDesktopWidget, QToolBar, QPushButton, QGroupBox, QGridLayout
 | 
				
			||||||
 | 
					from PyQt5.QtWidgets import QVBoxLayout
 | 
				
			||||||
 | 
					from PyQt5.QtGui import QPixmap
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PictureImporter(QMainWindow):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, parent=None, max_relative_resize_width: float = 0.8, max_relative_resize_height: float = 0.8,):
 | 
				
			||||||
 | 
					        super().__init__(parent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Menubar
 | 
				
			||||||
 | 
					        self.__menu_bar = self.menuBar()
 | 
				
			||||||
 | 
					        self.__menu_bar.addAction("Action1")
 | 
				
			||||||
 | 
					        self.__menu_bar.addAction("Action2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Toolbar
 | 
				
			||||||
 | 
					        open = QToolBar()
 | 
				
			||||||
 | 
					        open.addAction("Open")
 | 
				
			||||||
 | 
					        self.addToolBar(open)
 | 
				
			||||||
 | 
					        close = QToolBar()
 | 
				
			||||||
 | 
					        close.addAction("Close")
 | 
				
			||||||
 | 
					        self.addToolBar(close)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # layout
 | 
				
			||||||
 | 
					        self.__layout = QGridLayout()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Central Component Settings
 | 
				
			||||||
 | 
					        self.__window = QWidget()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.setCentralWidget(self.__window)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Statusbar Settings
 | 
				
			||||||
 | 
					        self.__status_bar = self.statusBar()
 | 
				
			||||||
 | 
					        self.__status_bar.showMessage("Welcome to ArtNet! :)", 5000)
 | 
				
			||||||
 | 
					        label = QLabel("ArtNet - v0.1")
 | 
				
			||||||
 | 
					        self.__status_bar.addPermanentWidget(label)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.resize(800, 600)
 | 
				
			||||||
 | 
					        self.setWindowTitle("ArtNet - Picture Importer")
 | 
				
			||||||
 | 
					        self.center()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def center(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Centers the window in the middle of the screen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        screen = QDesktopWidget().screenGeometry()
 | 
				
			||||||
 | 
					        size = self.geometry()
 | 
				
			||||||
 | 
					        self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @DeprecationWarning
 | 
				
			||||||
 | 
					    def display_geometry(self):
 | 
				
			||||||
 | 
					        x = self.x()
 | 
				
			||||||
 | 
					        y = self.y()
 | 
				
			||||||
 | 
					        print("x: {0}, y: {1}".format(x, y))
 | 
				
			||||||
 | 
					        x = self.pos().x()
 | 
				
			||||||
 | 
					        y = self.pos().y()
 | 
				
			||||||
 | 
					        print("x: {0}, y: {1}".format(x, y))
 | 
				
			||||||
 | 
					        x = self.frameGeometry().x()
 | 
				
			||||||
 | 
					        y = self.frameGeometry().y()
 | 
				
			||||||
 | 
					        print("x: {0}, y: {1}".format(x, y))
 | 
				
			||||||
 | 
					        x = self.geometry().x()
 | 
				
			||||||
 | 
					        y = self.geometry().y()
 | 
				
			||||||
 | 
					        print("x: {0}, y: {1}".format(x, y))
 | 
				
			||||||
 | 
					        print("geometry: ", self.geometry())
 | 
				
			||||||
 | 
					        print("frameGeometry: ", self.frameGeometry())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_temporary_status_message(self, text: str, duration: int):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set a temporary status message (bottom left) for the given duration in milliseconds.
 | 
				
			||||||
 | 
					        :param text:
 | 
				
			||||||
 | 
					        :param duration:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.__status_bar.showMessage("Welcome to ArtNet! :)", 5000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def display_image(self, full_path: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Display an image in the central widget
 | 
				
			||||||
 | 
					        :param full_path:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        label = QLabel(self)
 | 
				
			||||||
 | 
					        pixmap = self.__image_resize(QPixmap(full_path))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        label.setPixmap(pixmap)
 | 
				
			||||||
 | 
					        label.setAlignment(Qt.AlignCenter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.setCentralWidget(label)
 | 
				
			||||||
 | 
					        self.center()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __image_resize(self, pixmap: QPixmap) -> QPixmap:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Resize the given pixmap so that we're not out of the desktop.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :return: new scaled QPixmap
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return pixmap
 | 
				
			||||||
 | 
					        screen_rect = QDesktopWidget().screenGeometry()
 | 
				
			||||||
 | 
					        print("Resizing pixmap to", int(screen_rect.width()*0.4), int(screen_rect.height()*0.6))
 | 
				
			||||||
 | 
					        return pixmap.scaled(int(screen_rect.width()*0.6), int(screen_rect.height()*0.7), Qt.KeepAspectRatio)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,349 @@
 | 
				
			|||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Form implementation generated from reading ui file 'picture_importer.ui'
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Created by: PyQt5 UI code generator 5.15.0
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# WARNING: Any manual changes made to this file will be lost when pyuic5 is
 | 
				
			||||||
 | 
					# run again.  Do not edit this file unless you know what you are doing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtCore, QtGui, QtWidgets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Ui_MainWindow(object):
 | 
				
			||||||
 | 
					    def setupUi(self, MainWindow):
 | 
				
			||||||
 | 
					        MainWindow.setObjectName("MainWindow")
 | 
				
			||||||
 | 
					        MainWindow.resize(827, 777)
 | 
				
			||||||
 | 
					        self.centralwidget = QtWidgets.QWidget(MainWindow)
 | 
				
			||||||
 | 
					        self.centralwidget.setEnabled(True)
 | 
				
			||||||
 | 
					        self.centralwidget.setObjectName("centralwidget")
 | 
				
			||||||
 | 
					        self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
 | 
				
			||||||
 | 
					        self.horizontalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
 | 
				
			||||||
 | 
					        self.horizontalLayout.setObjectName("horizontalLayout")
 | 
				
			||||||
 | 
					        self.left_frame = QtWidgets.QFrame(self.centralwidget)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.left_frame.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.left_frame.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.left_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.left_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.left_frame.setObjectName("left_frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.left_frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
 | 
				
			||||||
 | 
					        self.presence_docker_button = QtWidgets.QToolButton(self.left_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Expanding)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.presence_docker_button.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.presence_docker_button.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.presence_docker_button.setObjectName("presence_docker_button")
 | 
				
			||||||
 | 
					        self.horizontalLayout_2.addWidget(self.presence_docker_button)
 | 
				
			||||||
 | 
					        self.presence_docker_layout = QtWidgets.QVBoxLayout()
 | 
				
			||||||
 | 
					        self.presence_docker_layout.setObjectName("presence_docker_layout")
 | 
				
			||||||
 | 
					        self.horizontalLayout_2.addLayout(self.presence_docker_layout)
 | 
				
			||||||
 | 
					        self.left_layout = QtWidgets.QVBoxLayout()
 | 
				
			||||||
 | 
					        self.left_layout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
 | 
				
			||||||
 | 
					        self.left_layout.setObjectName("left_layout")
 | 
				
			||||||
 | 
					        self.prev_image_button = QtWidgets.QToolButton(self.left_frame)
 | 
				
			||||||
 | 
					        self.prev_image_button.setObjectName("prev_image_button")
 | 
				
			||||||
 | 
					        self.left_layout.addWidget(self.prev_image_button)
 | 
				
			||||||
 | 
					        self.horizontalLayout_2.addLayout(self.left_layout)
 | 
				
			||||||
 | 
					        self.center_frame = QtWidgets.QFrame(self.left_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.center_frame.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.center_frame.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.center_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.center_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.center_frame.setObjectName("center_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout = QtWidgets.QVBoxLayout(self.center_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout.setObjectName("verticalLayout")
 | 
				
			||||||
 | 
					        self.frame = QtWidgets.QFrame(self.center_frame)
 | 
				
			||||||
 | 
					        self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.frame.setObjectName("frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
 | 
				
			||||||
 | 
					        self.image_title_line = QtWidgets.QLineEdit(self.frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.image_title_line.setFont(font)
 | 
				
			||||||
 | 
					        self.image_title_line.setAutoFillBackground(False)
 | 
				
			||||||
 | 
					        self.image_title_line.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.image_title_line.setReadOnly(False)
 | 
				
			||||||
 | 
					        self.image_title_line.setObjectName("image_title_line")
 | 
				
			||||||
 | 
					        self.horizontalLayout_4.addWidget(self.image_title_line)
 | 
				
			||||||
 | 
					        self.imageNumberSpinBox = QtWidgets.QSpinBox(self.frame)
 | 
				
			||||||
 | 
					        self.imageNumberSpinBox.setObjectName("imageNumberSpinBox")
 | 
				
			||||||
 | 
					        self.horizontalLayout_4.addWidget(self.imageNumberSpinBox)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.frame)
 | 
				
			||||||
 | 
					        self.image_file_label = QtWidgets.QLabel(self.center_frame)
 | 
				
			||||||
 | 
					        self.image_file_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.image_file_label.setObjectName("image_file_label")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.image_file_label)
 | 
				
			||||||
 | 
					        self.author_by = QtWidgets.QLabel(self.center_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.author_by.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.author_by.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(7)
 | 
				
			||||||
 | 
					        font.setBold(False)
 | 
				
			||||||
 | 
					        font.setWeight(50)
 | 
				
			||||||
 | 
					        self.author_by.setFont(font)
 | 
				
			||||||
 | 
					        self.author_by.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.author_by.setObjectName("author_by")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.author_by)
 | 
				
			||||||
 | 
					        self.image_author_label = QtWidgets.QLabel(self.center_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(10)
 | 
				
			||||||
 | 
					        font.setBold(False)
 | 
				
			||||||
 | 
					        font.setItalic(False)
 | 
				
			||||||
 | 
					        font.setWeight(50)
 | 
				
			||||||
 | 
					        self.image_author_label.setFont(font)
 | 
				
			||||||
 | 
					        self.image_author_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.image_author_label.setObjectName("image_author_label")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.image_author_label)
 | 
				
			||||||
 | 
					        self.image_frame = QtWidgets.QFrame(self.center_frame)
 | 
				
			||||||
 | 
					        self.image_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.image_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.image_frame.setObjectName("image_frame")
 | 
				
			||||||
 | 
					        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.image_frame)
 | 
				
			||||||
 | 
					        self.verticalLayout_2.setObjectName("verticalLayout_2")
 | 
				
			||||||
 | 
					        self.image_label = QtWidgets.QLabel(self.image_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.image_label.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.image_label.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.image_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.image_label.setObjectName("image_label")
 | 
				
			||||||
 | 
					        self.verticalLayout_2.addWidget(self.image_label)
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.image_frame)
 | 
				
			||||||
 | 
					        self.link_label = QtWidgets.QLabel(self.center_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(8)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.link_label.setFont(font)
 | 
				
			||||||
 | 
					        self.link_label.setAlignment(QtCore.Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.link_label.setObjectName("link_label")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.link_label)
 | 
				
			||||||
 | 
					        self.label_5 = QtWidgets.QLabel(self.center_frame)
 | 
				
			||||||
 | 
					        self.label_5.setObjectName("label_5")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.label_5)
 | 
				
			||||||
 | 
					        self.link_line = QtWidgets.QLineEdit(self.center_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(7)
 | 
				
			||||||
 | 
					        self.link_line.setFont(font)
 | 
				
			||||||
 | 
					        self.link_line.setObjectName("link_line")
 | 
				
			||||||
 | 
					        self.verticalLayout.addWidget(self.link_line)
 | 
				
			||||||
 | 
					        self.horizontalLayout_2.addWidget(self.center_frame)
 | 
				
			||||||
 | 
					        self.right_layout = QtWidgets.QVBoxLayout()
 | 
				
			||||||
 | 
					        self.right_layout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
 | 
				
			||||||
 | 
					        self.right_layout.setObjectName("right_layout")
 | 
				
			||||||
 | 
					        self.next_image_button = QtWidgets.QToolButton(self.left_frame)
 | 
				
			||||||
 | 
					        self.next_image_button.setObjectName("next_image_button")
 | 
				
			||||||
 | 
					        self.right_layout.addWidget(self.next_image_button)
 | 
				
			||||||
 | 
					        self.horizontalLayout_2.addLayout(self.right_layout)
 | 
				
			||||||
 | 
					        self.horizontalLayout.addWidget(self.left_frame)
 | 
				
			||||||
 | 
					        self.right_frame = QtWidgets.QFrame(self.centralwidget)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.right_frame.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.right_frame.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.right_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
 | 
				
			||||||
 | 
					        self.right_frame.setFrameShadow(QtWidgets.QFrame.Raised)
 | 
				
			||||||
 | 
					        self.right_frame.setObjectName("right_frame")
 | 
				
			||||||
 | 
					        self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.right_frame)
 | 
				
			||||||
 | 
					        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
 | 
				
			||||||
 | 
					        self.tag_layout = QtWidgets.QVBoxLayout()
 | 
				
			||||||
 | 
					        self.tag_layout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
 | 
				
			||||||
 | 
					        self.tag_layout.setObjectName("tag_layout")
 | 
				
			||||||
 | 
					        self.label = QtWidgets.QLabel(self.right_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label.setFont(font)
 | 
				
			||||||
 | 
					        self.label.setObjectName("label")
 | 
				
			||||||
 | 
					        self.tag_layout.addWidget(self.label)
 | 
				
			||||||
 | 
					        self.tag_list_layout = QtWidgets.QVBoxLayout()
 | 
				
			||||||
 | 
					        self.tag_list_layout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
 | 
				
			||||||
 | 
					        self.tag_list_layout.setObjectName("tag_list_layout")
 | 
				
			||||||
 | 
					        self.tag_search_bar = QtWidgets.QLineEdit(self.right_frame)
 | 
				
			||||||
 | 
					        self.tag_search_bar.setMaximumSize(QtCore.QSize(400, 16777215))
 | 
				
			||||||
 | 
					        self.tag_search_bar.setObjectName("tag_search_bar")
 | 
				
			||||||
 | 
					        self.tag_list_layout.addWidget(self.tag_search_bar)
 | 
				
			||||||
 | 
					        self.search_result_list = QtWidgets.QListView(self.right_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.search_result_list.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.search_result_list.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.search_result_list.setMinimumSize(QtCore.QSize(0, 0))
 | 
				
			||||||
 | 
					        self.search_result_list.setMaximumSize(QtCore.QSize(400, 16777215))
 | 
				
			||||||
 | 
					        self.search_result_list.setObjectName("search_result_list")
 | 
				
			||||||
 | 
					        self.tag_list_layout.addWidget(self.search_result_list)
 | 
				
			||||||
 | 
					        self.label_2 = QtWidgets.QLabel(self.right_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label_2.setFont(font)
 | 
				
			||||||
 | 
					        self.label_2.setObjectName("label_2")
 | 
				
			||||||
 | 
					        self.tag_list_layout.addWidget(self.label_2)
 | 
				
			||||||
 | 
					        self.tag_list = QtWidgets.QListView(self.right_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.tag_list.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.tag_list.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.tag_list.setMinimumSize(QtCore.QSize(100, 0))
 | 
				
			||||||
 | 
					        self.tag_list.setMaximumSize(QtCore.QSize(400, 16777215))
 | 
				
			||||||
 | 
					        self.tag_list.setObjectName("tag_list")
 | 
				
			||||||
 | 
					        self.tag_list_layout.addWidget(self.tag_list)
 | 
				
			||||||
 | 
					        self.label_3 = QtWidgets.QLabel(self.right_frame)
 | 
				
			||||||
 | 
					        font = QtGui.QFont()
 | 
				
			||||||
 | 
					        font.setPointSize(9)
 | 
				
			||||||
 | 
					        font.setBold(True)
 | 
				
			||||||
 | 
					        font.setWeight(75)
 | 
				
			||||||
 | 
					        self.label_3.setFont(font)
 | 
				
			||||||
 | 
					        self.label_3.setObjectName("label_3")
 | 
				
			||||||
 | 
					        self.tag_list_layout.addWidget(self.label_3)
 | 
				
			||||||
 | 
					        self.implied_tag_list = QtWidgets.QListView(self.right_frame)
 | 
				
			||||||
 | 
					        self.implied_tag_list.setMinimumSize(QtCore.QSize(100, 0))
 | 
				
			||||||
 | 
					        self.implied_tag_list.setMaximumSize(QtCore.QSize(400, 16777215))
 | 
				
			||||||
 | 
					        self.implied_tag_list.setObjectName("implied_tag_list")
 | 
				
			||||||
 | 
					        self.tag_list_layout.addWidget(self.implied_tag_list)
 | 
				
			||||||
 | 
					        self.tag_layout.addLayout(self.tag_list_layout)
 | 
				
			||||||
 | 
					        self.tag_button_layout = QtWidgets.QHBoxLayout()
 | 
				
			||||||
 | 
					        self.tag_button_layout.setSizeConstraint(QtWidgets.QLayout.SetMinimumSize)
 | 
				
			||||||
 | 
					        self.tag_button_layout.setSpacing(5)
 | 
				
			||||||
 | 
					        self.tag_button_layout.setObjectName("tag_button_layout")
 | 
				
			||||||
 | 
					        self.save_button = QtWidgets.QPushButton(self.right_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.save_button.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.save_button.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.save_button.setMaximumSize(QtCore.QSize(16777215, 16777215))
 | 
				
			||||||
 | 
					        self.save_button.setObjectName("save_button")
 | 
				
			||||||
 | 
					        self.tag_button_layout.addWidget(self.save_button)
 | 
				
			||||||
 | 
					        self.import_button = QtWidgets.QPushButton(self.right_frame)
 | 
				
			||||||
 | 
					        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
 | 
				
			||||||
 | 
					        sizePolicy.setHorizontalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setVerticalStretch(0)
 | 
				
			||||||
 | 
					        sizePolicy.setHeightForWidth(self.import_button.sizePolicy().hasHeightForWidth())
 | 
				
			||||||
 | 
					        self.import_button.setSizePolicy(sizePolicy)
 | 
				
			||||||
 | 
					        self.import_button.setMaximumSize(QtCore.QSize(16777215, 16777215))
 | 
				
			||||||
 | 
					        self.import_button.setObjectName("import_button")
 | 
				
			||||||
 | 
					        self.tag_button_layout.addWidget(self.import_button)
 | 
				
			||||||
 | 
					        self.prev_unknown_image_button = QtWidgets.QPushButton(self.right_frame)
 | 
				
			||||||
 | 
					        self.prev_unknown_image_button.setObjectName("prev_unknown_image_button")
 | 
				
			||||||
 | 
					        self.tag_button_layout.addWidget(self.prev_unknown_image_button)
 | 
				
			||||||
 | 
					        self.next_unknown_image_button = QtWidgets.QPushButton(self.right_frame)
 | 
				
			||||||
 | 
					        self.next_unknown_image_button.setObjectName("next_unknown_image_button")
 | 
				
			||||||
 | 
					        self.tag_button_layout.addWidget(self.next_unknown_image_button)
 | 
				
			||||||
 | 
					        self.delete_button = QtWidgets.QPushButton(self.right_frame)
 | 
				
			||||||
 | 
					        self.delete_button.setObjectName("delete_button")
 | 
				
			||||||
 | 
					        self.tag_button_layout.addWidget(self.delete_button)
 | 
				
			||||||
 | 
					        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
 | 
				
			||||||
 | 
					        self.tag_button_layout.addItem(spacerItem)
 | 
				
			||||||
 | 
					        self.tag_layout.addLayout(self.tag_button_layout)
 | 
				
			||||||
 | 
					        self.horizontalLayout_3.addLayout(self.tag_layout)
 | 
				
			||||||
 | 
					        self.horizontalLayout.addWidget(self.right_frame)
 | 
				
			||||||
 | 
					        MainWindow.setCentralWidget(self.centralwidget)
 | 
				
			||||||
 | 
					        self.statusbar = QtWidgets.QStatusBar(MainWindow)
 | 
				
			||||||
 | 
					        self.statusbar.setObjectName("statusbar")
 | 
				
			||||||
 | 
					        MainWindow.setStatusBar(self.statusbar)
 | 
				
			||||||
 | 
					        self.menuBar = QtWidgets.QMenuBar(MainWindow)
 | 
				
			||||||
 | 
					        self.menuBar.setGeometry(QtCore.QRect(0, 0, 827, 19))
 | 
				
			||||||
 | 
					        self.menuBar.setObjectName("menuBar")
 | 
				
			||||||
 | 
					        self.menuArtNet = QtWidgets.QMenu(self.menuBar)
 | 
				
			||||||
 | 
					        self.menuArtNet.setObjectName("menuArtNet")
 | 
				
			||||||
 | 
					        self.menuTags = QtWidgets.QMenu(self.menuBar)
 | 
				
			||||||
 | 
					        self.menuTags.setObjectName("menuTags")
 | 
				
			||||||
 | 
					        self.menuCategory = QtWidgets.QMenu(self.menuBar)
 | 
				
			||||||
 | 
					        self.menuCategory.setObjectName("menuCategory")
 | 
				
			||||||
 | 
					        MainWindow.setMenuBar(self.menuBar)
 | 
				
			||||||
 | 
					        self.actionChange_Connection_Details = QtWidgets.QAction(MainWindow)
 | 
				
			||||||
 | 
					        self.actionChange_Connection_Details.setObjectName("actionChange_Connection_Details")
 | 
				
			||||||
 | 
					        self.actionChange_ArtNet_Root_Folder = QtWidgets.QAction(MainWindow)
 | 
				
			||||||
 | 
					        self.actionChange_ArtNet_Root_Folder.setObjectName("actionChange_ArtNet_Root_Folder")
 | 
				
			||||||
 | 
					        self.actionCreate_New_Tag = QtWidgets.QAction(MainWindow)
 | 
				
			||||||
 | 
					        self.actionCreate_New_Tag.setObjectName("actionCreate_New_Tag")
 | 
				
			||||||
 | 
					        self.actionDelete_a_Tag = QtWidgets.QAction(MainWindow)
 | 
				
			||||||
 | 
					        self.actionDelete_a_Tag.setObjectName("actionDelete_a_Tag")
 | 
				
			||||||
 | 
					        self.actionEdit_a_Tag = QtWidgets.QAction(MainWindow)
 | 
				
			||||||
 | 
					        self.actionEdit_a_Tag.setObjectName("actionEdit_a_Tag")
 | 
				
			||||||
 | 
					        self.actionCreate_New_Category = QtWidgets.QAction(MainWindow)
 | 
				
			||||||
 | 
					        self.actionCreate_New_Category.setObjectName("actionCreate_New_Category")
 | 
				
			||||||
 | 
					        self.actionDelete_a_Category = QtWidgets.QAction(MainWindow)
 | 
				
			||||||
 | 
					        self.actionDelete_a_Category.setObjectName("actionDelete_a_Category")
 | 
				
			||||||
 | 
					        self.actionCreate_New_Category_2 = QtWidgets.QAction(MainWindow)
 | 
				
			||||||
 | 
					        self.actionCreate_New_Category_2.setObjectName("actionCreate_New_Category_2")
 | 
				
			||||||
 | 
					        self.actionDelete_a_Category_2 = QtWidgets.QAction(MainWindow)
 | 
				
			||||||
 | 
					        self.actionDelete_a_Category_2.setObjectName("actionDelete_a_Category_2")
 | 
				
			||||||
 | 
					        self.menuArtNet.addAction(self.actionChange_Connection_Details)
 | 
				
			||||||
 | 
					        self.menuArtNet.addAction(self.actionChange_ArtNet_Root_Folder)
 | 
				
			||||||
 | 
					        self.menuTags.addAction(self.actionCreate_New_Tag)
 | 
				
			||||||
 | 
					        self.menuTags.addAction(self.actionDelete_a_Tag)
 | 
				
			||||||
 | 
					        self.menuTags.addAction(self.actionEdit_a_Tag)
 | 
				
			||||||
 | 
					        self.menuCategory.addAction(self.actionCreate_New_Category_2)
 | 
				
			||||||
 | 
					        self.menuCategory.addAction(self.actionDelete_a_Category_2)
 | 
				
			||||||
 | 
					        self.menuBar.addAction(self.menuArtNet.menuAction())
 | 
				
			||||||
 | 
					        self.menuBar.addAction(self.menuTags.menuAction())
 | 
				
			||||||
 | 
					        self.menuBar.addAction(self.menuCategory.menuAction())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.retranslateUi(MainWindow)
 | 
				
			||||||
 | 
					        QtCore.QMetaObject.connectSlotsByName(MainWindow)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def retranslateUi(self, MainWindow):
 | 
				
			||||||
 | 
					        _translate = QtCore.QCoreApplication.translate
 | 
				
			||||||
 | 
					        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
 | 
				
			||||||
 | 
					        self.presence_docker_button.setText(_translate("MainWindow", "<"))
 | 
				
			||||||
 | 
					        self.prev_image_button.setText(_translate("MainWindow", "<"))
 | 
				
			||||||
 | 
					        self.image_title_line.setText(_translate("MainWindow", "Image_Title"))
 | 
				
			||||||
 | 
					        self.image_file_label.setText(_translate("MainWindow", "file_name"))
 | 
				
			||||||
 | 
					        self.author_by.setText(_translate("MainWindow", "by"))
 | 
				
			||||||
 | 
					        self.image_author_label.setText(_translate("MainWindow", "author_name"))
 | 
				
			||||||
 | 
					        self.image_label.setText(_translate("MainWindow", "No Image"))
 | 
				
			||||||
 | 
					        self.link_label.setText(_translate("MainWindow", "Source_Link"))
 | 
				
			||||||
 | 
					        self.label_5.setText(_translate("MainWindow", "Link:"))
 | 
				
			||||||
 | 
					        self.next_image_button.setText(_translate("MainWindow", ">"))
 | 
				
			||||||
 | 
					        self.label.setText(_translate("MainWindow", "Search Tags"))
 | 
				
			||||||
 | 
					        self.label_2.setText(_translate("MainWindow", "Selected Tags:"))
 | 
				
			||||||
 | 
					        self.label_3.setText(_translate("MainWindow", "Implied Tags:"))
 | 
				
			||||||
 | 
					        self.save_button.setText(_translate("MainWindow", "Save"))
 | 
				
			||||||
 | 
					        self.import_button.setText(_translate("MainWindow", "Import Tags"))
 | 
				
			||||||
 | 
					        self.prev_unknown_image_button.setText(_translate("MainWindow", "prev Unknown"))
 | 
				
			||||||
 | 
					        self.next_unknown_image_button.setText(_translate("MainWindow", "next Unknown"))
 | 
				
			||||||
 | 
					        self.delete_button.setText(_translate("MainWindow", "Delete"))
 | 
				
			||||||
 | 
					        self.menuArtNet.setTitle(_translate("MainWindow", "ArtNet"))
 | 
				
			||||||
 | 
					        self.menuTags.setTitle(_translate("MainWindow", "Tags"))
 | 
				
			||||||
 | 
					        self.menuCategory.setTitle(_translate("MainWindow", "Category"))
 | 
				
			||||||
 | 
					        self.actionChange_Connection_Details.setText(_translate("MainWindow", "Change DB Connection"))
 | 
				
			||||||
 | 
					        self.actionChange_ArtNet_Root_Folder.setText(_translate("MainWindow", "Change ArtNet Root"))
 | 
				
			||||||
 | 
					        self.actionCreate_New_Tag.setText(_translate("MainWindow", "Create New Tag"))
 | 
				
			||||||
 | 
					        self.actionDelete_a_Tag.setText(_translate("MainWindow", "Delete a Tag"))
 | 
				
			||||||
 | 
					        self.actionEdit_a_Tag.setText(_translate("MainWindow", "Edit a Tag"))
 | 
				
			||||||
 | 
					        self.actionCreate_New_Category.setText(_translate("MainWindow", "Create New Category"))
 | 
				
			||||||
 | 
					        self.actionDelete_a_Category.setText(_translate("MainWindow", "Delete a Category"))
 | 
				
			||||||
 | 
					        self.actionCreate_New_Category_2.setText(_translate("MainWindow", "Create New Category"))
 | 
				
			||||||
 | 
					        self.actionDelete_a_Category_2.setText(_translate("MainWindow", "Delete a Category"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    app = QtWidgets.QApplication(sys.argv)
 | 
				
			||||||
 | 
					    MainWindow = QtWidgets.QMainWindow()
 | 
				
			||||||
 | 
					    ui = Ui_MainWindow()
 | 
				
			||||||
 | 
					    ui.setupUi(MainWindow)
 | 
				
			||||||
 | 
					    MainWindow.show()
 | 
				
			||||||
 | 
					    sys.exit(app.exec_())
 | 
				
			||||||
@ -0,0 +1,564 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<ui version="4.0">
 | 
				
			||||||
 | 
					 <class>MainWindow</class>
 | 
				
			||||||
 | 
					 <widget class="QMainWindow" name="MainWindow">
 | 
				
			||||||
 | 
					  <property name="geometry">
 | 
				
			||||||
 | 
					   <rect>
 | 
				
			||||||
 | 
					    <x>0</x>
 | 
				
			||||||
 | 
					    <y>0</y>
 | 
				
			||||||
 | 
					    <width>827</width>
 | 
				
			||||||
 | 
					    <height>777</height>
 | 
				
			||||||
 | 
					   </rect>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <property name="windowTitle">
 | 
				
			||||||
 | 
					   <string>MainWindow</string>
 | 
				
			||||||
 | 
					  </property>
 | 
				
			||||||
 | 
					  <widget class="QWidget" name="centralwidget">
 | 
				
			||||||
 | 
					   <property name="enabled">
 | 
				
			||||||
 | 
					    <bool>true</bool>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					   <layout class="QHBoxLayout" name="horizontalLayout">
 | 
				
			||||||
 | 
					    <property name="sizeConstraint">
 | 
				
			||||||
 | 
					     <enum>QLayout::SetDefaultConstraint</enum>
 | 
				
			||||||
 | 
					    </property>
 | 
				
			||||||
 | 
					    <item>
 | 
				
			||||||
 | 
					     <widget class="QFrame" name="left_frame">
 | 
				
			||||||
 | 
					      <property name="sizePolicy">
 | 
				
			||||||
 | 
					       <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
 | 
				
			||||||
 | 
					        <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					        <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					       </sizepolicy>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <property name="frameShape">
 | 
				
			||||||
 | 
					       <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <property name="frameShadow">
 | 
				
			||||||
 | 
					       <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <layout class="QHBoxLayout" name="horizontalLayout_2">
 | 
				
			||||||
 | 
					       <item>
 | 
				
			||||||
 | 
					        <widget class="QToolButton" name="presence_docker_button">
 | 
				
			||||||
 | 
					         <property name="sizePolicy">
 | 
				
			||||||
 | 
					          <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
 | 
				
			||||||
 | 
					           <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					           <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					          </sizepolicy>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					         <property name="text">
 | 
				
			||||||
 | 
					          <string><</string>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					        </widget>
 | 
				
			||||||
 | 
					       </item>
 | 
				
			||||||
 | 
					       <item>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="presence_docker_layout"/>
 | 
				
			||||||
 | 
					       </item>
 | 
				
			||||||
 | 
					       <item>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="left_layout">
 | 
				
			||||||
 | 
					         <property name="sizeConstraint">
 | 
				
			||||||
 | 
					          <enum>QLayout::SetMinimumSize</enum>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QToolButton" name="prev_image_button">
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string><</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </item>
 | 
				
			||||||
 | 
					       <item>
 | 
				
			||||||
 | 
					        <widget class="QFrame" name="center_frame">
 | 
				
			||||||
 | 
					         <property name="sizePolicy">
 | 
				
			||||||
 | 
					          <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
 | 
				
			||||||
 | 
					           <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					           <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					          </sizepolicy>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					         <property name="frameShape">
 | 
				
			||||||
 | 
					          <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					         <property name="frameShadow">
 | 
				
			||||||
 | 
					          <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					         <layout class="QVBoxLayout" name="verticalLayout">
 | 
				
			||||||
 | 
					          <item>
 | 
				
			||||||
 | 
					           <widget class="QFrame" name="frame">
 | 
				
			||||||
 | 
					            <property name="frameShape">
 | 
				
			||||||
 | 
					             <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="frameShadow">
 | 
				
			||||||
 | 
					             <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <layout class="QHBoxLayout" name="horizontalLayout_4">
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <widget class="QLineEdit" name="image_title_line">
 | 
				
			||||||
 | 
					               <property name="font">
 | 
				
			||||||
 | 
					                <font>
 | 
				
			||||||
 | 
					                 <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					                 <weight>75</weight>
 | 
				
			||||||
 | 
					                 <bold>true</bold>
 | 
				
			||||||
 | 
					                </font>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					               <property name="autoFillBackground">
 | 
				
			||||||
 | 
					                <bool>false</bool>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					               <property name="text">
 | 
				
			||||||
 | 
					                <string>Image_Title</string>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					               <property name="alignment">
 | 
				
			||||||
 | 
					                <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					               <property name="readOnly">
 | 
				
			||||||
 | 
					                <bool>false</bool>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					              </widget>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <widget class="QSpinBox" name="imageNumberSpinBox"/>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					            </layout>
 | 
				
			||||||
 | 
					           </widget>
 | 
				
			||||||
 | 
					          </item>
 | 
				
			||||||
 | 
					          <item>
 | 
				
			||||||
 | 
					           <widget class="QLabel" name="image_file_label">
 | 
				
			||||||
 | 
					            <property name="text">
 | 
				
			||||||
 | 
					             <string>file_name</string>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="alignment">
 | 
				
			||||||
 | 
					             <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					           </widget>
 | 
				
			||||||
 | 
					          </item>
 | 
				
			||||||
 | 
					          <item>
 | 
				
			||||||
 | 
					           <widget class="QLabel" name="author_by">
 | 
				
			||||||
 | 
					            <property name="sizePolicy">
 | 
				
			||||||
 | 
					             <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
 | 
				
			||||||
 | 
					              <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					              <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					             </sizepolicy>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="font">
 | 
				
			||||||
 | 
					             <font>
 | 
				
			||||||
 | 
					              <pointsize>7</pointsize>
 | 
				
			||||||
 | 
					              <weight>50</weight>
 | 
				
			||||||
 | 
					              <bold>false</bold>
 | 
				
			||||||
 | 
					             </font>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="text">
 | 
				
			||||||
 | 
					             <string>by</string>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="alignment">
 | 
				
			||||||
 | 
					             <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					           </widget>
 | 
				
			||||||
 | 
					          </item>
 | 
				
			||||||
 | 
					          <item>
 | 
				
			||||||
 | 
					           <widget class="QLabel" name="image_author_label">
 | 
				
			||||||
 | 
					            <property name="font">
 | 
				
			||||||
 | 
					             <font>
 | 
				
			||||||
 | 
					              <pointsize>10</pointsize>
 | 
				
			||||||
 | 
					              <weight>50</weight>
 | 
				
			||||||
 | 
					              <italic>false</italic>
 | 
				
			||||||
 | 
					              <bold>false</bold>
 | 
				
			||||||
 | 
					             </font>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="text">
 | 
				
			||||||
 | 
					             <string>author_name</string>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="alignment">
 | 
				
			||||||
 | 
					             <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					           </widget>
 | 
				
			||||||
 | 
					          </item>
 | 
				
			||||||
 | 
					          <item>
 | 
				
			||||||
 | 
					           <widget class="QFrame" name="image_frame">
 | 
				
			||||||
 | 
					            <property name="frameShape">
 | 
				
			||||||
 | 
					             <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="frameShadow">
 | 
				
			||||||
 | 
					             <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <layout class="QVBoxLayout" name="verticalLayout_2">
 | 
				
			||||||
 | 
					             <item>
 | 
				
			||||||
 | 
					              <widget class="QLabel" name="image_label">
 | 
				
			||||||
 | 
					               <property name="sizePolicy">
 | 
				
			||||||
 | 
					                <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
 | 
				
			||||||
 | 
					                 <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					                 <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					                </sizepolicy>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					               <property name="text">
 | 
				
			||||||
 | 
					                <string>No Image</string>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					               <property name="alignment">
 | 
				
			||||||
 | 
					                <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					               </property>
 | 
				
			||||||
 | 
					              </widget>
 | 
				
			||||||
 | 
					             </item>
 | 
				
			||||||
 | 
					            </layout>
 | 
				
			||||||
 | 
					           </widget>
 | 
				
			||||||
 | 
					          </item>
 | 
				
			||||||
 | 
					          <item>
 | 
				
			||||||
 | 
					           <widget class="QLabel" name="link_label">
 | 
				
			||||||
 | 
					            <property name="font">
 | 
				
			||||||
 | 
					             <font>
 | 
				
			||||||
 | 
					              <pointsize>8</pointsize>
 | 
				
			||||||
 | 
					              <weight>75</weight>
 | 
				
			||||||
 | 
					              <bold>true</bold>
 | 
				
			||||||
 | 
					             </font>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="text">
 | 
				
			||||||
 | 
					             <string>Source_Link</string>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					            <property name="alignment">
 | 
				
			||||||
 | 
					             <set>Qt::AlignCenter</set>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					           </widget>
 | 
				
			||||||
 | 
					          </item>
 | 
				
			||||||
 | 
					          <item>
 | 
				
			||||||
 | 
					           <widget class="QLabel" name="label_5">
 | 
				
			||||||
 | 
					            <property name="text">
 | 
				
			||||||
 | 
					             <string>Link:</string>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					           </widget>
 | 
				
			||||||
 | 
					          </item>
 | 
				
			||||||
 | 
					          <item>
 | 
				
			||||||
 | 
					           <widget class="QLineEdit" name="link_line">
 | 
				
			||||||
 | 
					            <property name="font">
 | 
				
			||||||
 | 
					             <font>
 | 
				
			||||||
 | 
					              <pointsize>7</pointsize>
 | 
				
			||||||
 | 
					             </font>
 | 
				
			||||||
 | 
					            </property>
 | 
				
			||||||
 | 
					           </widget>
 | 
				
			||||||
 | 
					          </item>
 | 
				
			||||||
 | 
					         </layout>
 | 
				
			||||||
 | 
					        </widget>
 | 
				
			||||||
 | 
					       </item>
 | 
				
			||||||
 | 
					       <item>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="right_layout">
 | 
				
			||||||
 | 
					         <property name="sizeConstraint">
 | 
				
			||||||
 | 
					          <enum>QLayout::SetMinimumSize</enum>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QToolButton" name="next_image_button">
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>></string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </item>
 | 
				
			||||||
 | 
					      </layout>
 | 
				
			||||||
 | 
					     </widget>
 | 
				
			||||||
 | 
					    </item>
 | 
				
			||||||
 | 
					    <item>
 | 
				
			||||||
 | 
					     <widget class="QFrame" name="right_frame">
 | 
				
			||||||
 | 
					      <property name="sizePolicy">
 | 
				
			||||||
 | 
					       <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
 | 
				
			||||||
 | 
					        <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					        <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					       </sizepolicy>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <property name="frameShape">
 | 
				
			||||||
 | 
					       <enum>QFrame::StyledPanel</enum>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <property name="frameShadow">
 | 
				
			||||||
 | 
					       <enum>QFrame::Raised</enum>
 | 
				
			||||||
 | 
					      </property>
 | 
				
			||||||
 | 
					      <layout class="QHBoxLayout" name="horizontalLayout_3">
 | 
				
			||||||
 | 
					       <item>
 | 
				
			||||||
 | 
					        <layout class="QVBoxLayout" name="tag_layout">
 | 
				
			||||||
 | 
					         <property name="sizeConstraint">
 | 
				
			||||||
 | 
					          <enum>QLayout::SetMinimumSize</enum>
 | 
				
			||||||
 | 
					         </property>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <widget class="QLabel" name="label">
 | 
				
			||||||
 | 
					           <property name="font">
 | 
				
			||||||
 | 
					            <font>
 | 
				
			||||||
 | 
					             <weight>75</weight>
 | 
				
			||||||
 | 
					             <bold>true</bold>
 | 
				
			||||||
 | 
					            </font>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="text">
 | 
				
			||||||
 | 
					            <string>Search Tags</string>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					          </widget>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <layout class="QVBoxLayout" name="tag_list_layout">
 | 
				
			||||||
 | 
					           <property name="sizeConstraint">
 | 
				
			||||||
 | 
					            <enum>QLayout::SetMinimumSize</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QLineEdit" name="tag_search_bar">
 | 
				
			||||||
 | 
					             <property name="maximumSize">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>400</width>
 | 
				
			||||||
 | 
					               <height>16777215</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QListView" name="search_result_list">
 | 
				
			||||||
 | 
					             <property name="sizePolicy">
 | 
				
			||||||
 | 
					              <sizepolicy hsizetype="Expanding" vsizetype="Minimum">
 | 
				
			||||||
 | 
					               <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					               <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					              </sizepolicy>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="minimumSize">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>0</width>
 | 
				
			||||||
 | 
					               <height>0</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="maximumSize">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>400</width>
 | 
				
			||||||
 | 
					               <height>16777215</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QLabel" name="label_2">
 | 
				
			||||||
 | 
					             <property name="font">
 | 
				
			||||||
 | 
					              <font>
 | 
				
			||||||
 | 
					               <weight>75</weight>
 | 
				
			||||||
 | 
					               <bold>true</bold>
 | 
				
			||||||
 | 
					              </font>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Selected Tags:</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QListView" name="tag_list">
 | 
				
			||||||
 | 
					             <property name="sizePolicy">
 | 
				
			||||||
 | 
					              <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
 | 
				
			||||||
 | 
					               <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					               <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					              </sizepolicy>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="minimumSize">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>100</width>
 | 
				
			||||||
 | 
					               <height>0</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="maximumSize">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>400</width>
 | 
				
			||||||
 | 
					               <height>16777215</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QLabel" name="label_3">
 | 
				
			||||||
 | 
					             <property name="font">
 | 
				
			||||||
 | 
					              <font>
 | 
				
			||||||
 | 
					               <pointsize>9</pointsize>
 | 
				
			||||||
 | 
					               <weight>75</weight>
 | 
				
			||||||
 | 
					               <bold>true</bold>
 | 
				
			||||||
 | 
					              </font>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Implied Tags:</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QListView" name="implied_tag_list">
 | 
				
			||||||
 | 
					             <property name="minimumSize">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>100</width>
 | 
				
			||||||
 | 
					               <height>0</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="maximumSize">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>400</width>
 | 
				
			||||||
 | 
					               <height>16777215</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					          </layout>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					         <item>
 | 
				
			||||||
 | 
					          <layout class="QHBoxLayout" name="tag_button_layout">
 | 
				
			||||||
 | 
					           <property name="spacing">
 | 
				
			||||||
 | 
					            <number>5</number>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <property name="sizeConstraint">
 | 
				
			||||||
 | 
					            <enum>QLayout::SetMinimumSize</enum>
 | 
				
			||||||
 | 
					           </property>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QPushButton" name="save_button">
 | 
				
			||||||
 | 
					             <property name="sizePolicy">
 | 
				
			||||||
 | 
					              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
 | 
				
			||||||
 | 
					               <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					               <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					              </sizepolicy>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="maximumSize">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>16777215</width>
 | 
				
			||||||
 | 
					               <height>16777215</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Save</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QPushButton" name="import_button">
 | 
				
			||||||
 | 
					             <property name="sizePolicy">
 | 
				
			||||||
 | 
					              <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
 | 
				
			||||||
 | 
					               <horstretch>0</horstretch>
 | 
				
			||||||
 | 
					               <verstretch>0</verstretch>
 | 
				
			||||||
 | 
					              </sizepolicy>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="maximumSize">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>16777215</width>
 | 
				
			||||||
 | 
					               <height>16777215</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Import Tags</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QPushButton" name="prev_unknown_image_button">
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>prev Unknown</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QPushButton" name="next_unknown_image_button">
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>next Unknown</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <widget class="QPushButton" name="delete_button">
 | 
				
			||||||
 | 
					             <property name="text">
 | 
				
			||||||
 | 
					              <string>Delete</string>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </widget>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					           <item>
 | 
				
			||||||
 | 
					            <spacer name="horizontalSpacer">
 | 
				
			||||||
 | 
					             <property name="orientation">
 | 
				
			||||||
 | 
					              <enum>Qt::Horizontal</enum>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					             <property name="sizeHint" stdset="0">
 | 
				
			||||||
 | 
					              <size>
 | 
				
			||||||
 | 
					               <width>40</width>
 | 
				
			||||||
 | 
					               <height>20</height>
 | 
				
			||||||
 | 
					              </size>
 | 
				
			||||||
 | 
					             </property>
 | 
				
			||||||
 | 
					            </spacer>
 | 
				
			||||||
 | 
					           </item>
 | 
				
			||||||
 | 
					          </layout>
 | 
				
			||||||
 | 
					         </item>
 | 
				
			||||||
 | 
					        </layout>
 | 
				
			||||||
 | 
					       </item>
 | 
				
			||||||
 | 
					      </layout>
 | 
				
			||||||
 | 
					     </widget>
 | 
				
			||||||
 | 
					    </item>
 | 
				
			||||||
 | 
					   </layout>
 | 
				
			||||||
 | 
					  </widget>
 | 
				
			||||||
 | 
					  <widget class="QStatusBar" name="statusbar"/>
 | 
				
			||||||
 | 
					  <widget class="QMenuBar" name="menuBar">
 | 
				
			||||||
 | 
					   <property name="geometry">
 | 
				
			||||||
 | 
					    <rect>
 | 
				
			||||||
 | 
					     <x>0</x>
 | 
				
			||||||
 | 
					     <y>0</y>
 | 
				
			||||||
 | 
					     <width>827</width>
 | 
				
			||||||
 | 
					     <height>19</height>
 | 
				
			||||||
 | 
					    </rect>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					   <widget class="QMenu" name="menuArtNet">
 | 
				
			||||||
 | 
					    <property name="title">
 | 
				
			||||||
 | 
					     <string>ArtNet</string>
 | 
				
			||||||
 | 
					    </property>
 | 
				
			||||||
 | 
					    <addaction name="actionChange_Connection_Details"/>
 | 
				
			||||||
 | 
					    <addaction name="actionChange_ArtNet_Root_Folder"/>
 | 
				
			||||||
 | 
					   </widget>
 | 
				
			||||||
 | 
					   <widget class="QMenu" name="menuTags">
 | 
				
			||||||
 | 
					    <property name="title">
 | 
				
			||||||
 | 
					     <string>Tags</string>
 | 
				
			||||||
 | 
					    </property>
 | 
				
			||||||
 | 
					    <addaction name="actionCreate_New_Tag"/>
 | 
				
			||||||
 | 
					    <addaction name="actionDelete_a_Tag"/>
 | 
				
			||||||
 | 
					    <addaction name="actionEdit_a_Tag"/>
 | 
				
			||||||
 | 
					   </widget>
 | 
				
			||||||
 | 
					   <widget class="QMenu" name="menuCategory">
 | 
				
			||||||
 | 
					    <property name="title">
 | 
				
			||||||
 | 
					     <string>Category</string>
 | 
				
			||||||
 | 
					    </property>
 | 
				
			||||||
 | 
					    <addaction name="actionCreate_New_Category_2"/>
 | 
				
			||||||
 | 
					    <addaction name="actionDelete_a_Category_2"/>
 | 
				
			||||||
 | 
					   </widget>
 | 
				
			||||||
 | 
					   <addaction name="menuArtNet"/>
 | 
				
			||||||
 | 
					   <addaction name="menuTags"/>
 | 
				
			||||||
 | 
					   <addaction name="menuCategory"/>
 | 
				
			||||||
 | 
					  </widget>
 | 
				
			||||||
 | 
					  <action name="actionChange_Connection_Details">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Change DB Connection</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionChange_ArtNet_Root_Folder">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Change ArtNet Root</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionCreate_New_Tag">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Create New Tag</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionDelete_a_Tag">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Delete a Tag</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionEdit_a_Tag">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Edit a Tag</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionCreate_New_Category">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Create New Category</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionDelete_a_Category">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Delete a Category</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionCreate_New_Category_2">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Create New Category</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					  <action name="actionDelete_a_Category_2">
 | 
				
			||||||
 | 
					   <property name="text">
 | 
				
			||||||
 | 
					    <string>Delete a Category</string>
 | 
				
			||||||
 | 
					   </property>
 | 
				
			||||||
 | 
					  </action>
 | 
				
			||||||
 | 
					 </widget>
 | 
				
			||||||
 | 
					 <resources/>
 | 
				
			||||||
 | 
					 <connections/>
 | 
				
			||||||
 | 
					</ui>
 | 
				
			||||||
@ -0,0 +1,999 @@
 | 
				
			|||||||
 | 
					import validators, os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from PyQt5 import QtWidgets
 | 
				
			||||||
 | 
					from PyQt5.QtCore import Qt, QSize, QUrl
 | 
				
			||||||
 | 
					from PyQt5.QtGui import QPixmap, QResizeEvent, QKeyEvent, QStandardItemModel, QStandardItem, QMovie
 | 
				
			||||||
 | 
					from PyQt5 import QtMultimedia
 | 
				
			||||||
 | 
					from PyQt5.QtMultimediaWidgets import QVideoWidget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.gui.picture_importer import Ui_MainWindow
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.db_connection_dialog.db_dialog import DBDialog
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.tag_modify_dialog.tag_mod_dialog import TagModifyDialog
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.tag_select_dialog.tag_select_dialog import TagSelectDialog
 | 
				
			||||||
 | 
					from ArtNet.gui.dockers.presence.presence_dock import PresenceDocker
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.category_modify_dialog.category_mod_dialog import CategoryModDialog
 | 
				
			||||||
 | 
					from ArtNet.gui.dialogs.tag_import_dialog.tag_imp_dialog import TagImportDialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ArtNet.web.link_generator import LinkGenerator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Window(QtWidgets.QMainWindow):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, main):
 | 
				
			||||||
 | 
					        super(Window, self).__init__()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main = main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__pixmap: QPixmap = None
 | 
				
			||||||
 | 
					        self.__video: QVideoWidget = None
 | 
				
			||||||
 | 
					        self.__player: QtMultimedia.QMediaPlayer = None
 | 
				
			||||||
 | 
					        self.__showing_video: bool = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__tmp_imageid_spinbox: int = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.presence_docker_open: bool = False
 | 
				
			||||||
 | 
					        self.presence_docker: PresenceDocker = None
 | 
				
			||||||
 | 
					        self.curr_art_id: int = None
 | 
				
			||||||
 | 
					        self.curr_image_title: str = None
 | 
				
			||||||
 | 
					        self.curr_link: str = None
 | 
				
			||||||
 | 
					        self.curr_art_path: str = None
 | 
				
			||||||
 | 
					        self.curr_file_name: str = None
 | 
				
			||||||
 | 
					        self.curr_presences: list = list()
 | 
				
			||||||
 | 
					        self.curr_tags: list = list()
 | 
				
			||||||
 | 
					        self.curr_imply_tags: list = list()
 | 
				
			||||||
 | 
					        self.curr_tag_aliases: list = list()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.setting_up_data: bool = True
 | 
				
			||||||
 | 
					        self.__data_changed: bool = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui = Ui_MainWindow()
 | 
				
			||||||
 | 
					        self.ui.setupUi(self)
 | 
				
			||||||
 | 
					        self.main_title = "ArtNet Picture Importer"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.actionChange_ArtNet_Root_Folder.triggered.connect(self.on_artnet_root_change_clicked)
 | 
				
			||||||
 | 
					        self.ui.actionChange_Connection_Details.triggered.connect(self.on_db_connection_change_clicked)
 | 
				
			||||||
 | 
					        self.ui.actionCreate_New_Tag.triggered.connect(self.on_tag_creation_clicked)
 | 
				
			||||||
 | 
					        self.ui.actionEdit_a_Tag.triggered.connect(self.on_tag_edit_clicked)
 | 
				
			||||||
 | 
					        self.ui.actionDelete_a_Tag.triggered.connect(self.on_tag_deletion_clicked)
 | 
				
			||||||
 | 
					        self.ui.actionCreate_New_Category_2.triggered.connect(self.on_category_creation_clicked)
 | 
				
			||||||
 | 
					        self.ui.actionDelete_a_Category_2.triggered.connect(self.on_category_deletion_clicked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.imageNumberSpinBox.valueChanged.connect(self.on_image_id_spinbox_changed)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.next_image_button.clicked.connect(self.on_next_clicked)
 | 
				
			||||||
 | 
					        self.ui.prev_image_button.clicked.connect(self.on_previous_clicked)
 | 
				
			||||||
 | 
					        self.ui.save_button.clicked.connect(self.on_save_clicked)
 | 
				
			||||||
 | 
					        self.ui.import_button.clicked.connect(self.on_import_tags_clicked)
 | 
				
			||||||
 | 
					        self.ui.prev_unknown_image_button.clicked.connect(self.on_prev_unknown_image_clicked)
 | 
				
			||||||
 | 
					        self.ui.next_unknown_image_button.clicked.connect(self.on_next_unknown_image_clicked)
 | 
				
			||||||
 | 
					        self.ui.delete_button.clicked.connect(self.on_delete_image_clicked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.presence_docker_button.clicked.connect(self.toggle_presence_docker)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.tag_search_bar.textChanged.connect(self.on_tag_search_change)
 | 
				
			||||||
 | 
					        self.ui.image_title_line.textChanged.connect(self.on_image_title_change)
 | 
				
			||||||
 | 
					        self.ui.link_line.textChanged.connect(self.on_link_line_change)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.link_label.setText("No Source Available")
 | 
				
			||||||
 | 
					        self.ui.image_file_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
 | 
				
			||||||
 | 
					        self.set_image_title_link()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.on_tag_search_change()
 | 
				
			||||||
 | 
					        self.center()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def data_changed(self):
 | 
				
			||||||
 | 
					        return self.__data_changed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @data_changed.setter
 | 
				
			||||||
 | 
					    def data_changed(self, v: bool):
 | 
				
			||||||
 | 
					        self.__data_changed = v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.curr_image_title is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if " (Not in Database)" in self.curr_image_title and v and not self.setting_up_data:
 | 
				
			||||||
 | 
					            self.curr_image_title = self.curr_image_title.replace(" (Not in Database)", "")
 | 
				
			||||||
 | 
					            self.setting_up_data = True
 | 
				
			||||||
 | 
					            self.ui.image_title_line.setText(self.curr_image_title)
 | 
				
			||||||
 | 
					            self.setting_up_data = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def center(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Centers the window in the middle of the screen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Note: actually not the center but a good position due to images changing size!
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        screen = QtWidgets.QDesktopWidget().screenGeometry()
 | 
				
			||||||
 | 
					        size = self.geometry()
 | 
				
			||||||
 | 
					        self.move((screen.width() - size.width()) / 3, (screen.height() - size.height()) / 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def check_save_changes(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Check if there were changes to image settings. If yes ask for confirmation to save them.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if self.data_changed:
 | 
				
			||||||
 | 
					            answer = QtWidgets.QMessageBox.question(self, "Save Changes?",
 | 
				
			||||||
 | 
					                                                    "There have been changes. Do you wish to save them?",
 | 
				
			||||||
 | 
					                                                    QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
 | 
				
			||||||
 | 
					                                                    QtWidgets.QMessageBox.No)
 | 
				
			||||||
 | 
					            if answer == QtWidgets.QMessageBox.Yes:
 | 
				
			||||||
 | 
					                if not self.save_changes():
 | 
				
			||||||
 | 
					                    return False
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_changes(self) -> bool:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Save the changes to image data to the DB.
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        image_data = {
 | 
				
			||||||
 | 
					            "ID": self.curr_art_id,
 | 
				
			||||||
 | 
					            "title": self.curr_image_title,
 | 
				
			||||||
 | 
					            "authors": self.curr_presences,
 | 
				
			||||||
 | 
					            "path": self.curr_art_path,
 | 
				
			||||||
 | 
					            "tags": self.curr_tags,
 | 
				
			||||||
 | 
					            "link": self.curr_link,
 | 
				
			||||||
 | 
					            "md5_hash": self.__main.get_md5_of_image(self.curr_art_path)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for presence in self.curr_presences:
 | 
				
			||||||
 | 
					            if presence[-1] == "(Not in Database)":
 | 
				
			||||||
 | 
					                msg = QtWidgets.QMessageBox()
 | 
				
			||||||
 | 
					                msg.setWindowTitle("Invalid Presence Domain")
 | 
				
			||||||
 | 
					                msg.setInformativeText("You've tried to save with a not working presence entry! " +
 | 
				
			||||||
 | 
					                                       "Please add one from the database!")
 | 
				
			||||||
 | 
					                msg.setIcon(QtWidgets.QMessageBox.Warning)
 | 
				
			||||||
 | 
					                msg.exec_()
 | 
				
			||||||
 | 
					                return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.db_connection.save_image(ID=image_data["ID"], title=image_data["title"],
 | 
				
			||||||
 | 
					                                             authors=image_data["authors"], path=image_data["path"],
 | 
				
			||||||
 | 
					                                             tags=image_data["tags"], link=image_data["link"],
 | 
				
			||||||
 | 
					                                             md5_hash=image_data["md5_hash"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_temporary_status_message("Saved {0} ({1}) to ArtNet DB!"
 | 
				
			||||||
 | 
					                                          .format(self.curr_image_title, self.curr_art_id), 5000)
 | 
				
			||||||
 | 
					        self.update_window_title()
 | 
				
			||||||
 | 
					        self.data_changed = False
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_temporary_status_message(self, text: str, duration: int):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set a temporary status message (bottom left) for the given duration in milliseconds.
 | 
				
			||||||
 | 
					        :param text:
 | 
				
			||||||
 | 
					        :param duration:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.ui.statusbar.showMessage(text, duration)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_presence(self, name: str, domain: str, artist: tuple, link: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Create a new Presence Entry with the given data
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :param artist:
 | 
				
			||||||
 | 
					        :param link:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if len(name) == 0 or len(domain) == 0 or artist is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.__main.db_connection.save_presence(name=name, domain=domain, artist_ID=artist[0], link=link)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_presence(self, name: str, domain: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Remove the presence from the DB
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.__main.db_connection.remove_presence(name, domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_authors(self, presence_name: str, presence_domain: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query a search for the authors fitting the given strings
 | 
				
			||||||
 | 
					        :param presence_name:
 | 
				
			||||||
 | 
					        :param presence_domain:
 | 
				
			||||||
 | 
					        :return: a list of tuples of (presence_name, presence_domain)
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__main.db_connection.search_fuzzy_presence(presence_name, presence_domain, all_if_empty=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_artist(self, ID: int, description: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Create a new artist with the given data (or update an exisitng one if ID is already taken
 | 
				
			||||||
 | 
					        :param ID:
 | 
				
			||||||
 | 
					        :param description:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.__main.db_connection.save_artist(ID, description)
 | 
				
			||||||
 | 
					        self.set_temporary_status_message("Created Artist {0}!".format(description), 3000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_artists(self, search: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query a search for the artists fitting the given data best. Search is fuzzy.
 | 
				
			||||||
 | 
					        :param search: either an ID (int) or the description
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            ID_int = int(search)
 | 
				
			||||||
 | 
					            description = None
 | 
				
			||||||
 | 
					        except ValueError:
 | 
				
			||||||
 | 
					            ID_int = None
 | 
				
			||||||
 | 
					            description = search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.__main.db_connection.search_fuzzy_artists(ID_int, description)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_artist(self, id: int) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query for the artist matching id. Returns None if the data does not exactly fit.
 | 
				
			||||||
 | 
					        :param id:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__main.db_connection.get_artist(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_artist(self, id: int):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Delte the given artist from the database.
 | 
				
			||||||
 | 
					        :param id:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.__main.db_connection.remove_artist(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_artist_presences(self, id: int) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query for all presences associated with the given artist.
 | 
				
			||||||
 | 
					        :param id:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__main.db_connection.get_artist_presences(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_all_artists(self) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Queries the database for a list of all available arists (not presences).
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__main.db_connection.get_all_artists()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_presence(self, name: str, domain: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query a search for the presence fitting the data
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        result = self.__main.db_connection.get_presence(name, domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return result if len(result) != 0 else None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_presence(self, name: str, domain: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Deletes a presence from the database and removes all Art_Author entries containing this presence.
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.__main.db_connection.remove_presence(name, domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_presences_art(self, name: str, domain: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query a list of art owned by the given presence
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__main.db_connection.get_presences_art(name, domain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_current_presences(self) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Get the presences currently associated with the current art
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.curr_presences
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_current_presences(self, presences: list):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the presences associated with the current art
 | 
				
			||||||
 | 
					        :param presences:  list of tuples of (name, domain)
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if len(presences) > 1:
 | 
				
			||||||
 | 
					            for name, domain in presences:
 | 
				
			||||||
 | 
					                if domain == "(Not in Database)":
 | 
				
			||||||
 | 
					                    presences.remove((name, domain))
 | 
				
			||||||
 | 
					        elif len(presences) == 0:
 | 
				
			||||||
 | 
					            presences = [(self.curr_art_path.split("/")[0], "(Not in Database)")]
 | 
				
			||||||
 | 
					        self.curr_presences = presences
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.curr_presences is not None:
 | 
				
			||||||
 | 
					            self.set_presence_label_text(self.curr_presences)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data_changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_categories(self, search: str, all_if_empty: bool = False):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Fuzzy Query for categories in the database.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        all_if_empty causes an empty search to return all categories instead of none
 | 
				
			||||||
 | 
					        :param search:
 | 
				
			||||||
 | 
					        :param all_if_empty:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if all_if_empty and len(search) == 0:
 | 
				
			||||||
 | 
					            return self.__main.db_connection.get_all_categories()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.__main.db_connection.search_fuzzy_categories(search)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_image_link_from_line(self) -> str:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Gets the image link from the QLineEdit if it is a valid link.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Otherwise an empty string
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.ui.link_line.text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_presence_label_text(self, presences: list):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the label listing all current presences and include links if possible.
 | 
				
			||||||
 | 
					        :param presences:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        links = []
 | 
				
			||||||
 | 
					        s = ""
 | 
				
			||||||
 | 
					        for name, domain in presences:
 | 
				
			||||||
 | 
					            full_data = self.get_presence(name, domain)
 | 
				
			||||||
 | 
					            if full_data is None:
 | 
				
			||||||
 | 
					                link = ""
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                name, domain, _, link = full_data[0]
 | 
				
			||||||
 | 
					            text = name + ":" + domain
 | 
				
			||||||
 | 
					            if link is None or len(link) == 0:  # no link, then just do plain text
 | 
				
			||||||
 | 
					                hyperlink = text
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                hyperlink = "<a href=\"{0}\">{1}</a>".format(link, text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            s += hyperlink
 | 
				
			||||||
 | 
					            s += "|"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        s = s[:-1]
 | 
				
			||||||
 | 
					        self.ui.image_author_label.setText(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_image_title_link(self) -> str:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Sets the Image title to a link if there is link data given for this image.
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.ui.link_label.setText("No Source Available")
 | 
				
			||||||
 | 
					        link = self.ui.link_line.text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if validators.url(link):
 | 
				
			||||||
 | 
					            self.curr_link = link
 | 
				
			||||||
 | 
					            self.data_changed = True
 | 
				
			||||||
 | 
					            hyperlink = "<a href=\"{0}\">{1}</a>".format(link, "Source")
 | 
				
			||||||
 | 
					            self.ui.link_label.setText(hyperlink)
 | 
				
			||||||
 | 
					            return link
 | 
				
			||||||
 | 
					        elif len(link) == 0:
 | 
				
			||||||
 | 
					            return ""
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.ui.link_label.setText("No Source Available")
 | 
				
			||||||
 | 
					            self.set_temporary_status_message("Invalid link \"{0}\" detected!".format(link), 5000)
 | 
				
			||||||
 | 
					            return ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag(self, name: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query a search for the tag to the DB and return the result
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__main.db_connection.get_tag_by_name(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_aliases(self, name: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query a search for the tag's aliases to the DB
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Note: Returns all aliases as a list of their IDs
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__main.db_connection.get_tag_aliases(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_implications(self, name: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query a search for the tag's implications to the DB
 | 
				
			||||||
 | 
					        :param name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__main.db_connection.get_tag_implications(name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tag_search_result(self, name: str) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Query a search for tags to the DB that are like name
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__main.db_connection.search_fuzzy_tag(name, all_if_empty=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_search_result_list(self, tags: list):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the tags in the search result list to tags
 | 
				
			||||||
 | 
					        :param tags:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.search_result_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in tags:
 | 
				
			||||||
 | 
					            item = QStandardItem(tag)
 | 
				
			||||||
 | 
					            flags = Qt.ItemIsEnabled
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if tag not in self.curr_imply_tags+self.curr_tag_aliases and tag not in self.curr_tags:
 | 
				
			||||||
 | 
					                item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					                flags |= Qt.ItemIsUserCheckable
 | 
				
			||||||
 | 
					            if self.curr_tags is not None and tag in (self.curr_tags+self.curr_imply_tags+self.curr_tag_aliases):
 | 
				
			||||||
 | 
					                # already selected, implied or aliased tags
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					            item.setFlags(flags)
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_tag_search_item_changed)
 | 
				
			||||||
 | 
					        self.ui.search_result_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_tag_list(self, tags: list, set_checked: bool = True, no_implication: bool = False):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Set the tags in the tag list to this.
 | 
				
			||||||
 | 
					        Also updates the tag implication list if no_implication is False
 | 
				
			||||||
 | 
					        :param tags:
 | 
				
			||||||
 | 
					        :param set_checked:
 | 
				
			||||||
 | 
					        :param no_implication: bool indicating if the implication list should also be updated
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.curr_tags = tags
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.tag_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for tag in tags:
 | 
				
			||||||
 | 
					            item = QStandardItem(tag)
 | 
				
			||||||
 | 
					            item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
 | 
				
			||||||
 | 
					            item.setData(Qt.Unchecked, Qt.CheckStateRole)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if set_checked:
 | 
				
			||||||
 | 
					                item.setCheckState(Qt.Checked)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        item_model.itemChanged.connect(self.on_tag_item_changed)
 | 
				
			||||||
 | 
					        self.ui.tag_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        implied_tags = []
 | 
				
			||||||
 | 
					        for x in self.curr_tags:
 | 
				
			||||||
 | 
					            # collect all implied tags into a list
 | 
				
			||||||
 | 
					            implied_tags += self.__main.db_connection.get_all_tag_implications(x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_implied_list(implied_tags)
 | 
				
			||||||
 | 
					        self.curr_tag_aliases = list()
 | 
				
			||||||
 | 
					        for tag in tags+implied_tags:
 | 
				
			||||||
 | 
					            self.curr_tag_aliases += self.__main.db_connection.get_tag_aliases(tag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data_changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_implied_list(self, tags: list):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Sets the implied tags in the imply list
 | 
				
			||||||
 | 
					        :param tags:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.curr_imply_tags = tags
 | 
				
			||||||
 | 
					        item_model = QStandardItemModel(self.ui.implied_tag_list)
 | 
				
			||||||
 | 
					        done = []
 | 
				
			||||||
 | 
					        for tag in tags:
 | 
				
			||||||
 | 
					            if tag in done:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                done.append(tag)
 | 
				
			||||||
 | 
					            item = QStandardItem(tag)
 | 
				
			||||||
 | 
					            item_model.appendRow(item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.implied_tag_list.setModel(item_model)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.data_changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def display_image(self, image_title: str, image_authors: list, full_path: str, relative_path: str, art_ID: int,
 | 
				
			||||||
 | 
					                      link: str, file_name: str):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Display an image in the central widget
 | 
				
			||||||
 | 
					        :param image_authors:
 | 
				
			||||||
 | 
					        :param image_title:
 | 
				
			||||||
 | 
					        :param full_path:
 | 
				
			||||||
 | 
					        :param relative_path:
 | 
				
			||||||
 | 
					        :param art_ID:
 | 
				
			||||||
 | 
					        :param link:
 | 
				
			||||||
 | 
					        :param file_name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.curr_art_id = art_ID
 | 
				
			||||||
 | 
					        self.curr_art_path = relative_path
 | 
				
			||||||
 | 
					        self.curr_image_title = image_title
 | 
				
			||||||
 | 
					        self.curr_file_name = os.path.basename(full_path)
 | 
				
			||||||
 | 
					        self.curr_link = link
 | 
				
			||||||
 | 
					        self.set_current_presences(image_authors)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        file_ending = relative_path.split(".")[-1]
 | 
				
			||||||
 | 
					        if self.__showing_video:  # remove old video from image layout
 | 
				
			||||||
 | 
					            #self.ui.image_frame.layout().removeWidget(self.__video)
 | 
				
			||||||
 | 
					            self.__video.hide()
 | 
				
			||||||
 | 
					            self.ui.image_label.show()
 | 
				
			||||||
 | 
					        if file_ending in ["gif"]:
 | 
				
			||||||
 | 
					            self.__showing_video = False
 | 
				
			||||||
 | 
					            self.__pixmap = QMovie(full_path)
 | 
				
			||||||
 | 
					            self.ui.image_label.setMovie(self.__pixmap)
 | 
				
			||||||
 | 
					            self.__pixmap.start()
 | 
				
			||||||
 | 
					            self.__pixmap.frameChanged.connect(self.on_movie_frame_changed)
 | 
				
			||||||
 | 
					        elif file_ending in ["webm"]:
 | 
				
			||||||
 | 
					            self.__showing_video = True
 | 
				
			||||||
 | 
					            self.__video = QVideoWidget()
 | 
				
			||||||
 | 
					            self.__player = QtMultimedia.QMediaPlayer(None, QtMultimedia.QMediaPlayer.VideoSurface)
 | 
				
			||||||
 | 
					            self.__player.setVideoOutput(self.__video)
 | 
				
			||||||
 | 
					            self.__player.setMedia(QtMultimedia.QMediaContent(QUrl.fromLocalFile(full_path)))
 | 
				
			||||||
 | 
					            self.__player.play()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.ui.image_frame.layout().addWidget(self.__video)
 | 
				
			||||||
 | 
					            self.ui.image_label.hide()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.__player.stateChanged.connect(self.on_movie_player_state_changed)
 | 
				
			||||||
 | 
					            self.__player.positionChanged.connect(self.on_movie_position_changed)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.__showing_video = False
 | 
				
			||||||
 | 
					            self.__pixmap = QPixmap(full_path)
 | 
				
			||||||
 | 
					            self.ui.image_label.setPixmap(self.__pixmap)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.ui.image_label.setScaledContents(True)
 | 
				
			||||||
 | 
					            self.ui.image_label.setFixedSize(0, 0)
 | 
				
			||||||
 | 
					            self.__image_resize()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.image_label.setAlignment(Qt.AlignCenter)
 | 
				
			||||||
 | 
					        self.ui.image_title_line.setText(image_title)
 | 
				
			||||||
 | 
					        self.update_window_title()
 | 
				
			||||||
 | 
					        self.ui.link_line.setText(link)
 | 
				
			||||||
 | 
					        self.ui.image_file_label.setText(file_name)
 | 
				
			||||||
 | 
					        self.set_image_title_link()
 | 
				
			||||||
 | 
					        self.set_image_id_spinbox()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_window_title(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Update the title of the window with the newest image title as given in text field
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        image_title = self.ui.image_title_line.text()
 | 
				
			||||||
 | 
					        self.setWindowTitle(self.main_title + " - " + image_title
 | 
				
			||||||
 | 
					                            + f" ({round(self.__main.known_image_amount/len(self.__main.all_images), 5)}%)")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_image_id_spinbox(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Sets the imageIDSpinBox to the image ID of the currently displayed image
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        self.ui.imageNumberSpinBox.setMinimum(0)
 | 
				
			||||||
 | 
					        self.ui.imageNumberSpinBox.setMaximum(len(self.__main.all_images)-1)
 | 
				
			||||||
 | 
					        self.ui.imageNumberSpinBox.setValue(self.__main.curr_image_index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __image_resize(self):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Resize the given pixmap so that we're not out of the desktop.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :return: new scaled QPixmap
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if self.ui.image_label.movie() is not None or self.__showing_video:  # if QMovie was used instead of image
 | 
				
			||||||
 | 
					            rect = self.geometry()
 | 
				
			||||||
 | 
					            size = QSize(min(rect.width(), rect.height()), min(rect.width(), rect.height()))
 | 
				
			||||||
 | 
					            if type(self.__pixmap) != QMovie:  # using QVideoWidget?
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					                #self.__player.setScaledSize(size)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.__pixmap.setScaledSize(size)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        size = self.__pixmap.size()
 | 
				
			||||||
 | 
					        screen_rect = QtWidgets.QDesktopWidget().screenGeometry()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        size.scale(int(screen_rect.width() * 0.6), int(screen_rect.height() * 0.6),
 | 
				
			||||||
 | 
					                   Qt.KeepAspectRatio)
 | 
				
			||||||
 | 
					        self.ui.image_label.setFixedSize(size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def resizeEvent(self, a0: QResizeEvent) -> None:
 | 
				
			||||||
 | 
					        self.__image_resize()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def keyPressEvent(self, a0: QKeyEvent) -> None:
 | 
				
			||||||
 | 
					        super(Window, self).keyPressEvent(a0)
 | 
				
			||||||
 | 
					        if a0.key() == Qt.Key_Left:
 | 
				
			||||||
 | 
					            self.on_previous_clicked()
 | 
				
			||||||
 | 
					        elif a0.key() == Qt.Key_Right:
 | 
				
			||||||
 | 
					            self.on_next_clicked()
 | 
				
			||||||
 | 
					        elif a0.key() == Qt.Key_Return:
 | 
				
			||||||
 | 
					            print("Pressed Enter!")
 | 
				
			||||||
 | 
					            if self.__showing_video:
 | 
				
			||||||
 | 
					                s = self.__player.state()
 | 
				
			||||||
 | 
					                if self.__player.state() == QtMultimedia.QMediaPlayer.PlayingState:
 | 
				
			||||||
 | 
					                    self.__player.pause()
 | 
				
			||||||
 | 
					                    self.set_temporary_status_message("Paused the Video!", 3000)
 | 
				
			||||||
 | 
					                elif self.__player.state() == QtMultimedia.QMediaPlayer.PausedState:
 | 
				
			||||||
 | 
					                    self.__player.play()
 | 
				
			||||||
 | 
					                    self.set_temporary_status_message("Started the Video!", 3000)
 | 
				
			||||||
 | 
					                elif self.__player.state() == QtMultimedia.QMediaPlayer.StoppedState:
 | 
				
			||||||
 | 
					                    self.__player.play()
 | 
				
			||||||
 | 
					                    self.set_temporary_status_message("Restarted the Video!", 3000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            elif type(self.__pixmap) == QMovie:
 | 
				
			||||||
 | 
					                if self.__pixmap.state() == QMovie.Paused:
 | 
				
			||||||
 | 
					                    self.__pixmap.start()
 | 
				
			||||||
 | 
					                    self.set_temporary_status_message("Started the Video!", 3000)
 | 
				
			||||||
 | 
					                elif self.__pixmap.state() == QMovie.Running:
 | 
				
			||||||
 | 
					                    self.__pixmap.setPaused(True)
 | 
				
			||||||
 | 
					                    self.set_temporary_status_message("Paused the Video!", 3000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_movie_player_state_changed(self, state: int):
 | 
				
			||||||
 | 
					        self.__image_resize()
 | 
				
			||||||
 | 
					        if QtMultimedia.QMediaPlayer.StoppedState == state:  # player stopped
 | 
				
			||||||
 | 
					            self.set_temporary_status_message("Reached end of Video!", 2000)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_movie_position_changed(self, position):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_movie_frame_changed(self, frame_number: int):
 | 
				
			||||||
 | 
					        if type(self.__pixmap) != QMovie:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if frame_number == 0:
 | 
				
			||||||
 | 
					            self.set_temporary_status_message("Reached end of Video!", 2000)
 | 
				
			||||||
 | 
					            self.__pixmap.setPaused(True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_save_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked Save!")
 | 
				
			||||||
 | 
					        self.set_image_title_link()
 | 
				
			||||||
 | 
					        self.save_changes()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_import_tags_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked Import!")
 | 
				
			||||||
 | 
					        dialog = TagImportDialog(self)
 | 
				
			||||||
 | 
					        if len(self.get_image_link_from_line()) == 0 or self.get_image_link_from_line() == '(Unknown)':
 | 
				
			||||||
 | 
					            url = LinkGenerator.get_instance().construct_link(self.curr_file_name,
 | 
				
			||||||
 | 
					                                                              LinkGenerator.get_instance()
 | 
				
			||||||
 | 
					                                                              .predict_domain(self.curr_file_name))
 | 
				
			||||||
 | 
					            self.ui.link_line.setText(url)  # Update no link to the predicted link
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            url = self.get_image_link_from_line()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        r = self.__main.scrape_tags(self.curr_file_name, url=url,
 | 
				
			||||||
 | 
					                                    art_ID=self.curr_art_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if r is None:
 | 
				
			||||||
 | 
					            msg = QtWidgets.QMessageBox()
 | 
				
			||||||
 | 
					            msg.setWindowTitle("Unsupported Domain")
 | 
				
			||||||
 | 
					            msg.setInformativeText("Could not predict a supported domain!")
 | 
				
			||||||
 | 
					            msg.setIcon(QtWidgets.QMessageBox.Warning)
 | 
				
			||||||
 | 
					            msg.exec_()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.ui.link_line.setText(url)
 | 
				
			||||||
 | 
					        self.set_image_title_link()
 | 
				
			||||||
 | 
					        tags, artists = r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        i = 0
 | 
				
			||||||
 | 
					        while i < len(tags):  # workaround for an issue with altering lists during iteration
 | 
				
			||||||
 | 
					            r = self.__main.db_connection.get_tag_by_name(tags[i])
 | 
				
			||||||
 | 
					            if len(r) > 0:
 | 
				
			||||||
 | 
					                self.curr_tags.append(tags[i])
 | 
				
			||||||
 | 
					                self.data_changed = True
 | 
				
			||||||
 | 
					                tags.remove(tags[i])
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                i += 1
 | 
				
			||||||
 | 
					        self.set_tag_list(self.curr_tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(tags) == 0:
 | 
				
			||||||
 | 
					            msg = QtWidgets.QMessageBox()
 | 
				
			||||||
 | 
					            msg.setWindowTitle("Nothing to import!")
 | 
				
			||||||
 | 
					            msg.setInformativeText("There were no tags to import for this art!")
 | 
				
			||||||
 | 
					            msg.setIcon(QtWidgets.QMessageBox.Information)
 | 
				
			||||||
 | 
					            msg.exec_()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        dialog.set_import_tag_list(tags)
 | 
				
			||||||
 | 
					        dialog.set_detected_artists(artists)
 | 
				
			||||||
 | 
					        dialog.set_used_link(url)
 | 
				
			||||||
 | 
					        dialog.to_import = tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = dialog.exec_()
 | 
				
			||||||
 | 
					        if result is None:
 | 
				
			||||||
 | 
					            self.set_tag_list(self.curr_tags)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.import_tags(self.curr_art_id, result)
 | 
				
			||||||
 | 
					        self.set_tag_list(self.curr_tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_next_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked Next!")
 | 
				
			||||||
 | 
					        if not self.check_save_changes():
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.curr_image_index += 1
 | 
				
			||||||
 | 
					        if self.__main.curr_image_index >= len(self.__main.all_images):
 | 
				
			||||||
 | 
					            self.__main.curr_image_index = 0
 | 
				
			||||||
 | 
					        self.__main.change_image()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.presence_docker_open:
 | 
				
			||||||
 | 
					            self.toggle_presence_docker()
 | 
				
			||||||
 | 
					        self.on_tag_search_change()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_image_title_change(self):
 | 
				
			||||||
 | 
					        self.data_changed = True
 | 
				
			||||||
 | 
					        self.curr_image_title = self.ui.image_title_line.text()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_previous_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked previous!")
 | 
				
			||||||
 | 
					        if not self.check_save_changes():
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.curr_image_index -= 1
 | 
				
			||||||
 | 
					        if self.__main.curr_image_index < 0:
 | 
				
			||||||
 | 
					            self.__main.curr_image_index += len(self.__main.all_images)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.change_image()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.presence_docker_open:
 | 
				
			||||||
 | 
					            self.toggle_presence_docker()
 | 
				
			||||||
 | 
					        self.on_tag_search_change()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def toggle_presence_docker(self):
 | 
				
			||||||
 | 
					        print("Clicked presence docker button!")
 | 
				
			||||||
 | 
					        if not self.presence_docker_open:
 | 
				
			||||||
 | 
					            self.presence_docker = PresenceDocker(self)
 | 
				
			||||||
 | 
					            self.ui.presence_docker_layout.addWidget(self.presence_docker)
 | 
				
			||||||
 | 
					            self.presence_docker.set_selected_presences_list(self.get_current_presences())
 | 
				
			||||||
 | 
					            self.ui.presence_docker_button.setText(">")
 | 
				
			||||||
 | 
					            self.presence_docker_open = True
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.presence_docker.setParent(None)
 | 
				
			||||||
 | 
					            self.ui.presence_docker_button.setText("<")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.presence_docker.destroy()
 | 
				
			||||||
 | 
					            self.presence_docker = None
 | 
				
			||||||
 | 
					            self.presence_docker_open = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_artnet_root_change_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked changing ArtNet root!")
 | 
				
			||||||
 | 
					        dialog = QtWidgets.QFileDialog(self, 'Choose new ArtNet root:')
 | 
				
			||||||
 | 
					        dialog.setFileMode(QtWidgets.QFileDialog.Directory)
 | 
				
			||||||
 | 
					        dialog.setOptions(QtWidgets.QFileDialog.ShowDirsOnly)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        directory = dialog.getExistingDirectory()
 | 
				
			||||||
 | 
					        self.__main.change_root(directory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_db_connection_change_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked db connection change!")
 | 
				
			||||||
 | 
					        dialog = DBDialog(self)
 | 
				
			||||||
 | 
					        prev_db_data = self.__main.get_db_connection_details()
 | 
				
			||||||
 | 
					        dialog.ui.user_line_edit.setText(prev_db_data["user"])
 | 
				
			||||||
 | 
					        dialog.ui.password_line_edit.setText(prev_db_data["password"])
 | 
				
			||||||
 | 
					        dialog.ui.host_line_edit.setText(prev_db_data["host"])
 | 
				
			||||||
 | 
					        dialog.ui.database_line_edit.setText(prev_db_data["database"])
 | 
				
			||||||
 | 
					        dialog.ui.port_line_edit.setText(str(prev_db_data["port"]))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        db_data: dict = dialog.exec_()
 | 
				
			||||||
 | 
					        if len(db_data.keys()) == 0:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.__main.change_db_connection(host=db_data["host"], port=db_data["port"],
 | 
				
			||||||
 | 
					                                         user=db_data["user"], password=db_data["password"],
 | 
				
			||||||
 | 
					                                         database=db_data["database"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_tag_creation_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked Tag Creation!")
 | 
				
			||||||
 | 
					        dialog = TagModifyDialog(self, create_tag=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tag_data: dict = dialog.exec_()
 | 
				
			||||||
 | 
					        print("Got Tag data", tag_data)
 | 
				
			||||||
 | 
					        if tag_data is None or len(tag_data.keys()) == 0:  # got canceled?
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(self.get_tag(tag_data["name"])) > 0:
 | 
				
			||||||
 | 
					            QtWidgets.QMessageBox.information(self, "Duplicate Tag", "The tag \"{0}\" already exists in the db!"
 | 
				
			||||||
 | 
					                                              .format(tag_data["name"]))
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.__main.db_connection.create_tag(name=tag_data["name"], description=tag_data["description"],
 | 
				
			||||||
 | 
					                                             aliases=tag_data["aliases"], implications=tag_data["implications"],
 | 
				
			||||||
 | 
					                                             category=tag_data["category"])
 | 
				
			||||||
 | 
					        self.on_tag_search_change()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_tag_deletion_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked Tag Deletion!")
 | 
				
			||||||
 | 
					        dialog = TagSelectDialog(self, delete_tag=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tag = dialog.exec_()
 | 
				
			||||||
 | 
					        print("Got Tag", tag)
 | 
				
			||||||
 | 
					        if tag is None or len(tag) == 0:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        confirmation_reply = QtWidgets.QMessageBox.question(self, "Delete Tag \"{0}\"".format(tag["name"]),
 | 
				
			||||||
 | 
					                                                            "Are you sure you want to delete this Tag?",
 | 
				
			||||||
 | 
					                                                            QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No,
 | 
				
			||||||
 | 
					                                                            QtWidgets.QMessageBox.No)
 | 
				
			||||||
 | 
					        if confirmation_reply == QtWidgets.QMessageBox.No:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.db_connection.remove_tag(tag["name"])
 | 
				
			||||||
 | 
					        self.on_tag_search_change()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def force_edit_tag_dialog(self, name: str):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        edit_dialog = TagModifyDialog(self, create_tag=True)
 | 
				
			||||||
 | 
					        edit_dialog.ui.tag_name_line.setText(name)
 | 
				
			||||||
 | 
					        edit_dialog.ui.tag_description_area.setText("")
 | 
				
			||||||
 | 
					        edit_dialog.set_selected_alias_tags([], set_checked=True)
 | 
				
			||||||
 | 
					        edit_dialog.alias_selection = []
 | 
				
			||||||
 | 
					        edit_dialog.set_selected_implicated_tags([], set_checked=True)
 | 
				
			||||||
 | 
					        edit_dialog.implication_selection = []
 | 
				
			||||||
 | 
					        edit_dialog.category_selection = []
 | 
				
			||||||
 | 
					        edit_dialog.set_all_categories()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tag_data = edit_dialog.exec_()
 | 
				
			||||||
 | 
					        print("Got Tag data", tag_data)
 | 
				
			||||||
 | 
					        if tag_data is None or len(tag_data.keys()) == 0:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        if len(tag_data["category"]) == 0:
 | 
				
			||||||
 | 
					            answer = QtWidgets.QMessageBox.information(self, "No Category",
 | 
				
			||||||
 | 
					                                                       "There has been no Category selected for this tag! "
 | 
				
			||||||
 | 
					                                                       "No tag is allowed without a category!")
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if len(self.get_tag(tag_data['name'])) > 0:
 | 
				
			||||||
 | 
					            QtWidgets.QMessageBox.information(self, "Tag already exists",
 | 
				
			||||||
 | 
					                                              "The Tag \"{0}\" you wanted to create already exists! Skipping...")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.__main.db_connection.create_tag(name=tag_data["name"], description=tag_data["description"],
 | 
				
			||||||
 | 
					                                                 aliases=tag_data["aliases"], implications=tag_data["implications"],
 | 
				
			||||||
 | 
					                                                 category=tag_data["category"])
 | 
				
			||||||
 | 
					        self.on_tag_search_change()
 | 
				
			||||||
 | 
					        return tag_data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_tag_edit_clicked(self):
 | 
				
			||||||
 | 
					        print("Clicked Tag Editing!")
 | 
				
			||||||
 | 
					        select_dialog = TagSelectDialog(self, delete_tag=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tag = select_dialog.exec_()
 | 
				
			||||||
 | 
					        if tag is None or len(tag) == 0:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tag['aliases'] = self.__main.db_connection.get_tag_aliases(tag["name"])
 | 
				
			||||||
 | 
					        tag['implications'] = self.__main.db_connection.get_tag_implications(tag["name"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        edit_dialog = TagModifyDialog(self, create_tag=False)
 | 
				
			||||||
 | 
					        edit_dialog.ui.tag_name_line.setText(tag["name"])
 | 
				
			||||||
 | 
					        edit_dialog.ui.tag_description_area.setText(tag["description"])
 | 
				
			||||||
 | 
					        edit_dialog.set_selected_alias_tags(tag["aliases"], set_checked=True)
 | 
				
			||||||
 | 
					        edit_dialog.alias_selection = tag["aliases"]
 | 
				
			||||||
 | 
					        edit_dialog.set_selected_implicated_tags(tag["implications"], set_checked=True)
 | 
				
			||||||
 | 
					        edit_dialog.implication_selection = tag["implications"]
 | 
				
			||||||
 | 
					        edit_dialog.category_selection = tag["category"]
 | 
				
			||||||
 | 
					        edit_dialog.set_all_categories()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        tag_data = edit_dialog.exec_()
 | 
				
			||||||
 | 
					        print("Got Tag data", tag_data)
 | 
				
			||||||
 | 
					        if tag_data is None or len(tag_data.keys()) == 0:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if "old_tag_name" not in tag_data.keys():
 | 
				
			||||||
 | 
					            tag_data["old_tag_name"] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.db_connection.edit_tag(name=tag_data["name"], description=tag_data["description"],
 | 
				
			||||||
 | 
					                                           aliases=tag_data["aliases"], implications=tag_data["implications"],
 | 
				
			||||||
 | 
					                                           category=tag_data["category"], old_tag=tag_data["old_tag_name"])
 | 
				
			||||||
 | 
					        self.on_tag_search_change()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_tag_search_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Checked:
 | 
				
			||||||
 | 
					            self.curr_tags.append(item.text())
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            if item.text() in self.curr_tags:
 | 
				
			||||||
 | 
					                self.curr_tags.remove(item.text())
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        self.set_tag_list(self.curr_tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_tag_item_changed(self, item: QStandardItem):
 | 
				
			||||||
 | 
					        print("Item {0} has changed!".format(item.text()))
 | 
				
			||||||
 | 
					        if item.checkState() == Qt.Unchecked:
 | 
				
			||||||
 | 
					            if item.text() in self.curr_tags:
 | 
				
			||||||
 | 
					                self.curr_tags.remove(item.text())
 | 
				
			||||||
 | 
					                self.set_tag_list(self.curr_tags)
 | 
				
			||||||
 | 
					                self.on_tag_search_change()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise Exception("Something went terribly wrong!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_tag_search_change(self):
 | 
				
			||||||
 | 
					        tags = self.__main.db_connection.search_fuzzy_tag(self.ui.tag_search_bar.text(), all_if_empty=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = []
 | 
				
			||||||
 | 
					        for tag_name, tag_desc, tag_category in tags:
 | 
				
			||||||
 | 
					            result.append(tag_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.set_search_result_list(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_category_creation_clicked(self):
 | 
				
			||||||
 | 
					        dialog = CategoryModDialog(self, delete_category=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data = dialog.exec_()
 | 
				
			||||||
 | 
					        if data is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.db_connection.save_category(data["name"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_category_deletion_clicked(self):
 | 
				
			||||||
 | 
					        dialog = CategoryModDialog(self, delete_category=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data = dialog.exec_()
 | 
				
			||||||
 | 
					        if data is None:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.db_connection.remove_category(data["name"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_link_line_change(self):
 | 
				
			||||||
 | 
					        self.data_changed = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_prev_unknown_image_clicked(self):
 | 
				
			||||||
 | 
					        unknown_image_index = self.__main.get_prev_unknown_image()
 | 
				
			||||||
 | 
					        print("Previous unknown image clicked!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = QtWidgets.QMessageBox.question(self, "Switch Image?",
 | 
				
			||||||
 | 
					                                                "Do you really want to skip to image #{1} \"{0}\"?"
 | 
				
			||||||
 | 
					                                                .format(self.__main.all_images[unknown_image_index],
 | 
				
			||||||
 | 
					                                                        unknown_image_index))
 | 
				
			||||||
 | 
					        if result == QtWidgets.QMessageBox.Yes:
 | 
				
			||||||
 | 
					            self.__main.curr_image_index = unknown_image_index
 | 
				
			||||||
 | 
					            self.__main.change_image()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_next_unknown_image_clicked(self):
 | 
				
			||||||
 | 
					        unknown_image_index = self.__main.get_next_unknown_image()
 | 
				
			||||||
 | 
					        print("Next unknown image clicked!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        result = QtWidgets.QMessageBox.question(self, "Switch Image?",
 | 
				
			||||||
 | 
					                                                "Do you really want to skip to image #{1} \"{0}\"?"
 | 
				
			||||||
 | 
					                                                .format(self.__main.all_images[unknown_image_index],
 | 
				
			||||||
 | 
					                                                        unknown_image_index))
 | 
				
			||||||
 | 
					        if result == QtWidgets.QMessageBox.Yes:
 | 
				
			||||||
 | 
					            self.__main.curr_image_index = unknown_image_index
 | 
				
			||||||
 | 
					            self.__main.change_image()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_image_id_spinbox_changed(self, v: int):
 | 
				
			||||||
 | 
					        if self.__tmp_imageid_spinbox == v:
 | 
				
			||||||
 | 
					            print("SpinBox change detected!")
 | 
				
			||||||
 | 
					            result = QtWidgets.QMessageBox.question(self, "Switch Image?",
 | 
				
			||||||
 | 
					                                                    "Do you really want to skip to image #{1} \"{0}\"?"
 | 
				
			||||||
 | 
					                                                    .format(self.__main.all_images[v],
 | 
				
			||||||
 | 
					                                                            v))
 | 
				
			||||||
 | 
					            if result == QtWidgets.QMessageBox.Yes:
 | 
				
			||||||
 | 
					                self.__main.curr_image_index = v
 | 
				
			||||||
 | 
					                self.__main.change_image()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__tmp_imageid_spinbox: int = v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_delete_image_clicked(self):
 | 
				
			||||||
 | 
					        print("Delete clicked!")
 | 
				
			||||||
 | 
					        art_hash = self.__main.get_md5_of_image(self.curr_art_path)
 | 
				
			||||||
 | 
					        if self.__main.db_connection.get_art_by_hash(art_hash) is not None:
 | 
				
			||||||
 | 
					            print("Delete on known image")
 | 
				
			||||||
 | 
					            confirm_result = QtWidgets.QMessageBox.question(self, "Delete data?", "Do you really wish to delete all "
 | 
				
			||||||
 | 
					                                                                                  "data from the DB about this image?")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if confirm_result == QtWidgets.QMessageBox.Yes:
 | 
				
			||||||
 | 
					                print(f"deleting image data of \"{self.curr_image_title}\"")
 | 
				
			||||||
 | 
					                self.__main.db_connection.remove_image(art_hash)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print("Delete on unknown image")
 | 
				
			||||||
 | 
					            confirm_result = QtWidgets.QMessageBox.question(self, "Delete image?", "Do you really wish to delete this "
 | 
				
			||||||
 | 
					                                                                                   "image?")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if confirm_result == QtWidgets.QMessageBox.Yes:
 | 
				
			||||||
 | 
					                print("deleting image file")
 | 
				
			||||||
 | 
					                self.__main.delete_image(self.curr_art_path)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.__main.change_image()
 | 
				
			||||||
@ -0,0 +1,169 @@
 | 
				
			|||||||
 | 
					import re
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
 | 
					import lxml.html
 | 
				
			||||||
 | 
					from urllib.parse import urlparse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DOMAIN_UNKNOWN = -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DomainIdentifier:
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Makeshift-automated enum class to allow runtime expansion of an enum.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Create an instance to get a new unique domain identifier that can resolve to an int.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TODO find better way :D
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    __domain_list = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, name: str):
 | 
				
			||||||
 | 
					        self.__name = name
 | 
				
			||||||
 | 
					        self.__domain_number = len(DomainIdentifier.__domain_list)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if DomainIdentifier.get_identifier(name) is not None:
 | 
				
			||||||
 | 
					            raise Exception("The domain \"{0}\" is already in the list! Tried to create a duplicate!".format(name))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        DomainIdentifier.__domain_list.append(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def name(self) -> str:
 | 
				
			||||||
 | 
					        return self.__name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def identifier(self) -> int:
 | 
				
			||||||
 | 
					        return self.__domain_number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def get_identifier(name: str) -> "DomainIdentifier":
 | 
				
			||||||
 | 
					        for d in DomainIdentifier.__domain_list:
 | 
				
			||||||
 | 
					            if d.name == name:
 | 
				
			||||||
 | 
					                return d
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DomainLinkGenerator:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, domain: DomainIdentifier):
 | 
				
			||||||
 | 
					        self.__identifier = domain
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def match_file_name(self, file_name) -> bool:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Checks if a given file name is plausible to be used by the given domain
 | 
				
			||||||
 | 
					        :param file_name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        raise NotImplementedError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_domain_name(self) -> str:
 | 
				
			||||||
 | 
					        return self.__identifier.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_identifier(self) -> int:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Return the Identifier for this Predictors domain.
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__identifier.identifier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def construct_link(self, file_name: str) -> str:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Construct a link by inserting the file_name into the known link pattern
 | 
				
			||||||
 | 
					        :param file_name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        raise NotImplementedError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def scrape_tags(self, url: str, headers: dict) -> list:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Scrape the tags from the given url for all tags associated with the work.
 | 
				
			||||||
 | 
					        :param url:
 | 
				
			||||||
 | 
					        :param headers:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        raise NotImplementedError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LinkGenerator:
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Predict and generate valid links to the file
 | 
				
			||||||
 | 
					    by matching the given file names against known patterns of the origin domain.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    __instance = None  # Singleton holder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.__link_generators = []
 | 
				
			||||||
 | 
					        import ArtNet.web.domains  # implements return_all_domains() which returns instances of all domains
 | 
				
			||||||
 | 
					        # return_all_domains() is to return a list of all DomainLinkGenerator instances that are to be used
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for p in ArtNet.web.domains.return_all_domains():
 | 
				
			||||||
 | 
					            self.register_domain_predictor(p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def get_instance() -> "LinkGenerator":
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Gets the current instance
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if LinkGenerator.__instance is None:
 | 
				
			||||||
 | 
					            LinkGenerator.__instance = LinkGenerator()
 | 
				
			||||||
 | 
					        return LinkGenerator.__instance
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def register_domain_predictor(self, predictor: DomainLinkGenerator):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Register another DomainValidator to be used by this LinkPredictor
 | 
				
			||||||
 | 
					        :param predictor:
 | 
				
			||||||
 | 
					        :param domain:  int identifier for the domain
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if predictor not in self.__link_generators:
 | 
				
			||||||
 | 
					            self.__link_generators.append(predictor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def predict_domain(self, file_name: str) -> int:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Predict the possible domains of the given file by guessing via the filename
 | 
				
			||||||
 | 
					        :param file_name:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        for g in self.__link_generators:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                if g.match_file_name(file_name):  # TODO stop accepting first match
 | 
				
			||||||
 | 
					                    return g.get_identifier()
 | 
				
			||||||
 | 
					            except NotImplementedError:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					        return DOMAIN_UNKNOWN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def construct_link(self, file_name: str, domain: int) -> str:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Construct a valid link to access the web page where the file name (hopefully) originated from.
 | 
				
			||||||
 | 
					        :param file_name:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        for g in self.__link_generators:
 | 
				
			||||||
 | 
					            if g.get_identifier() == domain:  # TODO stop accepting first match
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    return g.construct_link(file_name)
 | 
				
			||||||
 | 
					                except NotImplementedError:
 | 
				
			||||||
 | 
					                    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def scrape_tags(self, url: str, domain: int) -> dict:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Scrapes the tags from the given url
 | 
				
			||||||
 | 
					        :param url:
 | 
				
			||||||
 | 
					        :param domain:
 | 
				
			||||||
 | 
					        :return:
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        headers = {
 | 
				
			||||||
 | 
					            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:76.0) Gecko/20100101 Firefox/76.0"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        url_domain = urlparse(url).netloc
 | 
				
			||||||
 | 
					        for g in self.__link_generators:
 | 
				
			||||||
 | 
					            if g.get_identifier() == domain or g.get_domain_name() == url_domain:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    return g.scrape_tags(url, headers)
 | 
				
			||||||
 | 
					                except NotImplementedError:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					# ArtNet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ArtNet is a database schema to tag and organize images, videos and 
 | 
				
			||||||
 | 
					other media files for easy search & traceability.
 | 
				
			||||||
 | 
					Create your very own reference database!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Dependencies
 | 
				
			||||||
 | 
					The database schema has been developed with [PostgreSQL 13](https://www.postgresql.org/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The GUI runs with Python 3.9 as well as:
 | 
				
			||||||
 | 
					 * PyQT5
 | 
				
			||||||
 | 
					 * PyYAML
 | 
				
			||||||
 | 
					 * other dependencies listed in requirements.txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Editor GUI
 | 
				
			||||||
 | 
					The GUI allows easy editing, creation and deletion of tags, art entries,
 | 
				
			||||||
 | 
					presence entries and artists while viewing the file in question.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The GUI can connect to different databases via 
 | 
				
			||||||
 | 
					"ArtNet" > "Change DB Connection" .
 | 
				
			||||||
 | 
					The login credentials are saved in the directory `.artnet` 
 | 
				
			||||||
 | 
					located in the current working directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Important:** Configuration Encryption is experimental and **unsafe**! 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					While the GUI makes an attempt to encrypt the configuration
 | 
				
			||||||
 | 
					file, the password for encryption is, as of writing, inside the source code.
 | 
				
			||||||
 | 
					The login data should therefore to be treated as plain text and
 | 
				
			||||||
 | 
					additionally secured in better ways such as proper file permissions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Tagging
 | 
				
			||||||
 | 
					**You can:**
 | 
				
			||||||
 | 
					 * create, edit & delete your own tags
 | 
				
			||||||
 | 
					 * imply tags with other tags (e.g. *banana* implies *fruit*)
 | 
				
			||||||
 | 
					 * create aliases for different tags that mean the same (e.g. *posing* being an alias to *pose*)
 | 
				
			||||||
 | 
					 * categorize your tags
 | 
				
			||||||
 | 
					 * create modules to import tagging from known sources
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Concepts & Names
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### ArtNet Root
 | 
				
			||||||
 | 
					The root folder in which your references are stored. 
 | 
				
			||||||
 | 
					Ultimately the structure is up to you but it is assumed for 
 | 
				
			||||||
 | 
					new entries to be somewhat like this:
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					ArtNetRoot/
 | 
				
			||||||
 | 
					    presence_name_A/
 | 
				
			||||||
 | 
					        image_A.jpg
 | 
				
			||||||
 | 
					        vid_B.mp4
 | 
				
			||||||
 | 
					    presence_name_B/
 | 
				
			||||||
 | 
					        image_D.jpg
 | 
				
			||||||
 | 
					    presence_name_C/
 | 
				
			||||||
 | 
					        image_C.jpg
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					A structure like this will allow to the GUI to show a correct guess
 | 
				
			||||||
 | 
					for the presence name when encountering an unknown art entry.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Presences & Authors
 | 
				
			||||||
 | 
					In ArtNet you can create a presence for every account an artist
 | 
				
			||||||
 | 
					has on different or the same website. These presences are connected to
 | 
				
			||||||
 | 
					an Artist entry and therefore allow the connection of many accounts to the same artist.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A presence consists of the presence name and the domain it is used on as well as an 
 | 
				
			||||||
 | 
					optional direct link to the account.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Multiple presences can be associated with any given art allowing for correct
 | 
				
			||||||
 | 
					attribution for collaborations and similar.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- TODO add artist_presence_relation_example_diagram here --
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Art
 | 
				
			||||||
 | 
					Basically the files to be organized and tagged.
 | 
				
			||||||
 | 
					Each art piece is a file associated with many tags, a source link and
 | 
				
			||||||
 | 
					one or more presences.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Tag
 | 
				
			||||||
 | 
					A tag is keyword that is later to be associated with Art.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Aliases
 | 
				
			||||||
 | 
					Each tag can have aliases which are to be considered equal to
 | 
				
			||||||
 | 
					the current tag and therefore also associated with the art.
 | 
				
			||||||
 | 
					This relation is bidirectional.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Implications
 | 
				
			||||||
 | 
					Each tag can also imply other tags, meaning when
 | 
				
			||||||
 | 
					the current tag is associated with an art piece the implied tags
 | 
				
			||||||
 | 
					are to be considered associated too but not vice versa.
 | 
				
			||||||
 | 
					This relation is unidirectional.
 | 
				
			||||||
@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					from ArtNet.artnet_manager import ArtNetManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# TODO fix DB bug
 | 
				
			||||||
 | 
					# TODO 1. Open known image
 | 
				
			||||||
 | 
					# TODO 2. edit a tag on the current image & save the edit
 | 
				
			||||||
 | 
					# TODO 3. attempt to save the current image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    am = ArtNetManager()
 | 
				
			||||||
 | 
					    am.run()
 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue