|
|
|
|
@@ -229,8 +229,10 @@ class MainWindow(QMainWindow):
|
|
|
|
|
self._add_action(pages_menu, "Pivoter -90", None, lambda: self._rotate_current(-90))
|
|
|
|
|
self._add_action(pages_menu, "Pivoter 180", None, lambda: self._rotate_current(180))
|
|
|
|
|
self._add_action(pages_menu, "Inverser l'ordre des pages", None, self._do_reverse_pages)
|
|
|
|
|
self._add_action(pages_menu, "Separer paires/impaires", None, self._do_shuffle_even_odd)
|
|
|
|
|
pages_menu.addSeparator()
|
|
|
|
|
self._add_action(pages_menu, "Inserer des pages blanches", None, self._do_insert_blank)
|
|
|
|
|
self._add_action(pages_menu, "Creer un document test...", None, self._do_create_sample)
|
|
|
|
|
|
|
|
|
|
# Annotations
|
|
|
|
|
annot_menu = menubar.addMenu("Annotations")
|
|
|
|
|
@@ -247,6 +249,13 @@ class MainWindow(QMainWindow):
|
|
|
|
|
self._add_action(annot_menu, "Definir les fonds perdus", None, self._do_bleeds)
|
|
|
|
|
self._add_action(annot_menu, "Enlever les fonds perdus", None, self._do_remove_bleeds)
|
|
|
|
|
|
|
|
|
|
# Macros
|
|
|
|
|
self._macros_menu = menubar.addMenu("Macros")
|
|
|
|
|
self._add_action(self._macros_menu, "Enregistrer la derniere action...", None, self._do_save_macro)
|
|
|
|
|
self._add_action(self._macros_menu, "Gerer les macros...", None, self._do_manage_macros)
|
|
|
|
|
self._macros_menu.addSeparator()
|
|
|
|
|
self._refresh_macros_menu()
|
|
|
|
|
|
|
|
|
|
# Aide
|
|
|
|
|
help_menu = menubar.addMenu("Aide")
|
|
|
|
|
self._add_action(help_menu, "Rechercher une mise a jour...", None, self._do_check_update)
|
|
|
|
|
@@ -501,10 +510,29 @@ class MainWindow(QMainWindow):
|
|
|
|
|
os.close(fd)
|
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
_FUN_MESSAGES = [
|
|
|
|
|
"Pliage des pages en origami...",
|
|
|
|
|
"Consultation des esprits de Gutenberg...",
|
|
|
|
|
"Negociation avec les pixels...",
|
|
|
|
|
"Alignement des atomes de papier...",
|
|
|
|
|
"Invocation du dieu de l'imposition...",
|
|
|
|
|
"Repassage des pages froissees...",
|
|
|
|
|
"Calibrage du massicot virtuel...",
|
|
|
|
|
"Appel a un ami imprimeur...",
|
|
|
|
|
"Les pages font la queue...",
|
|
|
|
|
"Rechauffement de l'encre numerique...",
|
|
|
|
|
"Comptage des points par pouce...",
|
|
|
|
|
"Meditation sur les marges...",
|
|
|
|
|
"Rangement des pages par ordre alphabetique... non, numerique !",
|
|
|
|
|
"Verification que le papier est bien a plat...",
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
def _show_progress(self):
|
|
|
|
|
import random
|
|
|
|
|
self._progress.setRange(0, 0)
|
|
|
|
|
self._progress.show()
|
|
|
|
|
self._status_label.setText("Traitement en cours...")
|
|
|
|
|
msg = random.choice(self._FUN_MESSAGES)
|
|
|
|
|
self._status_label.setText(msg)
|
|
|
|
|
QApplication.processEvents()
|
|
|
|
|
|
|
|
|
|
def _hide_progress(self):
|
|
|
|
|
@@ -612,6 +640,7 @@ class MainWindow(QMainWindow):
|
|
|
|
|
output = self._make_temp()
|
|
|
|
|
try:
|
|
|
|
|
trim_and_shift(self._current_file, output, **settings)
|
|
|
|
|
self._last_action = {"action": "trim_shift", "settings": settings}
|
|
|
|
|
self._show_result(output)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self._hide_progress()
|
|
|
|
|
@@ -630,6 +659,7 @@ class MainWindow(QMainWindow):
|
|
|
|
|
try:
|
|
|
|
|
create_booklet(self._current_file, output, **settings)
|
|
|
|
|
self._show_result(output)
|
|
|
|
|
self._last_action = {"action": "booklet", "settings": settings}
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self._hide_progress()
|
|
|
|
|
QMessageBox.critical(self, "Erreur", str(e))
|
|
|
|
|
@@ -644,6 +674,7 @@ class MainWindow(QMainWindow):
|
|
|
|
|
output = self._make_temp()
|
|
|
|
|
try:
|
|
|
|
|
nup_pages(self._current_file, output, **settings)
|
|
|
|
|
self._last_action = {"action": "nup", "settings": settings}
|
|
|
|
|
self._show_result(output)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self._hide_progress()
|
|
|
|
|
@@ -659,6 +690,7 @@ class MainWindow(QMainWindow):
|
|
|
|
|
output = self._make_temp()
|
|
|
|
|
try:
|
|
|
|
|
step_and_repeat(self._current_file, output, **settings)
|
|
|
|
|
self._last_action = {"action": "step_repeat", "settings": settings}
|
|
|
|
|
self._show_result(output)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self._hide_progress()
|
|
|
|
|
@@ -981,6 +1013,153 @@ class MainWindow(QMainWindow):
|
|
|
|
|
|
|
|
|
|
# ── A propos ──
|
|
|
|
|
|
|
|
|
|
# ── Macros ──
|
|
|
|
|
|
|
|
|
|
def _last_action_info(self):
|
|
|
|
|
return getattr(self, '_last_action', None)
|
|
|
|
|
|
|
|
|
|
def _do_save_macro(self):
|
|
|
|
|
from PyQt6.QtWidgets import QInputDialog
|
|
|
|
|
name, ok = QInputDialog.getText(self, "Enregistrer la macro", "Nom de la macro :")
|
|
|
|
|
if ok and name.strip():
|
|
|
|
|
info = self._last_action_info()
|
|
|
|
|
if info:
|
|
|
|
|
from app.presets.preset_manager import save_preset
|
|
|
|
|
save_preset(name.strip(), info["action"], info["settings"])
|
|
|
|
|
self._refresh_macros_menu()
|
|
|
|
|
self._status_label.setText(f"Macro '{name.strip()}' enregistree")
|
|
|
|
|
else:
|
|
|
|
|
QMessageBox.information(self, "Macro", "Effectuez d'abord une action a enregistrer.")
|
|
|
|
|
|
|
|
|
|
def _do_manage_macros(self):
|
|
|
|
|
from app.presets.preset_manager import list_presets, delete_preset
|
|
|
|
|
from PyQt6.QtWidgets import QDialog, QVBoxLayout, QListWidget, QPushButton, QHBoxLayout
|
|
|
|
|
presets = list_presets()
|
|
|
|
|
if not presets:
|
|
|
|
|
QMessageBox.information(self, "Macros", "Aucune macro enregistree.")
|
|
|
|
|
return
|
|
|
|
|
dlg = QDialog(self)
|
|
|
|
|
dlg.setWindowTitle("Gerer les macros")
|
|
|
|
|
dlg.setMinimumWidth(350)
|
|
|
|
|
layout = QVBoxLayout(dlg)
|
|
|
|
|
lst = QListWidget()
|
|
|
|
|
lst.addItems(presets.keys())
|
|
|
|
|
layout.addWidget(lst)
|
|
|
|
|
bl = QHBoxLayout()
|
|
|
|
|
btn_del = QPushButton("Supprimer")
|
|
|
|
|
def do_del():
|
|
|
|
|
item = lst.currentItem()
|
|
|
|
|
if item:
|
|
|
|
|
delete_preset(item.text())
|
|
|
|
|
lst.takeItem(lst.row(item))
|
|
|
|
|
self._refresh_macros_menu()
|
|
|
|
|
btn_del.clicked.connect(do_del)
|
|
|
|
|
bl.addWidget(btn_del)
|
|
|
|
|
btn_close = QPushButton("Fermer")
|
|
|
|
|
btn_close.clicked.connect(dlg.close)
|
|
|
|
|
bl.addWidget(btn_close)
|
|
|
|
|
layout.addLayout(bl)
|
|
|
|
|
dlg.exec()
|
|
|
|
|
|
|
|
|
|
def _refresh_macros_menu(self):
|
|
|
|
|
from app.presets.preset_manager import list_presets
|
|
|
|
|
# Supprimer les actions apres le separateur
|
|
|
|
|
actions = self._macros_menu.actions()
|
|
|
|
|
found_sep = False
|
|
|
|
|
for act in actions:
|
|
|
|
|
if act.isSeparator():
|
|
|
|
|
found_sep = True
|
|
|
|
|
continue
|
|
|
|
|
if found_sep:
|
|
|
|
|
self._macros_menu.removeAction(act)
|
|
|
|
|
# Ajouter les presets
|
|
|
|
|
presets = list_presets()
|
|
|
|
|
for name in presets:
|
|
|
|
|
self._macros_menu.addAction(name, lambda n=name: self._run_macro(n))
|
|
|
|
|
|
|
|
|
|
def _run_macro(self, name):
|
|
|
|
|
from app.presets.preset_manager import list_presets
|
|
|
|
|
presets = list_presets()
|
|
|
|
|
preset = presets.get(name)
|
|
|
|
|
if not preset or not self._require_file():
|
|
|
|
|
return
|
|
|
|
|
action = preset["action"]
|
|
|
|
|
settings = preset["settings"]
|
|
|
|
|
self._show_progress()
|
|
|
|
|
output = self._make_temp()
|
|
|
|
|
try:
|
|
|
|
|
if action == "booklet":
|
|
|
|
|
create_booklet(self._current_file, output, **settings)
|
|
|
|
|
elif action == "nup":
|
|
|
|
|
nup_pages(self._current_file, output, **settings)
|
|
|
|
|
self._last_action = {"action": "nup", "settings": settings}
|
|
|
|
|
elif action == "step_repeat":
|
|
|
|
|
step_and_repeat(self._current_file, output, **settings)
|
|
|
|
|
self._last_action = {"action": "step_repeat", "settings": settings}
|
|
|
|
|
elif action == "crop":
|
|
|
|
|
crop_pages(self._current_file, output, **settings)
|
|
|
|
|
elif action == "trim_shift":
|
|
|
|
|
trim_and_shift(self._current_file, output, **settings)
|
|
|
|
|
self._last_action = {"action": "trim_shift", "settings": settings}
|
|
|
|
|
else:
|
|
|
|
|
self._hide_progress()
|
|
|
|
|
QMessageBox.warning(self, "Macro", f"Action inconnue : {action}")
|
|
|
|
|
return
|
|
|
|
|
self._show_result(output)
|
|
|
|
|
self._status_label.setText(f"Macro '{name}' executee")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self._hide_progress()
|
|
|
|
|
QMessageBox.critical(self, "Erreur", str(e))
|
|
|
|
|
|
|
|
|
|
# ── Pages supplementaires ──
|
|
|
|
|
|
|
|
|
|
def _do_shuffle_even_odd(self):
|
|
|
|
|
"""Separer pages paires et impaires en deux documents."""
|
|
|
|
|
if not self._require_file():
|
|
|
|
|
return
|
|
|
|
|
from pypdf import PdfReader, PdfWriter
|
|
|
|
|
reader = PdfReader(self._current_file)
|
|
|
|
|
writer_odd = PdfWriter()
|
|
|
|
|
writer_even = PdfWriter()
|
|
|
|
|
for i, page in enumerate(reader.pages):
|
|
|
|
|
if (i + 1) % 2 == 0:
|
|
|
|
|
writer_even.add_page(page)
|
|
|
|
|
else:
|
|
|
|
|
writer_odd.add_page(page)
|
|
|
|
|
# Sauvegarder les deux
|
|
|
|
|
path_odd, _ = QFileDialog.getSaveFileName(self, "Enregistrer pages impaires", "", "PDF (*.pdf)")
|
|
|
|
|
if not path_odd:
|
|
|
|
|
return
|
|
|
|
|
with open(path_odd, "wb") as f:
|
|
|
|
|
writer_odd.write(f)
|
|
|
|
|
path_even, _ = QFileDialog.getSaveFileName(self, "Enregistrer pages paires", "", "PDF (*.pdf)")
|
|
|
|
|
if path_even:
|
|
|
|
|
with open(path_even, "wb") as f:
|
|
|
|
|
writer_even.write(f)
|
|
|
|
|
self._status_label.setText("Pages paires/impaires separees")
|
|
|
|
|
|
|
|
|
|
def _do_create_sample(self):
|
|
|
|
|
"""Creer un document test numerote."""
|
|
|
|
|
from PyQt6.QtWidgets import QInputDialog
|
|
|
|
|
num, ok = QInputDialog.getInt(self, "Document test", "Nombre de pages :", 8, 1, 200)
|
|
|
|
|
if not ok:
|
|
|
|
|
return
|
|
|
|
|
from reportlab.pdfgen import canvas as rl_canvas
|
|
|
|
|
from reportlab.lib.pagesizes import A4
|
|
|
|
|
output = self._make_temp()
|
|
|
|
|
c = rl_canvas.Canvas(output, pagesize=A4)
|
|
|
|
|
for i in range(1, num + 1):
|
|
|
|
|
c.setFont("Helvetica-Bold", 72)
|
|
|
|
|
c.drawCentredString(A4[0] / 2, A4[1] / 2, str(i))
|
|
|
|
|
c.setFont("Helvetica", 14)
|
|
|
|
|
c.drawCentredString(A4[0] / 2, A4[1] / 2 - 40, f"Page {i} sur {num}")
|
|
|
|
|
c.setFont("Helvetica", 10)
|
|
|
|
|
c.drawCentredString(A4[0] / 2, 30, "CopyDev Imposing Tool — Document test")
|
|
|
|
|
c.showPage()
|
|
|
|
|
c.save()
|
|
|
|
|
self._open_pdf(output)
|
|
|
|
|
self._status_label.setText(f"Document test de {num} pages cree")
|
|
|
|
|
|
|
|
|
|
def _do_check_update(self):
|
|
|
|
|
from app.updater import check_for_update, do_update, VERSION
|
|
|
|
|
self._status_label.setText("Recherche de mises a jour...")
|
|
|
|
|
|