feat: add "Disable all in" / "Enable all in" to playlist right-click menu

Folder-wide disable/enable is now reachable right next to the per-video
"Disable in" submenu, listing every subcategory in the profile (not just
ones tied to the loaded video). Backed by profile-wide subcategory counts
pushed to the playlist in _refresh_playlist_checks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 14:14:42 +02:00
parent d0a94e7b68
commit 68c633ab46
+36
View File
@@ -3182,6 +3182,7 @@ class PlaylistWidget(QListWidget):
self._filter_text = "" self._filter_text = ""
self._disabled_paths: set[str] = set() # videos with disabled clips → red self._disabled_paths: set[str] = set() # videos with disabled clips → red
self._folder_counts: dict[str, dict[str, int]] = {} # path → {folder: count} self._folder_counts: dict[str, dict[str, int]] = {} # path → {folder: count}
self._all_subcat_counts: dict[str, int] = {} # profile-wide folder → count
self._separators_before: set[str] = set() # paths that show a separator row above self._separators_before: set[str] = set() # paths that show a separator row above
self._visible: list[str | None] = [] # rows shown; None = separator row self._visible: list[str | None] = [] # rows shown; None = separator row
self._selected_path: str | None = None self._selected_path: str | None = None
@@ -3194,6 +3195,10 @@ class PlaylistWidget(QListWidget):
def set_folder_counts(self, counts: dict[str, dict[str, int]]) -> None: def set_folder_counts(self, counts: dict[str, dict[str, int]]) -> None:
self._folder_counts = counts self._folder_counts = counts
def set_all_subcat_counts(self, counts: dict[str, int]) -> None:
"""Profile-wide subcategory folder → clip count (incl. _disabled)."""
self._all_subcat_counts = counts
def set_filter(self, text: str) -> None: def set_filter(self, text: str) -> None:
self._filter_text = text.lower() self._filter_text = text.lower()
self._rebuild() self._rebuild()
@@ -3408,6 +3413,8 @@ class PlaylistWidget(QListWidget):
unhide_requested = pyqtSignal(list) # emits list of full paths to unhide unhide_requested = pyqtSignal(list) # emits list of full paths to unhide
disable_requested = pyqtSignal(str, str) # (video path, subcategory folder) disable_requested = pyqtSignal(str, str) # (video path, subcategory folder)
enable_requested = pyqtSignal(str, str) # (video path, disabled folder) enable_requested = pyqtSignal(str, str) # (video path, disabled folder)
disable_all_requested = pyqtSignal(str) # subcategory folder (all videos)
enable_all_requested = pyqtSignal(str) # subcategory folder (all videos)
separators_changed = pyqtSignal() # separator set was modified separators_changed = pyqtSignal() # separator set was modified
def _selected_paths(self) -> list[str]: def _selected_paths(self) -> list[str]:
@@ -3428,6 +3435,8 @@ class PlaylistWidget(QListWidget):
act_sep_above = act_sep_below = None act_sep_above = act_sep_below = None
disable_acts: dict = {} disable_acts: dict = {}
enable_acts: dict = {} enable_acts: dict = {}
disable_all_acts: dict = {}
enable_all_acts: dict = {}
if len(sel) == 1: if len(sel) == 1:
name = os.path.basename(sel[0]) name = os.path.basename(sel[0])
act_remove = menu.addAction(f"Remove: {name}") act_remove = menu.addAction(f"Remove: {name}")
@@ -3448,6 +3457,22 @@ class PlaylistWidget(QListWidget):
for f in disabled: for f in disabled:
base = f[:-len("_disabled")] base = f[:-len("_disabled")]
enable_acts[sub.addAction(f"{base} ({folders[f]})")] = f enable_acts[sub.addAction(f"{base} ({folders[f]})")] = f
# Disable / re-enable an entire subcategory across ALL videos.
all_active = sorted(f for f, c in self._all_subcat_counts.items()
if c and not f.endswith("_disabled"))
all_disabled = sorted(f for f, c in self._all_subcat_counts.items()
if c and f.endswith("_disabled"))
if all_active:
sub = menu.addMenu("Disable all in")
for f in all_active:
disable_all_acts[sub.addAction(
f"{f} ({self._all_subcat_counts[f]})")] = f
if all_disabled:
sub = menu.addMenu("Enable all in")
for f in all_disabled:
base = f[:-len("_disabled")]
enable_all_acts[sub.addAction(
f"{base} ({self._all_subcat_counts[f]})")] = base
menu.addSeparator() menu.addSeparator()
above_present = sel[0] in self._separators_before above_present = sel[0] in self._separators_before
act_sep_above = menu.addAction( act_sep_above = menu.addAction(
@@ -3510,6 +3535,10 @@ class PlaylistWidget(QListWidget):
self.disable_requested.emit(sel[0], disable_acts[chosen]) self.disable_requested.emit(sel[0], disable_acts[chosen])
elif chosen in enable_acts: elif chosen in enable_acts:
self.enable_requested.emit(sel[0], enable_acts[chosen]) self.enable_requested.emit(sel[0], enable_acts[chosen])
elif chosen in disable_all_acts:
self.disable_all_requested.emit(disable_all_acts[chosen])
elif chosen in enable_all_acts:
self.enable_all_requested.emit(enable_all_acts[chosen])
class _KeyFilter(QObject): class _KeyFilter(QObject):
@@ -4369,6 +4398,8 @@ class MainWindow(QMainWindow):
pw.unhide_requested.connect(self._on_unhide_files) pw.unhide_requested.connect(self._on_unhide_files)
pw.disable_requested.connect(self._on_disable_video) pw.disable_requested.connect(self._on_disable_video)
pw.enable_requested.connect(self._on_enable_video) pw.enable_requested.connect(self._on_enable_video)
pw.disable_all_requested.connect(self._disable_all_in_folder)
pw.enable_all_requested.connect(self._enable_all_in_folder)
pw.separators_changed.connect(self._save_playlist_tabs) pw.separators_changed.connect(self._save_playlist_tabs)
if label is None: if label is None:
label = f"List {self._playlist_tabs.count() + 1}" label = f"List {self._playlist_tabs.count() + 1}"
@@ -4824,6 +4855,11 @@ class MainWindow(QMainWindow):
self._playlist.unmark_done(path) self._playlist.unmark_done(path)
self._playlist.set_folder_counts(folder_counts) self._playlist.set_folder_counts(folder_counts)
self._playlist.set_disabled_paths(disabled_paths) self._playlist.set_disabled_paths(disabled_paths)
# Profile-wide subcategory counts (exclude the main export folder).
base = os.path.basename(self._txt_folder.text())
all_counts = {f: c for f, c in self._db.get_all_folder_counts(profile).items()
if f != base}
self._playlist.set_all_subcat_counts(all_counts)
def _on_delete_marker(self, output_path: str) -> None: def _on_delete_marker(self, output_path: str) -> None:
deleted = self._db.delete_group(output_path) deleted = self._db.delete_group(output_path)