V3.4.0 — Panneau fusion, macros CLI, bouton config client Vision

- 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) <noreply@anthropic.com>
This commit is contained in:
Jules
2026-03-21 16:54:34 +01:00
parent 5e368ef260
commit e05f2e1fba
6 changed files with 153 additions and 20 deletions

105
app/dialogs/merge_dialog.py Normal file
View File

@@ -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

View File

@@ -1108,25 +1108,29 @@ class MainWindow(QMainWindow):
QMessageBox.critical(self, "Erreur", str(e)) QMessageBox.critical(self, "Erreur", str(e))
def _do_merge(self): def _do_merge(self):
paths, _ = QFileDialog.getOpenFileNames(self, "Selectionner les PDF a fusionner", "", "PDF (*.pdf)") from app.dialogs.merge_dialog import MergeDialog
if not paths or len(paths) < 2: # Pre-remplir avec le fichier courant si ouvert
if paths and len(paths) == 1: 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.") QMessageBox.information(self, "Fusion", "Selectionnez au moins 2 fichiers PDF.")
return return
from pypdf import PdfWriter from pypdf import PdfWriter
self._show_progress() self._show_progress()
try: try:
writer = PdfWriter() writer = PdfWriter()
for path in paths: for path in files:
writer.append(path) writer.append(path)
output = self._make_temp() output = self._make_temp()
with open(output, "wb") as f: with open(output, "wb") as f:
writer.write(f) writer.write(f)
self._show_result(output) self._show_result(output)
self._status_label.setText(f"Fusion de {len(paths)} fichiers terminee") self._status_label.setText(f"Fusion de {len(files)} fichiers terminee")
except Exception as e: except Exception as e:
self._hide_progress() self._hide_progress()
QMessageBox.critical(self, "Erreur", str(e)) QMessageBox.critical(self, "Erreur", str(e))
# ── A propos ── # ── A propos ──

View File

@@ -14,7 +14,7 @@ REPO = "jules/copydev-imposing-tool"
BRANCH = "master" BRANCH = "master"
# Version actuelle (incrementee a chaque release) # Version actuelle (incrementee a chaque release)
VERSION = "3.3.1" VERSION = "3.4.0"
def get_remote_version(): def get_remote_version():

10
main.py
View File

@@ -210,12 +210,16 @@ def main():
# Gestion des arguments # Gestion des arguments
args = sys.argv[1:] args = sys.argv[1:]
action = None action = None
macro_name = None
files_to_open = [] files_to_open = []
i = 0 i = 0
while i < len(args): while i < len(args):
if args[i] == "--action" and i + 1 < len(args): if args[i] == "--action" and i + 1 < len(args):
action = args[i + 1] action = args[i + 1]
i += 2 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]): elif args[i].lower().endswith('.pdf') and os.path.exists(args[i]):
files_to_open.append(args[i]) files_to_open.append(args[i])
i += 1 i += 1
@@ -265,6 +269,12 @@ def main():
QMessageBox.critical(window, "Erreur", str(e)) QMessageBox.critical(window, "Erreur", str(e))
QTimer.singleShot(500, run_cli_action) 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() window.show()
splash.close() splash.close()
sys.exit(app.exec()) sys.exit(app.exec())

View File

@@ -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" /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 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 [OK] Menu contextuel ajoute
echo (clic droit sur PDF > CopyDev Impose > ...) echo (clic droit sur PDF > CopyDev Impose > ...)
goto :EOF goto :EOF

View File

@@ -1 +1 @@
3.3.1 3.4.0