From e05f2e1fba348cd6999dd6bc182d721ecedc2480 Mon Sep 17 00:00:00 2001 From: Jules Date: Sat, 21 Mar 2026 16:54:34 +0100 Subject: [PATCH] =?UTF-8?q?V3.4.0=20=E2=80=94=20Panneau=20fusion,=20macros?= =?UTF-8?q?=20CLI,=20bouton=20config=20client=20Vision?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Panneau de fusion PDF avec dialog dedié : - Liste des fichiers avec drag & drop pour reordonner - Boutons Ajouter/Retirer/Monter/Descendre - Pre-rempli avec le fichier courant - Support --macro en ligne de commande - register_windows.bat : ajout dynamique des macros au menu contextuel - Vision : bouton "Configurer le client" dans le modal licence (ouvre le gros modal client avec SFTP, fonctions, tunnel, etc.) Co-Authored-By: Claude Opus 4.6 (1M context) --- app/dialogs/merge_dialog.py | 105 ++++++++++++++++++++++++++++++++++++ app/main_window.py | 40 +++++++------- app/updater.py | 2 +- main.py | 10 ++++ register_windows.bat | 14 +++++ version.txt | 2 +- 6 files changed, 153 insertions(+), 20 deletions(-) create mode 100644 app/dialogs/merge_dialog.py diff --git a/app/dialogs/merge_dialog.py b/app/dialogs/merge_dialog.py new file mode 100644 index 0000000..7b0d554 --- /dev/null +++ b/app/dialogs/merge_dialog.py @@ -0,0 +1,105 @@ +"""Dialogue Fusion de PDF avec reordonnement drag & drop.""" + +from PyQt6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel, + QListWidget, QListWidgetItem, QAbstractItemView, + QPushButton, QDialogButtonBox, QFileDialog) +from PyQt6.QtCore import Qt, QSize + + +class MergeDialog(QDialog): + def __init__(self, initial_files=None, parent=None): + super().__init__(parent) + self.setWindowTitle("Fusionner des PDF") + self.setMinimumSize(500, 400) + self._files = list(initial_files or []) + self._setup_ui() + self._refresh_list() + + def _setup_ui(self): + layout = QVBoxLayout(self) + + layout.addWidget(QLabel("Glissez les fichiers pour reordonner. Cliquez Ajouter pour en ajouter.")) + + self._list = QListWidget() + self._list.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove) + self._list.setDefaultDropAction(Qt.DropAction.MoveAction) + self._list.setStyleSheet(""" + QListWidget { background: #fff; border: 1px solid #d0d0d0; border-radius: 6px; padding: 4px; } + QListWidget::item { padding: 8px; border-bottom: 1px solid #eee; } + QListWidget::item:selected { background: #e0f4ff; color: #006fa6; } + """) + layout.addWidget(self._list) + + btn_layout = QHBoxLayout() + btn_add = QPushButton("Ajouter des PDF...") + btn_add.clicked.connect(self._add_files) + btn_layout.addWidget(btn_add) + + btn_remove = QPushButton("Retirer") + btn_remove.clicked.connect(self._remove_file) + btn_layout.addWidget(btn_remove) + + btn_up = QPushButton("Monter") + btn_up.clicked.connect(self._move_up) + btn_layout.addWidget(btn_up) + + btn_down = QPushButton("Descendre") + btn_down.clicked.connect(self._move_down) + btn_layout.addWidget(btn_down) + + layout.addLayout(btn_layout) + + self._count_label = QLabel("") + layout.addWidget(self._count_label) + + buttons = QDialogButtonBox( + QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel + ) + buttons.accepted.connect(self.accept) + buttons.rejected.connect(self.reject) + layout.addWidget(buttons) + + def _refresh_list(self): + self._list.clear() + for i, path in enumerate(self._files): + import os + name = os.path.basename(path) + item = QListWidgetItem(f"{i+1}. {name}") + item.setData(Qt.ItemDataRole.UserRole, path) + item.setToolTip(path) + self._list.addItem(item) + self._count_label.setText(f"{len(self._files)} fichier(s)") + + def _add_files(self): + paths, _ = QFileDialog.getOpenFileNames(self, "Ajouter des PDF", "", "PDF (*.pdf)") + if paths: + self._files.extend(paths) + self._refresh_list() + + def _remove_file(self): + row = self._list.currentRow() + if row >= 0: + self._files.pop(row) + self._refresh_list() + + def _move_up(self): + row = self._list.currentRow() + if row > 0: + self._files[row], self._files[row-1] = self._files[row-1], self._files[row] + self._refresh_list() + self._list.setCurrentRow(row - 1) + + def _move_down(self): + row = self._list.currentRow() + if 0 <= row < len(self._files) - 1: + self._files[row], self._files[row+1] = self._files[row+1], self._files[row] + self._refresh_list() + self._list.setCurrentRow(row + 1) + + def get_files(self): + # Relire l'ordre depuis la liste (drag & drop peut avoir change) + files = [] + for i in range(self._list.count()): + item = self._list.item(i) + files.append(item.data(Qt.ItemDataRole.UserRole)) + return files diff --git a/app/main_window.py b/app/main_window.py index 5dd84b0..3323c14 100644 --- a/app/main_window.py +++ b/app/main_window.py @@ -1108,25 +1108,29 @@ class MainWindow(QMainWindow): QMessageBox.critical(self, "Erreur", str(e)) def _do_merge(self): - paths, _ = QFileDialog.getOpenFileNames(self, "Selectionner les PDF a fusionner", "", "PDF (*.pdf)") - if not paths or len(paths) < 2: - if paths and len(paths) == 1: + from app.dialogs.merge_dialog import MergeDialog + # Pre-remplir avec le fichier courant si ouvert + initial = [self._current_file] if self._current_file else [] + dlg = MergeDialog(initial_files=initial, parent=self) + if dlg.exec(): + files = dlg.get_files() + if len(files) < 2: QMessageBox.information(self, "Fusion", "Selectionnez au moins 2 fichiers PDF.") - return - from pypdf import PdfWriter - self._show_progress() - try: - writer = PdfWriter() - for path in paths: - writer.append(path) - output = self._make_temp() - with open(output, "wb") as f: - writer.write(f) - self._show_result(output) - self._status_label.setText(f"Fusion de {len(paths)} fichiers terminee") - except Exception as e: - self._hide_progress() - QMessageBox.critical(self, "Erreur", str(e)) + return + from pypdf import PdfWriter + self._show_progress() + try: + writer = PdfWriter() + for path in files: + writer.append(path) + output = self._make_temp() + with open(output, "wb") as f: + writer.write(f) + self._show_result(output) + self._status_label.setText(f"Fusion de {len(files)} fichiers terminee") + except Exception as e: + self._hide_progress() + QMessageBox.critical(self, "Erreur", str(e)) # ── A propos ── diff --git a/app/updater.py b/app/updater.py index f568a54..1ca5cd5 100644 --- a/app/updater.py +++ b/app/updater.py @@ -14,7 +14,7 @@ REPO = "jules/copydev-imposing-tool" BRANCH = "master" # Version actuelle (incrementee a chaque release) -VERSION = "3.3.1" +VERSION = "3.4.0" def get_remote_version(): diff --git a/main.py b/main.py index 9a88afb..8d1e5b3 100644 --- a/main.py +++ b/main.py @@ -210,12 +210,16 @@ def main(): # Gestion des arguments args = sys.argv[1:] action = None + macro_name = None files_to_open = [] i = 0 while i < len(args): if args[i] == "--action" and i + 1 < len(args): action = args[i + 1] i += 2 + elif args[i] == "--macro" and i + 1 < len(args): + macro_name = args[i + 1] + i += 2 elif args[i].lower().endswith('.pdf') and os.path.exists(args[i]): files_to_open.append(args[i]) i += 1 @@ -265,6 +269,12 @@ def main(): QMessageBox.critical(window, "Erreur", str(e)) QTimer.singleShot(500, run_cli_action) + # Macro en ligne de commande + if macro_name and files_to_open: + def run_cli_macro(): + window._run_macro(macro_name) + QTimer.singleShot(500, run_cli_macro) + window.show() splash.close() sys.exit(app.exec()) diff --git a/register_windows.bat b/register_windows.bat index bbefc2f..6dd4b7a 100644 --- a/register_windows.bat +++ b/register_windows.bat @@ -80,6 +80,20 @@ reg add "HKCU\Software\Classes\SystemFileAssociations\.pdf\shell\CopyDevImpose\s reg add "HKCU\Software\Classes\SystemFileAssociations\.pdf\shell\CopyDevImpose\shell\unbooklet" /ve /d "Delivretiser" /f >nul 2>&1 reg add "HKCU\Software\Classes\SystemFileAssociations\.pdf\shell\CopyDevImpose\shell\unbooklet\command" /ve /d "\"%EXE_PATH%\" --action unbooklet \"%%1\"" /f >nul 2>&1 +:: Ajouter les macros enregistrees +if exist "%~dp0.presets.json" ( + echo Ajout des macros... + for /f "tokens=1 delims=:" %%m in ('findstr /r "\"[^\"]*\":" "%~dp0.presets.json" ^| findstr /v "{" ^| findstr /v "action" ^| findstr /v "settings"') do ( + set "MACRO=%%~m" + set "MACRO=!MACRO: =!" + set "MACRO=!MACRO:"=!" + if not "!MACRO!"=="" ( + reg add "HKCU\Software\Classes\SystemFileAssociations\.pdf\shell\CopyDevImpose\shell\macro_!MACRO!" /ve /d "Macro: !MACRO!" /f >nul 2>&1 + reg add "HKCU\Software\Classes\SystemFileAssociations\.pdf\shell\CopyDevImpose\shell\macro_!MACRO!\command" /ve /d "\"%EXE_PATH%\" --macro \"!MACRO!\" \"%%1\"" /f >nul 2>&1 + ) + ) +) + echo [OK] Menu contextuel ajoute echo (clic droit sur PDF > CopyDev Impose > ...) goto :EOF diff --git a/version.txt b/version.txt index bea438e..1809198 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -3.3.1 +3.4.0