Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use list of libraries as a starting point #127

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
142 changes: 108 additions & 34 deletions tagstudio/src/qt/ts_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,22 @@
"""A Qt driver for TagStudio."""

import ctypes
import enum
import logging
import math
import os
import sys
import time
import webbrowser
from datetime import datetime as dt
from hashlib import sha1
from pathlib import Path
from queue import Empty, Queue
from typing import Optional

from PIL import Image
from PySide6 import QtCore
from PySide6.QtCore import QObject, QThread, Signal, Qt, QThreadPool, QTimer, QSettings
from PySide6.QtCore import QObject, QThread, Signal, Qt, QThreadPool, QSettings
from PySide6.QtGui import (
QGuiApplication,
QPixmap,
Expand All @@ -42,6 +44,8 @@
QFileDialog,
QSplashScreen,
QMenu,
QLabel,
QVBoxLayout,
)
from humanfriendly import format_timespan

Expand Down Expand Up @@ -110,6 +114,14 @@
QSettings.setPath(QSettings.IniFormat, QSettings.UserScope, os.getcwd())


class SettingItems(str, enum.Enum):
"""List of setting item names."""

START_SHOW_LIBS = "start_show_libs"
LAST_LIBRARY = "last_library"
LIBS_LIST = "libs_list"


class NavigationState:
"""Represents a state of the Library grid view."""

Expand Down Expand Up @@ -173,9 +185,6 @@ def __init__(self, core, args):
self.lib = self.core.lib
self.args = args

# self.main_window = None
# self.main_window = Ui_MainWindow()

self.branch: str = (" (" + VERSION_BRANCH + ")") if VERSION_BRANCH else ""
self.base_title: str = f"TagStudio {VERSION}{self.branch}"
# self.title_text: str = self.base_title
Expand All @@ -192,6 +201,9 @@ def __init__(self, core, args):
QSettings.IniFormat, QSettings.UserScope, "tagstudio", "TagStudio"
)

# flag for whether the library window has been initialized already
self._lib_window_init = False

max_threads = os.cpu_count()
for i in range(max_threads):
# thread = threading.Thread(target=self.consumer, name=f'ThumbRenderer_{i}',args=(), daemon=True)
Expand Down Expand Up @@ -238,9 +250,6 @@ def start(self):

# Handle OS signals
self.setup_signals()
timer = QTimer()
timer.start(500)
timer.timeout.connect(lambda: None)

# self.main_window = loader.load(home_path)
self.main_window = Ui_MainWindow()
Expand Down Expand Up @@ -366,6 +375,18 @@ def start(self):
tag_database_action.triggered.connect(lambda: self.show_tag_database())
edit_menu.addAction(tag_database_action)

check_action = QAction("List Libraries on Start", self)
check_action.setCheckable(True)
check_action.setChecked(
self.settings.value(SettingItems.START_SHOW_LIBS, False, type=bool)
)
check_action.triggered.connect(
lambda checked: self.settings.setValue(
SettingItems.START_SHOW_LIBS, checked
)
)
edit_menu.addAction(check_action)

# Tools Menu ===========================================================
fix_unlinked_entries_action = QAction("Fix &Unlinked Entries", menu_bar)
fue_modal = FixUnlinkedEntriesModal(self.lib, self)
Expand Down Expand Up @@ -465,6 +486,72 @@ def start(self):
self.collation_thumb_size = math.ceil(self.thumb_size * 2)
# self.filtered_items: list[tuple[SearchItemType, int]] = []

if self.args.open:
self.open_library(self.args.open)
elif self.settings.value(SettingItems.START_SHOW_LIBS, type=bool):
self.settings.beginGroup(SettingItems.LIBS_LIST)
lib_items = {x: self.settings.value(x) for x in self.settings.allKeys()}
if lib_items:
self.settings.endGroup()
self.list_libraries_panel(lib_items)
else:
self.init_library_window()
elif lib := self.settings.value(SettingItems.LAST_LIBRARY):
self.splash.showMessage(
f'Opening Library "{lib}"...',
int(Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter),
QColor("#9782ff"),
)
self.open_library(lib)
else:
self.init_library_window()

app.exec_()

self.shutdown()

def list_libraries_panel(self, libraries: dict[str, str]):
layout = QVBoxLayout()

label = QLabel("Select a library")
label.setFixedHeight(50)
label.setAlignment(Qt.AlignCenter)
layout.addWidget(label)

for lib_key, lib_path in libraries.items():
button = QPushButton(text=lib_path)
button.setObjectName(lib_key)

def open_library_button_clicked(path):
return lambda: self.open_library(path)

button.clicked.connect(open_library_button_clicked(lib_path))
button.setStyleSheet(
"background-color: #ffffff; color: #000000; text-align: left; padding-left: 30px;"
)
button.setFixedHeight(50)
layout.addWidget(button)

# add empty label to fill remaining space
spacer = QLabel()
layout.addWidget(spacer)

flow_container: QWidget = QWidget()
flow_container.setObjectName("flowContainer")
flow_container.setLayout(layout)

sa: QScrollArea = self.main_window.scrollArea
sa.setWidget(flow_container)

self.main_window.show()
self.main_window.activateWindow()
self.splash.finish(self.main_window)

def init_library_window(self):
if self._lib_window_init:
return

self._lib_window_init = True
self._init_thumb_grid()

# TODO: Put this into its own method that copies the font file(s) into memory
Expand Down Expand Up @@ -518,26 +605,6 @@ def start(self):
self.preview_panel.update_widgets()

# Check if a library should be opened on startup, args should override last_library
# TODO: check for behavior (open last, open default, start empty)
if (
self.args.open
or self.settings.contains("last_library")
and os.path.isdir(self.settings.value("last_library"))
):
if self.args.open:
lib = self.args.open
elif self.settings.value("last_library"):
lib = self.settings.value("last_library")
self.splash.showMessage(
f'Opening Library "{lib}"...',
int(Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter),
QColor("#9782ff"),
)
self.open_library(lib)

app.exec_()

self.shutdown()

def callback_library_needed_check(self, func):
"""Check if loaded library has valid path before executing the button function"""
Expand All @@ -551,7 +618,7 @@ def shutdown(self):
"""Save Library on Application Exit"""
if self.lib.library_dir:
self.save_library()
self.settings.setValue("last_library", self.lib.library_dir)
self.settings.setValue(SettingItems.LAST_LIBRARY, self.lib.library_dir)
self.settings.sync()
logging.info("[SHUTDOWN] Ending Thumbnail Threads...")
for _ in self.thumb_threads:
Expand Down Expand Up @@ -600,7 +667,7 @@ def close_library(self):
self.main_window.statusbar.showMessage(f"Closing & Saving Library...")
start_time = time.time()
self.save_library(show_status=False)
self.settings.setValue("last_library", self.lib.library_dir)
self.settings.setValue(SettingItems.LAST_LIBRARY, self.lib.library_dir)
self.settings.sync()

self.lib.clear_internal_vars()
Expand Down Expand Up @@ -712,7 +779,7 @@ def add_new_files_callback(self):
iterator.value.connect(lambda x: pw.update_progress(x + 1))
iterator.value.connect(
lambda x: pw.update_label(
f'Scanning Directories for New Files...\n{x+1} File{"s" if x+1 != 1 else ""} Searched, {len(self.lib.files_not_in_library)} New Files Found'
f'Scanning Directories for New Files...\n{x + 1} File{"s" if x + 1 != 1 else ""} Searched, {len(self.lib.files_not_in_library)} New Files Found'
)
)
r = CustomRunnable(lambda: iterator.run())
Expand Down Expand Up @@ -763,7 +830,7 @@ def add_new_files_runnable(self):
iterator.value.connect(lambda x: pw.update_progress(x + 1))
iterator.value.connect(
lambda x: pw.update_label(
f"Running Configured Macros on {x+1}/{len(new_ids)} New Entries"
f"Running Configured Macros on {x + 1}/{len(new_ids)} New Entries"
)
)
r = CustomRunnable(lambda: iterator.run())
Expand Down Expand Up @@ -1296,12 +1363,17 @@ def filter_items(self, query=""):
self.main_window.statusbar.showMessage(
f"{len(all_items)} Results ({format_timespan(end_time - start_time)})"
)
# logging.info(f'Done Filtering! ({(end_time - start_time):.3f}) seconds')

# self.update_thumbs()
def update_libs_list(self, library_path: str):
self.settings.beginGroup(SettingItems.LIBS_LIST)
path_hash = sha1(library_path.encode("utf-8")).hexdigest()
self.settings.setValue(path_hash, library_path)
self.settings.endGroup()

def open_library(self, path):
def open_library(self, path: str):
"""Opens a TagStudio library."""
self.init_library_window()

if self.lib.library_dir:
self.save_library()
self.lib.clear_internal_vars()
Expand All @@ -1326,6 +1398,8 @@ def open_library(self, path):
print(f"Library Creation Return Code: {self.lib.create_library(path)}")
self.add_new_files_callback()

self.update_libs_list(path)

title_text = f"{self.base_title} - Library '{self.lib.library_dir}'"
self.main_window.setWindowTitle(title_text)

Expand Down