from datetime import datetime from pathlib import Path from PyQt6.QtCore import QObject, Qt, pyqtSignal from PyQt6.QtWidgets import ( QCheckBox, QFrame, QScrollArea, QFileDialog, QHBoxLayout, QLabel, QLineEdit, QMessageBox, QPlainTextEdit, QProgressBar, QSizePolicy, QVBoxLayout, QWidget, ) from raveos_center import katalogus, mentesek, muveletek from raveos_center.elemek import Kartya, cimke, gomb from raveos_center.hatter import hatterben AZON = "mentes" CIM = "Mentés" MERET = {"small": "kicsi", "medium": "közepes", "large": "nagy", "xlarge": "nagyon nagy"} class RovidUt(QLabel): def __init__(self, ut): super().__init__(ut) self.teljes = ut self.setObjectName("monohalvany") self.setToolTip(ut) self.setMinimumWidth(60) self.setSizePolicy(QSizePolicy.Policy.Ignored, QSizePolicy.Policy.Preferred) def resizeEvent(self, esemeny): super().resizeEvent(esemeny) self.setText(self.fontMetrics().elidedText(self.teljes, Qt.TextElideMode.ElideMiddle, self.width())) class _Jelzo(QObject): naplo = pyqtSignal(str) haladas = pyqtSignal(int) def elem_sor(elem, bejelolve): sor = QWidget() s = QHBoxLayout(sor) s.setContentsMargins(0, 4, 0, 4) s.setSpacing(12) jelolo = QCheckBox() jelolo.setChecked(bejelolve) s.addWidget(jelolo) szovegek = QVBoxLayout() szovegek.setSpacing(0) nev = cimke(katalogus.loc(elem.get("label")) or elem["id"]) nev.setStyleSheet("font-weight: 600;") szovegek.addWidget(nev) szovegek.addWidget(RovidUt(str(mentesek.abszolut(elem)))) if elem.get("note"): szovegek.addWidget(cimke(katalogus.loc(elem["note"]), "halvany", True)) s.addLayout(szovegek, 1) if elem.get("scope") == "system": s.addWidget(cimke("ROOT", "allapotcimke")) if elem.get("size_hint"): s.addWidget(cimke(MERET.get(elem["size_hint"], elem["size_hint"]), "halvany")) jelolo.nev = nev return sor, jelolo class Mentes(QWidget): def __init__(self, kozpont): super().__init__() self.kozpont = kozpont self.fut = False self.mentes_jelolok = [] self.visszaallitas_jelolok = [] self.jelzo = _Jelzo() doboz = QVBoxLayout(self) doboz.setContentsMargins(0, 24, 0, 0) doboz.setSpacing(20) doboz.addWidget( cimke( "Mentsd el az alkalmazásaid beállításait és a fontos mappáidat egyetlen fájlba, és állítsd vissza " "őket egy másik gépen vagy újratelepítés után. A ROOT jelölésű elemekhez a rendszer jelszót kér.", "masodlagos", True, ) ) oszlopok = QHBoxLayout() oszlopok.setSpacing(24) doboz.addLayout(oszlopok, 1) bal = QVBoxLayout() bal.setSpacing(16) jobb = QVBoxLayout() jobb.setSpacing(16) oszlopok.addLayout(bal, 3) oszlopok.addLayout(jobb, 2) mentes = Kartya("Mentés", terkoz=10, margo=20) gorgeto = QScrollArea() gorgeto.setWidgetResizable(True) gorgeto.setFrameShape(QFrame.Shape.NoFrame) gorgeto.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) gorgeto.setMinimumHeight(160) lista_doboz = QWidget() gorgeto.setWidget(lista_doboz) self.mentes_lista = QVBoxLayout(lista_doboz) self.mentes_lista.setContentsMargins(0, 0, 12, 0) self.mentes_lista.setSpacing(2) mentes.elrendezes.addWidget(gorgeto, 1) cel_sor = QHBoxLayout() cel_sor.setSpacing(8) self.cel = QLineEdit(str(Path.home() / f"raveos-mentes-{datetime.now():%Y%m%d}.tar.gz")) cel_sor.addWidget(self.cel, 1) tallozas = gomb("Tallózás", kicsi=True) tallozas.clicked.connect(self._cel_valaszt) cel_sor.addWidget(tallozas) mentes.elrendezes.addSpacing(8) mentes.elrendezes.addWidget(cimke("Mentés helye", "kartyacim")) mentes.elrendezes.addLayout(cel_sor) gs = QHBoxLayout() gs.addStretch(1) self.mentes_gomb = gomb("Mentés indítása", fo=True) self.mentes_gomb.clicked.connect(self._mentes) gs.addWidget(self.mentes_gomb) mentes.elrendezes.addLayout(gs) bal.addWidget(mentes, 1) vissza = Kartya("Visszaállítás", terkoz=10, margo=20) fs = QHBoxLayout() fs.setSpacing(8) self.forras = QLineEdit() self.forras.setPlaceholderText("Válaszd ki a mentésfájlt (.tar.gz)") self.forras.setReadOnly(True) fs.addWidget(self.forras, 1) valaszt = gomb("Mentés kiválasztása", kicsi=True) valaszt.clicked.connect(self._forras_valaszt) fs.addWidget(valaszt) vissza.elrendezes.addLayout(fs) self.vissza_lista = QVBoxLayout() self.vissza_lista.setSpacing(2) vissza.elrendezes.addLayout(self.vissza_lista) vissza.elrendezes.addWidget( cimke("A visszaállítás felülírja a meglévő fájlokat a kiválasztott helyeken.", "halvany", True) ) vs = QHBoxLayout() vs.addStretch(1) self.vissza_gomb = gomb("Visszaállítás", fo=True) self.vissza_gomb.setEnabled(False) self.vissza_gomb.clicked.connect(self._visszaallitas) vs.addWidget(self.vissza_gomb) vissza.elrendezes.addLayout(vs) jobb.addWidget(vissza) self.sav = QProgressBar() self.sav.setObjectName("sav") self.sav.setTextVisible(False) self.sav.setFixedHeight(6) jobb.addWidget(self.sav) jobb.addWidget(cimke("NAPLÓ", "h2")) self.naplo = QPlainTextEdit() self.naplo.setObjectName("naplo") self.naplo.setReadOnly(True) self.naplo.setMinimumHeight(100) jobb.addWidget(self.naplo, 1) self.jelzo.naplo.connect(self.naplo.appendPlainText) self.jelzo.haladas.connect(self.sav.setValue) self._mentes_lista_epit() def _mentes_lista_epit(self): try: csoportok = mentesek.csoportok() except (OSError, ValueError, RuntimeError) as e: self.mentes_lista.addWidget(cimke(f"A mentési lista nem tölthető be: {e}", "figyelem", True)) return self.mentes_lista.addStretch(0) for csoport in csoportok: fej = cimke(katalogus.loc(csoport.get("label")).upper(), "monozold") self.mentes_lista.addSpacing(8) self.mentes_lista.addWidget(fej) if csoport.get("description"): self.mentes_lista.addWidget(cimke(katalogus.loc(csoport["description"]), "halvany", True)) for elem in csoport.get("items", []): sor, jelolo = elem_sor(elem, elem.get("default_selected", False)) self.mentes_lista.addWidget(sor) self.mentes_jelolok.append((jelolo, elem)) def megjelenik(self, *_): self._gombok() def _gombok(self): self.mentes_gomb.setEnabled(not self.fut) self.vissza_gomb.setEnabled(not self.fut and bool(self.visszaallitas_jelolok)) def _cel_valaszt(self): ut, _ = QFileDialog.getSaveFileName(self, "Mentés helye", self.cel.text(), "Mentés (*.tar.gz)") if ut: self.cel.setText(ut if ut.endswith(".tar.gz") else ut + ".tar.gz") def _forras_valaszt(self): ut, _ = QFileDialog.getOpenFileName(self, "Mentés kiválasztása", str(Path.home()), "Mentés (*.tar.gz)") if not ut: return self.forras.setText(ut) self._tartalom([]) hatterben(mentesek.tartalom, ut, kesz=self._tartalom, hiba=lambda u: self._hiba(f"A fájl nem olvasható: {u}")) def _tartalom(self, lista): while self.vissza_lista.count(): w = self.vissza_lista.takeAt(0).widget() if w: w.deleteLater() self.visszaallitas_jelolok = [] if not lista: self.vissza_lista.addWidget(cimke("Ebben a fájlban nincs visszaállítható elem.", "halvany")) for elem in lista: sor, jelolo = elem_sor(elem, True) self.vissza_lista.addWidget(sor) self.visszaallitas_jelolok.append((jelolo, elem)) if any(e.get("regi") for e in lista): self.vissza_lista.addWidget( cimke("Régi (App Installer) formátumú mentés: a rendszerelemek ebből nem állíthatók vissza.", "halvany", True) ) self._gombok() def _hiba(self, szoveg): self.naplo.appendPlainText(f"[HIBA] {szoveg}") def _rootot_kell(self, elemek): if any(e.get("scope") == "system" for e in elemek) and not muveletek.helper_elerheto(): QMessageBox.warning(self, "Mentés", "A rendszerelemekhez a RaveOS Center rendszerhelpere szükséges, de nincs telepítve.") return False return True def _mentes(self): elemek = [e for j, e in self.mentes_jelolok if j.isChecked()] cel = self.cel.text().strip() if not elemek or not cel or not self._rootot_kell(elemek): return if Path(cel).exists(): if QMessageBox.question(self, "Mentés", f"A fájl már létezik, felülírod?\n{cel}") != QMessageBox.StandardButton.Yes: return self._indul(f"Mentés indul: {cel}") hatterben( mentesek.mentes, cel, elemek, self.jelzo.naplo.emit, self.jelzo.haladas.emit, kesz=lambda n: self._vege(f"Mentés kész: {n} elem, {cel}"), hiba=lambda u: self._vege(f"A mentés nem sikerült: {u}", False), ) def _visszaallitas(self): elemek = [e for j, e in self.visszaallitas_jelolok if j.isChecked()] if not elemek or not self._rootot_kell(elemek): return if QMessageBox.question( self, "Visszaállítás", f"{len(elemek)} elem visszaállítása felülírja a meglévő fájlokat. Folytatod?" ) != QMessageBox.StandardButton.Yes: return self._indul(f"Visszaállítás indul: {self.forras.text()}") hatterben( mentesek.visszaallitas, self.forras.text(), elemek, self.jelzo.naplo.emit, self.jelzo.haladas.emit, kesz=lambda n: self._vege(f"Visszaállítás kész: {n} elem."), hiba=lambda u: self._vege(f"A visszaállítás nem sikerült: {u}", False), ) def _indul(self, szoveg): self.fut = True self._gombok() self.sav.setValue(0) self.naplo.appendPlainText(szoveg) def _vege(self, szoveg, rendben=True): self.fut = False self._gombok() self.naplo.appendPlainText(szoveg if rendben else f"[HIBA] {szoveg}") FUL = Mentes