Skip to content

Commit 5d85417

Browse files
authored
Merge pull request #151 from yedpodtrzitko/yed/libs-sidebar
add list of libraries into sidebar
2 parents f35d9c1 + 5d21375 commit 5d85417

3 files changed

Lines changed: 258 additions & 55 deletions

File tree

tagstudio/src/core/enums.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import enum
2+
3+
4+
class SettingItems(str, enum.Enum):
5+
"""List of setting item names."""
6+
7+
START_LOAD_LAST = "start_load_last"
8+
LAST_LIBRARY = "last_library"
9+
LIBS_LIST = "libs_list"
10+
WINDOW_SHOW_LIBS = "window_show_libs"
11+
12+
13+
class Theme(str, enum.Enum):
14+
COLOR_BG = "#65000000"
15+
COLOR_HOVER = "#65AAAAAA"
16+
COLOR_PRESSED = "#65EEEEEE"

tagstudio/src/qt/ts_qt.py

Lines changed: 101 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import webbrowser
1717
from datetime import datetime as dt
1818
from pathlib import Path
19-
from queue import Empty, Queue
19+
from queue import Queue
2020
from typing import Optional
2121

2222
from PIL import Image
@@ -46,6 +46,7 @@
4646
)
4747
from humanfriendly import format_timespan
4848

49+
from src.core.enums import SettingItems
4950
from src.core.library import ItemType
5051
from src.core.ts_core import (
5152
PLAINTEXT_TYPES,
@@ -88,7 +89,9 @@
8889
from src.qt.modals.fix_unlinked import FixUnlinkedEntriesModal
8990
from src.qt.modals.fix_dupes import FixDupeFilesModal
9091
from src.qt.modals.folders_to_tags import FoldersToTagsModal
91-
import src.qt.resources_rc
92+
93+
# this import has side-effect of import PySide resources
94+
import src.qt.resources_rc # pylint: disable=unused-import
9295

9396
# SIGQUIT is not defined on Windows
9497
if sys.platform == "win32":
@@ -282,6 +285,7 @@ def start(self):
282285
edit_menu = QMenu("&Edit", menu_bar)
283286
tools_menu = QMenu("&Tools", menu_bar)
284287
macros_menu = QMenu("&Macros", menu_bar)
288+
window_menu = QMenu("&Window", menu_bar)
285289
help_menu = QMenu("&Help", menu_bar)
286290

287291
# File Menu ============================================================
@@ -376,6 +380,18 @@ def start(self):
376380
tag_database_action.triggered.connect(lambda: self.show_tag_database())
377381
edit_menu.addAction(tag_database_action)
378382

383+
check_action = QAction("Open library on start", self)
384+
check_action.setCheckable(True)
385+
check_action.setChecked(
386+
self.settings.value(SettingItems.START_LOAD_LAST, True, type=bool)
387+
)
388+
check_action.triggered.connect(
389+
lambda checked: self.settings.setValue(
390+
SettingItems.START_LOAD_LAST, checked
391+
)
392+
)
393+
window_menu.addAction(check_action)
394+
379395
# Tools Menu ===========================================================
380396
fix_unlinked_entries_action = QAction("Fix &Unlinked Entries", menu_bar)
381397
fue_modal = FixUnlinkedEntriesModal(self.lib, self)
@@ -423,6 +439,20 @@ def start(self):
423439
macros_menu.addAction(self.sort_fields_action)
424440

425441
folders_to_tags_action = QAction("Create Tags From Folders", menu_bar)
442+
show_libs_list_action = QAction("Show Recent Libraries", menu_bar)
443+
show_libs_list_action.setCheckable(True)
444+
show_libs_list_action.setChecked(
445+
self.settings.value(SettingItems.WINDOW_SHOW_LIBS, True, type=bool)
446+
)
447+
show_libs_list_action.triggered.connect(
448+
lambda checked: (
449+
self.settings.setValue(SettingItems.WINDOW_SHOW_LIBS, checked),
450+
self.toggle_libs_list(checked),
451+
)
452+
)
453+
window_menu.addAction(show_libs_list_action)
454+
455+
folders_to_tags_action = QAction("Folders to Tags", menu_bar)
426456
ftt_modal = FoldersToTagsModal(self.lib, self)
427457
folders_to_tags_action.triggered.connect(lambda: ftt_modal.show())
428458
macros_menu.addAction(folders_to_tags_action)
@@ -440,6 +470,7 @@ def start(self):
440470
menu_bar.addMenu(edit_menu)
441471
menu_bar.addMenu(tools_menu)
442472
menu_bar.addMenu(macros_menu)
473+
menu_bar.addMenu(window_menu)
443474
menu_bar.addMenu(help_menu)
444475

445476
self.preview_panel = PreviewPanel(self.lib, self)
@@ -458,6 +489,31 @@ def start(self):
458489
self.thumb_renderers: list[ThumbRenderer] = []
459490
self.collation_thumb_size = math.ceil(self.thumb_size * 2)
460491

492+
self.init_library_window()
493+
494+
lib = None
495+
if self.args.open:
496+
lib = self.args.open
497+
elif self.settings.value(SettingItems.START_LOAD_LAST, True, type=bool):
498+
lib = self.settings.value(SettingItems.LAST_LIBRARY)
499+
500+
if lib:
501+
self.splash.showMessage(
502+
f'Opening Library "{lib}"...',
503+
int(Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter),
504+
QColor("#9782ff"),
505+
)
506+
self.open_library(lib)
507+
508+
if self.args.ci:
509+
# gracefully terminate the app in CI environment
510+
self.thumb_job_queue.put((self.SIGTERM.emit, []))
511+
512+
app.exec()
513+
514+
self.shutdown()
515+
516+
def init_library_window(self):
461517
self._init_thumb_grid()
462518

463519
# TODO: Put this into its own method that copies the font file(s) into memory
@@ -510,31 +566,12 @@ def start(self):
510566
self.splash.finish(self.main_window)
511567
self.preview_panel.update_widgets()
512568

513-
# Check if a library should be opened on startup, args should override last_library
514-
# TODO: check for behavior (open last, open default, start empty)
515-
if (
516-
self.args.open
517-
or self.settings.contains("last_library")
518-
and os.path.isdir(self.settings.value("last_library"))
519-
):
520-
if self.args.open:
521-
lib = self.args.open
522-
elif self.settings.value("last_library"):
523-
lib = self.settings.value("last_library")
524-
self.splash.showMessage(
525-
f'Opening Library "{lib}"...',
526-
int(Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter),
527-
QColor("#9782ff"),
528-
)
529-
self.open_library(lib)
530-
531-
if self.args.ci:
532-
# gracefully terminate the app in CI environment
533-
self.thumb_job_queue.put((self.SIGTERM.emit, []))
534-
535-
app.exec()
536-
537-
self.shutdown()
569+
def toggle_libs_list(self, value: bool):
570+
if value:
571+
self.preview_panel.libs_flow_container.show()
572+
else:
573+
self.preview_panel.libs_flow_container.hide()
574+
self.preview_panel.update()
538575

539576
def callback_library_needed_check(self, func):
540577
"""Check if loaded library has valid path before executing the button function"""
@@ -548,7 +585,7 @@ def shutdown(self):
548585
"""Save Library on Application Exit"""
549586
if self.lib.library_dir:
550587
self.save_library()
551-
self.settings.setValue("last_library", self.lib.library_dir)
588+
self.settings.setValue(SettingItems.LAST_LIBRARY, self.lib.library_dir)
552589
self.settings.sync()
553590
logging.info("[SHUTDOWN] Ending Thumbnail Threads...")
554591
for _ in self.thumb_threads:
@@ -597,7 +634,7 @@ def close_library(self):
597634
self.main_window.statusbar.showMessage(f"Closing & Saving Library...")
598635
start_time = time.time()
599636
self.save_library(show_status=False)
600-
self.settings.setValue("last_library", self.lib.library_dir)
637+
self.settings.setValue(SettingItems.LAST_LIBRARY, self.lib.library_dir)
601638
self.settings.sync()
602639

603640
self.lib.clear_internal_vars()
@@ -709,7 +746,7 @@ def add_new_files_callback(self):
709746
iterator.value.connect(lambda x: pw.update_progress(x + 1))
710747
iterator.value.connect(
711748
lambda x: pw.update_label(
712-
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'
749+
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'
713750
)
714751
)
715752
r = CustomRunnable(lambda: iterator.run())
@@ -760,7 +797,7 @@ def add_new_files_runnable(self):
760797
iterator.value.connect(lambda x: pw.update_progress(x + 1))
761798
iterator.value.connect(
762799
lambda x: pw.update_label(
763-
f"Running Configured Macros on {x+1}/{len(new_ids)} New Entries"
800+
f"Running Configured Macros on {x + 1}/{len(new_ids)} New Entries"
764801
)
765802
)
766803
r = CustomRunnable(lambda: iterator.run())
@@ -1297,6 +1334,38 @@ def filter_items(self, query=""):
12971334

12981335
# self.update_thumbs()
12991336

1337+
def remove_recent_library(self, item_key: str):
1338+
self.settings.beginGroup(SettingItems.LIBS_LIST)
1339+
self.settings.remove(item_key)
1340+
self.settings.endGroup()
1341+
self.settings.sync()
1342+
1343+
def update_libs_list(self, path: str | Path):
1344+
"""add library to list in SettingItems.LIBS_LIST"""
1345+
ITEMS_LIMIT = 5
1346+
path = Path(path)
1347+
1348+
self.settings.beginGroup(SettingItems.LIBS_LIST)
1349+
1350+
all_libs = {str(time.time()): str(path)}
1351+
1352+
for item_key in self.settings.allKeys():
1353+
item_path = self.settings.value(item_key)
1354+
if Path(item_path) != path:
1355+
all_libs[item_key] = item_path
1356+
1357+
# sort items, most recent first
1358+
all_libs = sorted(all_libs.items(), key=lambda item: item[0], reverse=True)
1359+
1360+
# remove previously saved items
1361+
self.settings.clear()
1362+
1363+
for item_key, item_value in all_libs[:ITEMS_LIMIT]:
1364+
self.settings.setValue(item_key, item_value)
1365+
1366+
self.settings.endGroup()
1367+
self.settings.sync()
1368+
13001369
def open_library(self, path):
13011370
"""Opens a TagStudio library."""
13021371
if self.lib.library_dir:
@@ -1314,7 +1383,7 @@ def open_library(self, path):
13141383
# self.lib.refresh_missing_files()
13151384
# title_text = f'{self.base_title} - Library \'{self.lib.library_dir}\''
13161385
# self.main_window.setWindowTitle(title_text)
1317-
pass
1386+
self.update_libs_list(path)
13181387

13191388
else:
13201389
logging.info(

0 commit comments

Comments
 (0)