Files

146 lines
5.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Tableau des extraits capturés, affiché dans le panneau latéral (voir
main_window.py) : de vraies colonnes/lignes avec un en-tête, plutôt qu'une
simple liste de texte.
Colonnes : Heure de capture, Titre, Aperçu du texte, et Lien — une icône
par ligne permettant de fusionner cet extrait avec le suivant en un seul
chapitre à l'export (voir models.group_into_chapters / pdf_builder.py).
"""
from __future__ import annotations
from PySide6.QtCore import Qt, Signal
from PySide6.QtWidgets import (
QAbstractItemView,
QHBoxLayout,
QHeaderView,
QTableWidget,
QTableWidgetItem,
QToolButton,
QWidget,
)
from .models import Clip, group_into_chapters
COL_TIME = 0
COL_TITLE = 1
COL_PREVIEW = 2
COL_LINK = 3
_LINKED_ICON = "🔗"
_UNLINKED_ICON = "➕"
class ClipTable(QTableWidget):
"""Tableau affichant les extraits capturés. Émet `renameRequested`
(double-clic sur une ligne, hors colonne Lien) et `linkToggled` (clic
sur l'icône de la colonne Lien) plutôt que d'exposer les détails Qt
du tableau — voir main_window.py pour les branchements."""
renameRequested = Signal(int)
linkToggled = Signal(int)
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(0, 4, parent)
self.setHorizontalHeaderLabels(["Heure", "Titre", "Aperçu", "Lien"])
self.verticalHeader().setVisible(False)
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
self.setAlternatingRowColors(True)
self.setShowGrid(False)
self.setToolTip(
"Double-cliquez sur un extrait pour le renommer.\n"
"Colonne Lien : 🔗 relie cet extrait au suivant pour former un "
"seul chapitre à l'export."
)
header = self.horizontalHeader()
header.setSectionResizeMode(COL_TIME, QHeaderView.ResizeMode.ResizeToContents)
header.setSectionResizeMode(COL_TITLE, QHeaderView.ResizeMode.Interactive)
header.setSectionResizeMode(COL_PREVIEW, QHeaderView.ResizeMode.Stretch)
header.setSectionResizeMode(COL_LINK, QHeaderView.ResizeMode.ResizeToContents)
self.setColumnWidth(COL_TITLE, 130)
self.cellDoubleClicked.connect(self._on_cell_double_clicked)
# ------------------------------------------------------------------ #
# API utilisée par main_window.py
# ------------------------------------------------------------------ #
def set_clips(self, clips: list[Clip]) -> None:
"""(Re)peuple le tableau, en préservant la ligne sélectionnée
quand son index reste valide (même logique que l'ancienne liste)."""
preserved_row = self.currentRow()
continuation_indices = {
index for chapter in group_into_chapters(clips) for index in chapter[1:]
}
self.setRowCount(len(clips))
last_index = len(clips) - 1
for index, clip in enumerate(clips):
prefix = "↳ " if index in continuation_indices else ""
self.setItem(index, COL_TIME, self._readonly_item(clip.captured_at.strftime("%H:%M")))
title_item = self._readonly_item(prefix + (clip.title or "Sans titre"))
title_item.setToolTip(clip.url)
self.setItem(index, COL_TITLE, title_item)
preview_item = self._readonly_item(clip.preview())
preview_item.setToolTip(clip.url)
self.setItem(index, COL_PREVIEW, preview_item)
if index == last_index:
link_item = self._readonly_item("")
link_item.setFlags(Qt.ItemFlag.NoItemFlags)
link_item.setToolTip("Dernier extrait : rien à lier après lui.")
self.setItem(index, COL_LINK, link_item)
else:
self.setCellWidget(index, COL_LINK, self._build_link_cell(index, clip.linked_to_next))
if 0 <= preserved_row < len(clips):
self.setCurrentCell(preserved_row, COL_TITLE)
def select_row(self, row: int) -> None:
self.setCurrentCell(row, COL_TITLE)
def clear_current(self) -> None:
self.setCurrentCell(-1, -1)
# ------------------------------------------------------------------ #
# Construction des cellules
# ------------------------------------------------------------------ #
@staticmethod
def _readonly_item(text: str) -> QTableWidgetItem:
item = QTableWidgetItem(text)
item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEditable)
return item
def _build_link_cell(self, index: int, linked: bool) -> QWidget:
button = QToolButton()
button.setAutoRaise(True)
button.setText(_LINKED_ICON if linked else _UNLINKED_ICON)
button.setToolTip(
"Extraits liés : forment un seul chapitre à l'export (un seul "
"titre, pas de saut de page entre eux).\nCliquer pour délier."
if linked
else "Lier cet extrait au suivant : ils formeront un seul "
"chapitre à l'export — utile quand un chapitre est réparti sur "
"plusieurs pages."
)
button.clicked.connect(lambda _checked=False, i=index: self.linkToggled.emit(i))
# Centré dans la cellule plutôt que collé à gauche (comportement
# par défaut de setCellWidget).
container = QWidget()
layout = QHBoxLayout(container)
layout.setContentsMargins(0, 0, 0, 0)
layout.addStretch(1)
layout.addWidget(button)
layout.addStretch(1)
return container
def _on_cell_double_clicked(self, row: int, column: int) -> None:
if column != COL_LINK:
self.renameRequested.emit(row)