"""Fenetre principale de Copydev Imposing Tool.""" import os import tempfile from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFileDialog, QMessageBox, QGroupBox, QStatusBar, QMenuBar, QSplitter, QProgressBar) from PyQt6.QtCore import Qt from PyQt6.QtGui import QAction from app.pdf_viewer import PdfViewer from app.dialogs.booklet_dialog import BookletDialog from app.dialogs.nup_dialog import NupDialog from app.dialogs.step_repeat_dialog import StepRepeatDialog from app.dialogs.manual_impose_dialog import ManualImposeDialog from app.dialogs.join_pages_dialog import JoinPagesDialog from app.dialogs.insert_blank_dialog import InsertBlankDialog from app.dialogs.page_numbers_dialog import PageNumbersDialog from app.dialogs.masking_dialog import MaskingDialog from app.dialogs.bleeds_dialog import BleedsDialog from app.engine.booklet import create_booklet from app.engine.nup import nup_pages from app.engine.step_repeat import step_and_repeat from app.engine.manual_impose import manual_impose from app.engine.join_pages import join_pages from app.engine.insert_blank import insert_blank_pages from app.engine.page_numbers import add_page_numbers from app.engine.masking import apply_masking from app.engine.bleeds import define_bleeds class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Copydev Imposing Tool") self.setMinimumSize(1000, 700) # Icone de la fenetre import sys as _sys from PyQt6.QtGui import QIcon _base = _sys._MEIPASS if getattr(_sys, 'frozen', False) else os.path.dirname(os.path.dirname(os.path.abspath(__file__))) icon_path = os.path.join(_base, "resources", "logo.png") if os.path.exists(icon_path): self.setWindowIcon(QIcon(icon_path)) self._current_file = None self._result_file = None self._setup_menu() self._setup_ui() self._setup_statusbar() def _setup_menu(self): menubar = self.menuBar() # Menu Fichier file_menu = menubar.addMenu("Fichier") open_act = QAction("Ouvrir PDF...", self) open_act.setShortcut("Ctrl+O") open_act.triggered.connect(self._open_file) file_menu.addAction(open_act) save_act = QAction("Enregistrer le resultat...", self) save_act.setShortcut("Ctrl+S") save_act.triggered.connect(self._save_result) file_menu.addAction(save_act) file_menu.addSeparator() quit_act = QAction("Quitter", self) quit_act.setShortcut("Ctrl+Q") quit_act.triggered.connect(self.close) file_menu.addAction(quit_act) # Menu Aide help_menu = menubar.addMenu("Aide") about_act = QAction("A propos...", self) about_act.triggered.connect(self._show_about) help_menu.addAction(about_act) def _setup_ui(self): central = QWidget() self.setCentralWidget(central) main_layout = QHBoxLayout(central) # === Panneau gauche : boutons === left_panel = QWidget() left_panel.setFixedWidth(200) left_layout = QVBoxLayout(left_panel) left_layout.setContentsMargins(5, 5, 5, 5) # Ouvrir btn_open = QPushButton("Ouvrir PDF...") btn_open.clicked.connect(self._open_file) left_layout.addWidget(btn_open) btn_save = QPushButton("Enregistrer resultat...") btn_save.clicked.connect(self._save_result) left_layout.addWidget(btn_save) left_layout.addSpacing(10) # Imposition grp_impose = QGroupBox("Imposition") il = QVBoxLayout(grp_impose) btn_booklet = QPushButton("Creer un livret") btn_booklet.clicked.connect(self._do_booklet) il.addWidget(btn_booklet) btn_nup = QPushButton("N pages par feuille") btn_nup.clicked.connect(self._do_nup) il.addWidget(btn_nup) btn_repeat = QPushButton("Repetition") btn_repeat.clicked.connect(self._do_step_repeat) il.addWidget(btn_repeat) btn_manual = QPushButton("Imposition manuelle") btn_manual.clicked.connect(self._do_manual_impose) il.addWidget(btn_manual) btn_join = QPushButton("Joindre deux pages") btn_join.clicked.connect(self._do_join_pages) il.addWidget(btn_join) left_layout.addWidget(grp_impose) # Pages grp_pages = QGroupBox("Pages") pl = QVBoxLayout(grp_pages) btn_blank = QPushButton("Pages blanches") btn_blank.clicked.connect(self._do_insert_blank) pl.addWidget(btn_blank) left_layout.addWidget(grp_pages) # Annotations grp_annot = QGroupBox("Annotations") al = QVBoxLayout(grp_annot) btn_numbers = QPushButton("Numerotation") btn_numbers.clicked.connect(self._do_page_numbers) al.addWidget(btn_numbers) btn_mask = QPushButton("Masquage") btn_mask.clicked.connect(self._do_masking) al.addWidget(btn_mask) btn_bleeds = QPushButton("Fonds perdus") btn_bleeds.clicked.connect(self._do_bleeds) al.addWidget(btn_bleeds) left_layout.addWidget(grp_annot) left_layout.addStretch() main_layout.addWidget(left_panel) # === Zone centrale : viewer PDF === self._viewer = PdfViewer() self._viewer.page_changed.connect(self._on_page_changed) main_layout.addWidget(self._viewer, 1) def _setup_statusbar(self): self._statusbar = QStatusBar() self.setStatusBar(self._statusbar) self._status_label = QLabel("Pret") self._statusbar.addWidget(self._status_label, 1) self._file_label = QLabel("") self._statusbar.addPermanentWidget(self._file_label) def _on_page_changed(self, page, total): pass def _open_file(self): path, _ = QFileDialog.getOpenFileName( self, "Ouvrir un fichier PDF", "", "PDF (*.pdf)" ) if path: self._current_file = path self._result_file = None self._viewer.load_pdf(path) self._file_label.setText(os.path.basename(path)) self._status_label.setText(f"Fichier charge : {os.path.basename(path)}") def _save_result(self): source = self._result_file or self._current_file if not source: QMessageBox.warning(self, "Erreur", "Aucun fichier a enregistrer.") return path, _ = QFileDialog.getSaveFileName( self, "Enregistrer le resultat", "", "PDF (*.pdf)" ) if path: if not path.lower().endswith(".pdf"): path += ".pdf" import shutil shutil.copy2(source, path) self._status_label.setText(f"Enregistre : {os.path.basename(path)}") def _require_file(self): if not self._current_file: QMessageBox.warning(self, "Erreur", "Veuillez d'abord ouvrir un fichier PDF.") return False return True def _make_temp(self): fd, path = tempfile.mkstemp(suffix=".pdf") os.close(fd) return path def _show_result(self, output_path): self._result_file = output_path self._viewer.load_pdf(output_path) self._status_label.setText("Traitement termine") def _do_booklet(self): if not self._require_file(): return dlg = BookletDialog(self) if dlg.exec(): settings = dlg.get_settings() output = self._make_temp() try: create_booklet(self._current_file, output, **settings) self._show_result(output) except Exception as e: QMessageBox.critical(self, "Erreur", str(e)) def _do_nup(self): if not self._require_file(): return dlg = NupDialog(self) if dlg.exec(): settings = dlg.get_settings() output = self._make_temp() try: nup_pages(self._current_file, output, **settings) self._show_result(output) except Exception as e: QMessageBox.critical(self, "Erreur", str(e)) def _do_step_repeat(self): if not self._require_file(): return dlg = StepRepeatDialog(self) if dlg.exec(): settings = dlg.get_settings() output = self._make_temp() try: step_and_repeat(self._current_file, output, **settings) self._show_result(output) except Exception as e: QMessageBox.critical(self, "Erreur", str(e)) def _do_manual_impose(self): if not self._require_file(): return from pypdf import PdfReader reader = PdfReader(self._current_file) dlg = ManualImposeDialog(total_pages=len(reader.pages), parent=self) if dlg.exec(): settings = dlg.get_settings() output = self._make_temp() try: manual_impose(self._current_file, output, **settings) self._show_result(output) except Exception as e: QMessageBox.critical(self, "Erreur", str(e)) def _do_join_pages(self): if not self._require_file(): return dlg = JoinPagesDialog(self) if dlg.exec(): settings = dlg.get_settings() output = self._make_temp() try: join_pages(self._current_file, output, **settings) self._show_result(output) except Exception as e: QMessageBox.critical(self, "Erreur", str(e)) def _do_insert_blank(self): if not self._require_file(): return from pypdf import PdfReader reader = PdfReader(self._current_file) dlg = InsertBlankDialog(total_pages=len(reader.pages), parent=self) if dlg.exec(): settings = dlg.get_settings() output = self._make_temp() try: insert_blank_pages(self._current_file, output, **settings) self._show_result(output) except Exception as e: QMessageBox.critical(self, "Erreur", str(e)) def _do_page_numbers(self): if not self._require_file(): return dlg = PageNumbersDialog(self) if dlg.exec(): settings = dlg.get_settings() output = self._make_temp() try: add_page_numbers(self._current_file, output, **settings) self._show_result(output) except Exception as e: QMessageBox.critical(self, "Erreur", str(e)) def _do_masking(self): if not self._require_file(): return dlg = MaskingDialog(self) if dlg.exec(): settings = dlg.get_settings() output = self._make_temp() try: apply_masking(self._current_file, output, **settings) self._show_result(output) except Exception as e: QMessageBox.critical(self, "Erreur", str(e)) def _do_bleeds(self): if not self._require_file(): return dlg = BleedsDialog(self) if dlg.exec(): settings = dlg.get_settings() output = self._make_temp() try: define_bleeds(self._current_file, output, **settings) self._show_result(output) except Exception as e: QMessageBox.critical(self, "Erreur", str(e)) def _show_about(self): from PyQt6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QDialogButtonBox from PyQt6.QtGui import QPixmap from PyQt6.QtCore import Qt dlg = QDialog(self) dlg.setWindowTitle("A propos") dlg.setFixedSize(480, 380) layout = QVBoxLayout(dlg) # Logo logo_label = QLabel() import sys as _sys _base = _sys._MEIPASS if getattr(_sys, 'frozen', False) else os.path.dirname(os.path.dirname(os.path.abspath(__file__))) logo_path = os.path.join(_base, "resources", "logo.png") if os.path.exists(logo_path): pixmap = QPixmap(logo_path).scaled(120, 120, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation) logo_label.setPixmap(pixmap) logo_label.setAlignment(Qt.AlignmentFlag.AlignCenter) layout.addWidget(logo_label) # Titre title = QLabel("

Copydev Imposing Tool

") title.setAlignment(Qt.AlignmentFlag.AlignCenter) layout.addWidget(title) # Version version = QLabel("Version 1.0.0") version.setAlignment(Qt.AlignmentFlag.AlignCenter) version.setStyleSheet("color: #666;") layout.addWidget(version) layout.addSpacing(10) # Description desc = QLabel( "Outil professionnel d'imposition PDF.\n" "Creation de livrets, n-up, repetition, imposition manuelle,\n" "numerotation, masquage et fonds perdus." ) desc.setAlignment(Qt.AlignmentFlag.AlignCenter) desc.setWordWrap(True) layout.addWidget(desc) layout.addSpacing(15) # Coordonnees contact = QLabel( '

' 'CopyDev
' 'Jules Dubois
' 'contact@copydev.fr
' 'www.copydev.fr' '

' ) contact.setAlignment(Qt.AlignmentFlag.AlignCenter) contact.setOpenExternalLinks(True) layout.addWidget(contact) layout.addSpacing(5) # Copyright copy_label = QLabel("© 2026 CopyDev — Tous droits reserves") copy_label.setAlignment(Qt.AlignmentFlag.AlignCenter) copy_label.setStyleSheet("color: #999; font-size: 11px;") layout.addWidget(copy_label) # Bouton Fermer buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) buttons.rejected.connect(dlg.close) layout.addWidget(buttons) dlg.exec()