mirror of
https://github.com/TagStudioDev/TagStudio.git
synced 2026-01-29 14:20:48 +00:00
Added Proper Visualls to show what would be added
This commit is contained in:
@@ -33,7 +33,7 @@ from PySide6.QtUiTools import QUiLoader
|
||||
from PySide6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QPlainTextEdit,
|
||||
QLineEdit, QScrollArea, QFrame, QTextEdit, QComboBox, QProgressDialog, QFileDialog,
|
||||
QListView, QSplitter, QSizePolicy, QMessageBox, QBoxLayout, QCheckBox, QSplashScreen,
|
||||
QMenu)
|
||||
QMenu,QTreeWidget, QTreeWidgetItem)
|
||||
from humanfriendly import format_timespan, format_size
|
||||
|
||||
from src.core.library import Collation, Entry, ItemType, Library, Tag
|
||||
@@ -3897,10 +3897,6 @@ class QtDriver(QObject):
|
||||
create_collage_action = QAction('Create Collage', menu_bar)
|
||||
create_collage_action.triggered.connect(lambda: self.create_collage())
|
||||
tools_menu.addAction(create_collage_action)
|
||||
|
||||
folders_to_tags_action = QAction('Folders to Tags', menu_bar)
|
||||
folders_to_tags_action.triggered.connect(lambda: self.folders_to_tags(self.lib))
|
||||
tools_menu.addAction(folders_to_tags_action)
|
||||
|
||||
# Macros Menu ==========================================================
|
||||
self.autofill_action = QAction('Autofill', menu_bar)
|
||||
@@ -3913,6 +3909,11 @@ class QtDriver(QObject):
|
||||
self.sort_fields_action.setToolTip('Alt+S')
|
||||
macros_menu.addAction(self.sort_fields_action)
|
||||
|
||||
folders_to_tags_action = QAction('Folders to Tags', menu_bar)
|
||||
ftt_modal = FoldersToTagsModal(self.lib, self)
|
||||
folders_to_tags_action.triggered.connect(lambda:ftt_modal.show())
|
||||
macros_menu.addAction(folders_to_tags_action)
|
||||
|
||||
self.set_macro_menu_viability()
|
||||
|
||||
menu_bar.addMenu(file_menu)
|
||||
@@ -4739,52 +4740,6 @@ class QtDriver(QObject):
|
||||
)))
|
||||
i = i+1
|
||||
|
||||
def folders_to_tags(self,library:Library):
|
||||
logging.info("Converting folders to Tags")
|
||||
tree = dict(dirs={})
|
||||
|
||||
def add_tag_to_tree(list:list[Tag]):
|
||||
branch = tree
|
||||
for tag in list:
|
||||
if tag.name not in branch["dirs"]:
|
||||
branch["dirs"][tag.name] = dict(dirs={},tag=tag)
|
||||
branch = branch["dirs"][tag.name]
|
||||
|
||||
def add_folders_to_tree(list:list[str])->Tag:
|
||||
branch = tree
|
||||
for folder in list:
|
||||
if folder not in branch["dirs"]:
|
||||
new_tag = Tag(-1, folder,"",[],([branch["tag"].id] if "tag" in branch else []),"black")
|
||||
library.add_tag_to_library(new_tag)
|
||||
branch["dirs"][folder] = dict(dirs={},tag=new_tag)
|
||||
branch = branch["dirs"][folder]
|
||||
return branch["tag"]
|
||||
|
||||
def reverse_tag(tag:Tag,list:list[Tag]):
|
||||
if list != None:
|
||||
list.append(tag)
|
||||
else:
|
||||
list = [tag]
|
||||
|
||||
if len(tag.subtag_ids) == 0:
|
||||
add_tag_to_tree(list)
|
||||
else:
|
||||
for subtag_id in tag.subtag_ids:
|
||||
subtag = library.get_tag(subtag_id)
|
||||
reverse_tag(subtag,list)
|
||||
|
||||
for tag in library.tags:
|
||||
reverse_tag(tag,None)
|
||||
|
||||
for entry in library.entries:
|
||||
folders = entry.path.split("\\")
|
||||
tag = add_folders_to_tree(folders)
|
||||
if tag:
|
||||
if not entry.has_tag(library,tag.id):
|
||||
entry.add_tag(library,tag.id,6)
|
||||
|
||||
logging.info("Done")
|
||||
|
||||
def try_save_collage(self, increment_progress:bool):
|
||||
if increment_progress:
|
||||
self.completed += 1
|
||||
@@ -4797,3 +4752,258 @@ class QtDriver(QObject):
|
||||
end_time = time.time()
|
||||
self.main_window.statusbar.showMessage(f'Collage Saved at "{filename}" ({format_timespan(end_time - self.collage_start_time)})')
|
||||
logging.info(f'Collage Saved at "{filename}" ({format_timespan(end_time - self.collage_start_time)})')
|
||||
|
||||
class FoldersToTagsModal(QWidget):
|
||||
# done = Signal(int)
|
||||
def __init__(self, library:'Library', driver:'QtDriver'):
|
||||
super().__init__()
|
||||
self.library = library
|
||||
self.driver:QtDriver = driver
|
||||
self.count = -1
|
||||
self.filename = ''
|
||||
|
||||
self.setWindowTitle(f'Folders To Tags')
|
||||
self.setWindowModality(Qt.WindowModality.ApplicationModal)
|
||||
self.setMinimumSize(500, 800)
|
||||
self.root_layout = QVBoxLayout(self)
|
||||
self.root_layout.setContentsMargins(6,6,6,6)
|
||||
|
||||
self.desc_widget = QLabel()
|
||||
self.desc_widget.setObjectName('descriptionLabel')
|
||||
self.desc_widget.setWordWrap(True)
|
||||
self.desc_widget.setStyleSheet(
|
||||
# 'background:blue;'
|
||||
'text-align:left;'
|
||||
# 'font-weight:bold;'
|
||||
'font-size:18px;'
|
||||
# 'padding-top: 6px'
|
||||
'')
|
||||
self.desc_widget.setText('''Creates tags based on the folder structure and applies them to entries.\n The Structure below shows all the tags that would be added and to which files they would be added. It being empty means that there are no Tag to be created or assigned''')
|
||||
self.desc_widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.scroll_contents = QWidget()
|
||||
self.scroll_layout = QVBoxLayout(self.scroll_contents)
|
||||
self.scroll_layout.setContentsMargins(6,0,6,0)
|
||||
self.scroll_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
|
||||
|
||||
self.scroll_area = QScrollArea()
|
||||
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
|
||||
self.scroll_area.setWidgetResizable(True)
|
||||
self.scroll_area.setFrameShadow(QFrame.Shadow.Plain)
|
||||
self.scroll_area.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.scroll_area.setWidget(self.scroll_contents)
|
||||
|
||||
self.Apply_button = QPushButton()
|
||||
self.Apply_button.setText('&Apply')
|
||||
self.Apply_button.clicked.connect(lambda: self.folders_to_tags(self.library))
|
||||
|
||||
self.showEvent = self.on_open
|
||||
|
||||
self.root_layout.addWidget(self.desc_widget)
|
||||
self.root_layout.addWidget(self.scroll_area)
|
||||
self.root_layout.addWidget(self.Apply_button)
|
||||
|
||||
def on_open(self,event):
|
||||
for i in reversed(range(self.scroll_layout.count())):
|
||||
self.scroll_layout.itemAt(i).widget().setParent(None)
|
||||
|
||||
data = self.generate_preview_data(self.library)
|
||||
|
||||
for folder in data["dirs"].values():
|
||||
test = self.TreeItemTest(folder,None)
|
||||
self.scroll_layout.addWidget(test)
|
||||
|
||||
|
||||
def generate_preview_data(self,library:Library):
|
||||
tree = dict(dirs={},files=[])
|
||||
|
||||
def add_tag_to_tree(list:list[Tag]):
|
||||
branch = tree
|
||||
for tag in list:
|
||||
if tag.name not in branch["dirs"]:
|
||||
branch["dirs"][tag.name] = dict(dirs={},tag=tag,files=[])
|
||||
branch = branch["dirs"][tag.name]
|
||||
|
||||
def add_folders_to_tree(list:list[str])->Tag:
|
||||
branch = tree
|
||||
for folder in list:
|
||||
if folder not in branch["dirs"]:
|
||||
new_tag = Tag(-1, folder,"",[],[],"green")
|
||||
branch["dirs"][folder] = dict(dirs={},tag=new_tag,files=[])
|
||||
branch = branch["dirs"][folder]
|
||||
return branch
|
||||
|
||||
for tag in library.tags:
|
||||
reversed_tag = self.reverse_tag(tag,None)
|
||||
logging.info(set(map(lambda tag:tag.name ,reversed_tag)))
|
||||
add_tag_to_tree(reversed_tag)
|
||||
|
||||
for entry in library.entries:
|
||||
folders = entry.path.split("\\")
|
||||
if len(folders) == 1 and folders[0] == "": continue
|
||||
branch = add_folders_to_tree(folders)
|
||||
if branch:
|
||||
field_indexes = library.get_field_index_in_entry(entry,6)
|
||||
has_tag=False
|
||||
for index in field_indexes:
|
||||
content = library.get_field_attr(entry.fields[index],"content")
|
||||
for tag_id in content:
|
||||
tag = library.get_tag(tag_id)
|
||||
if tag.name == branch["tag"].name:
|
||||
has_tag=True
|
||||
break
|
||||
if not has_tag:
|
||||
branch["files"].append(entry.filename)
|
||||
|
||||
def cut_branches_adding_nothing(branch:dict):
|
||||
folders = set(branch["dirs"].keys())
|
||||
for folder in folders:
|
||||
logging.info(folder)
|
||||
cut = cut_branches_adding_nothing(branch["dirs"][folder])
|
||||
if cut:
|
||||
branch['dirs'].pop(folder)
|
||||
|
||||
if not "tag" in branch: return
|
||||
if branch["tag"].id == -1:#Needs to be first
|
||||
return False
|
||||
if len(branch["dirs"].keys()) == 0:
|
||||
return True
|
||||
|
||||
|
||||
cut_branches_adding_nothing(tree)
|
||||
|
||||
return tree
|
||||
|
||||
def folders_to_tags(self,library:Library):
|
||||
logging.info("Converting folders to Tags")
|
||||
tree = dict(dirs={})
|
||||
def add_tag_to_tree(list:list[Tag]):
|
||||
branch = tree
|
||||
for tag in list:
|
||||
if tag.name not in branch["dirs"]:
|
||||
branch["dirs"][tag.name] = dict(dirs={},tag=tag)
|
||||
branch = branch["dirs"][tag.name]
|
||||
|
||||
def add_folders_to_tree(list:list[str])->Tag:
|
||||
branch = tree
|
||||
for folder in list:
|
||||
if folder not in branch["dirs"]:
|
||||
new_tag = Tag(-1, folder,"",[],([branch["tag"].id] if "tag" in branch else []),"")
|
||||
library.add_tag_to_library(new_tag)
|
||||
branch["dirs"][folder] = dict(dirs={},tag=new_tag)
|
||||
branch = branch["dirs"][folder]
|
||||
return branch["tag"]
|
||||
|
||||
|
||||
for tag in library.tags:
|
||||
reversed_tag = self.reverse_tag(tag,None)
|
||||
add_tag_to_tree(reversed_tag)
|
||||
|
||||
for entry in library.entries:
|
||||
folders = entry.path.split("\\")
|
||||
if len(folders)== 1 and folders[0]=="": continue
|
||||
tag = add_folders_to_tree(folders)
|
||||
if tag:
|
||||
if not entry.has_tag(library,tag.id):
|
||||
entry.add_tag(library,tag.id,6)
|
||||
|
||||
self.close()
|
||||
|
||||
logging.info("Done")
|
||||
|
||||
def reverse_tag(self,tag:Tag,list:list[Tag]) -> list[Tag]:
|
||||
if list != None:
|
||||
list.append(tag)
|
||||
else:
|
||||
list = [tag]
|
||||
|
||||
if len(tag.subtag_ids) == 0:
|
||||
list.reverse()
|
||||
return list
|
||||
else:
|
||||
for subtag_id in tag.subtag_ids:
|
||||
subtag = self.library.get_tag(subtag_id)
|
||||
return self.reverse_tag(subtag,list)
|
||||
|
||||
class ModifiedTagWidget(QWidget): # Needed to be modified because the original searched the display name in the library where it wasn't added yet
|
||||
def __init__(self, tag:Tag,parentTag:Tag) -> None:
|
||||
super().__init__()
|
||||
self.tag = tag
|
||||
|
||||
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
self.base_layout = QVBoxLayout(self)
|
||||
self.base_layout.setObjectName('baseLayout')
|
||||
self.base_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.bg_button = QPushButton(self)
|
||||
self.bg_button.setFlat(True)
|
||||
if parentTag != None:
|
||||
text = f"{tag.name} ({parentTag.name})".replace('&', '&&')
|
||||
else:
|
||||
text = tag.name.replace('&', '&&')
|
||||
self.bg_button.setText(text)
|
||||
self.bg_button.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)
|
||||
|
||||
self.inner_layout = QHBoxLayout()
|
||||
self.inner_layout.setObjectName('innerLayout')
|
||||
self.inner_layout.setContentsMargins(2, 2, 2, 2)
|
||||
self.bg_button.setLayout(self.inner_layout)
|
||||
self.bg_button.setMinimumSize(math.ceil(22*1.5), 22)
|
||||
|
||||
self.bg_button.setStyleSheet(
|
||||
f'QPushButton{{'
|
||||
f'background: {get_tag_color(ColorType.PRIMARY, tag.color)};'
|
||||
f"color: {get_tag_color(ColorType.TEXT, tag.color)};"
|
||||
f'font-weight: 600;'
|
||||
f"border-color:{get_tag_color(ColorType.BORDER, tag.color)};"
|
||||
f'border-radius: 6px;'
|
||||
f'border-style:inset;'
|
||||
f'border-width: {math.ceil(1*self.devicePixelRatio())}px;'
|
||||
f'padding-right: 4px;'
|
||||
f'padding-bottom: 1px;'
|
||||
f'padding-left: 4px;'
|
||||
f'font-size: 13px'
|
||||
f'}}'
|
||||
f'QPushButton::hover{{'
|
||||
f"border-color:{get_tag_color(ColorType.LIGHT_ACCENT, tag.color)};"
|
||||
f'}}')
|
||||
|
||||
self.base_layout.addWidget(self.bg_button)
|
||||
self.setMinimumSize(50,20)
|
||||
class TreeItemTest(QWidget):
|
||||
def __init__(self,data:dict,parentTag:Tag):
|
||||
super().__init__()
|
||||
|
||||
self.root_layout = QVBoxLayout(self)
|
||||
self.root_layout.setContentsMargins(20,0,0,0)
|
||||
self.root_layout.setSpacing(1)
|
||||
|
||||
self.test = QWidget()
|
||||
self.root_layout.addWidget(self.test)
|
||||
|
||||
self.tag_layout = FlowLayout(self.test)
|
||||
|
||||
self.tag_widget = FoldersToTagsModal.ModifiedTagWidget(data["tag"],parentTag)
|
||||
self.tag_widget.bg_button.clicked.connect(lambda:self.hide_show())
|
||||
self.tag_layout.addWidget(self.tag_widget)
|
||||
|
||||
self.children_widget = QWidget()
|
||||
self.children_layout = QVBoxLayout(self.children_widget)
|
||||
self.root_layout.addWidget(self.children_widget)
|
||||
|
||||
self.populate(data)
|
||||
|
||||
def hide_show(self):
|
||||
self.children_widget.setHidden(not self.children_widget.isHidden())
|
||||
|
||||
def populate(self,data:dict):
|
||||
for folder in data["dirs"].values():
|
||||
item = FoldersToTagsModal.TreeItemTest(folder,data["tag"])
|
||||
self.children_layout.addWidget(item)
|
||||
for file in data["files"]:
|
||||
label = QLabel()
|
||||
label.setText(file)
|
||||
self.children_layout.addWidget(label)
|
||||
|
||||
if len(data["files"]) == 0 and len(data["dirs"].values()) == 0:
|
||||
self.hide_show()
|
||||
Reference in New Issue
Block a user