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