diff options
| author | Nippy <nippy@Nippy-Mac-mini.local> | 2026-11-01 18:13:54 +0100 |
|---|---|---|
| committer | Nippy <nippy@Nippy-Mac-mini.local> | 2026-11-01 18:13:54 +0100 |
| commit | a64ef966534f8dba6af889ba4bfce15691bfc85b (patch) | |
| tree | b30f284d05b80fa115569ab220deae13797fad6f /raveos-center/raveos_center/oldalak/rendszer | |
| parent | 919f977b40016f588b0c8532c8a57f6035056b95 (diff) | |
| download | RaveOS-PKGBUILD-a64ef966534f8dba6af889ba4bfce15691bfc85b.tar.gz RaveOS-PKGBUILD-a64ef966534f8dba6af889ba4bfce15691bfc85b.zip | |
új telepítő
Diffstat (limited to 'raveos-center/raveos_center/oldalak/rendszer')
7 files changed, 1477 insertions, 0 deletions
diff --git a/raveos-center/raveos_center/oldalak/rendszer/__init__.py b/raveos-center/raveos_center/oldalak/rendszer/__init__.py new file mode 100644 index 0000000..60b5768 --- /dev/null +++ b/raveos-center/raveos_center/oldalak/rendszer/__init__.py @@ -0,0 +1,49 @@ +import importlib + +from raveos_center.elemek import Fulsor, Oldal, Verem + +AZON = "rendszer" +MENU = "Rendszer" +IKON = "rendszer" + +FULEK = ["driverek", "gaming", "karbantartas", "snapshotok", "secureboot", "mentes"] + + +class Rendszer(Oldal): + def __init__(self, kozpont): + super().__init__(kozpont, "DRIVEREK · GAMING · KARBANTARTÁS · SNAPSHOTOK", "Rendszer", kitolt=True) + self.fulek = {} + modulok = [importlib.import_module(f"{__name__}.{nev}") for nev in FULEK] + self.fulsor = Fulsor([(m.AZON, m.CIM) for m in modulok], self.valt) + self.torzs.addWidget(self.fulsor) + self.verem = Verem() + for m in modulok: + ful = m.FUL(kozpont) + self.fulek[m.AZON] = ful + self.verem.addWidget(ful) + self.torzs.addWidget(self.verem, 1) + self.aktiv = modulok[0].AZON if modulok else None + if self.aktiv: + self.fulsor.aktiv(self.aktiv) + + def valt(self, azon, *args): + if azon not in self.fulek: + return + self.aktiv = azon + self.fulsor.aktiv(azon) + self.verem.setCurrentWidget(self.fulek[azon]) + self.fulek[azon].megjelenik(*args) + + def elerheto(self, ful=None, *_): + return ful is None or ful in self.fulek + + def megjelenik(self, ful=None, *args): + self.valt(ful if ful in self.fulek else self.aktiv, *args) + + def indulaskor(self): + for ful in self.fulek.values(): + if hasattr(ful, "indulaskor"): + ful.indulaskor() + + +OLDAL = Rendszer diff --git a/raveos-center/raveos_center/oldalak/rendszer/driverek.py b/raveos-center/raveos_center/oldalak/rendszer/driverek.py new file mode 100644 index 0000000..499e87a --- /dev/null +++ b/raveos-center/raveos_center/oldalak/rendszer/driverek.py @@ -0,0 +1,159 @@ +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QHBoxLayout, QMessageBox, QVBoxLayout, QWidget + +from raveos_center import driverek, muveletek +from raveos_center.elemek import Kartya, cimke, gomb +from raveos_center.folyamat import FolyamatAblak +from raveos_center.hatter import ervenytelenit, gyorsitott + +AZON = "driverek" +CIM = "Driverek" + + +class EszkozSor(QWidget): + def __init__(self, elem, telepit): + super().__init__() + self.setObjectName("appsor") + self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True) + sor = QHBoxLayout(self) + sor.setContentsMargins(16, 12, 16, 12) + sor.setSpacing(16) + szovegek = QVBoxLayout() + szovegek.setSpacing(3) + nev = cimke(elem["nev"], tordel=True) + nev.setStyleSheet("font-size: 14px; font-weight: 600;") + szovegek.addWidget(nev) + szovegek.addWidget(cimke(f"Jelenlegi driver: {elem['jelenlegi'] or 'nincs betöltve'}", "monohalvany")) + if elem["hianyzik"]: + hiany = cimke(f"Hiányzó csomagok: {' '.join(elem['hianyzik'])}", "monohalvany", True) + hiany.setStyleSheet("color: #d9a441;") + szovegek.addWidget(hiany) + if elem["megjegyzes"]: + szovegek.addWidget(cimke(elem["megjegyzes"], "halvany", True)) + sor.addLayout(szovegek, 1) + if elem["hianyzik"]: + g = gomb("Ajánlott telepítése", fo=True, kicsi=True) + g.setEnabled(muveletek.helper_elerheto()) + g.clicked.connect(lambda: telepit([elem])) + sor.addWidget(g, 0, Qt.AlignmentFlag.AlignVCenter) + else: + rendben = cimke("RENDBEN", "allapotcimke") + rendben.setProperty("szin", "zold") + sor.addWidget(rendben, 0, Qt.AlignmentFlag.AlignVCenter) + + +class Driverek(QWidget): + def __init__(self, kozpont): + super().__init__() + self.kozpont = kozpont + self.elemek = [] + self.kapott = None + doboz = QVBoxLayout(self) + doboz.setContentsMargins(0, 20, 0, 0) + doboz.setSpacing(16) + fej = QHBoxLayout() + fej.addWidget( + cimke( + "A RaveOS felismeri a géped eszközeit, és megmutatja, melyikhez van ajánlott driver. " + "A videokártya drivere a telepítéskor is ugyanígy kerül fel.", + "masodlagos", + True, + ), + 1, + ) + self.ujra = gomb("Újraellenőrzés", kicsi=True) + self.ujra.clicked.connect(self.frissit) + fej.addWidget(self.ujra, 0, Qt.AlignmentFlag.AlignTop) + self.mind = gomb("Minden ajánlott telepítése", fo=True, kicsi=True) + self.mind.clicked.connect(lambda: self._telepit([e for e in self.elemek if e["hianyzik"]])) + self.mind.hide() + fej.addWidget(self.mind, 0, Qt.AlignmentFlag.AlignTop) + doboz.addLayout(fej) + self.figyelem = cimke("", "figyelem", True) + self.figyelem.hide() + doboz.addWidget(self.figyelem) + self.lista = QVBoxLayout() + self.lista.setSpacing(20) + doboz.addLayout(self.lista) + doboz.addStretch(1) + + def megjelenik(self, *_): + gyorsitott("driverek", driverek.allapot, kesz=self._kesz, hiba=self._hiba, kor=120) + + def frissit(self): + self.ujra.setEnabled(False) + ervenytelenit("driverek") + gyorsitott("driverek", driverek.allapot, kesz=self._kesz, hiba=self._hiba) + + def _hiba(self, uzenet): + self.ujra.setEnabled(True) + self.figyelem.setText(f"A hardver felismerése nem sikerült: {uzenet}") + self.figyelem.show() + + def _kesz(self, elemek): + self.ujra.setEnabled(True) + if elemek == self.kapott: + return + self.kapott = elemek + self.elemek = elemek + while self.lista.count(): + w = self.lista.takeAt(0).widget() + if w: + w.deleteLater() + if not muveletek.helper_elerheto(): + self.figyelem.setText("A RaveOS Center rendszerhelpere nincs telepítve, ezért driver nem telepíthető.") + self.figyelem.show() + else: + self.figyelem.hide() + if driverek.szkript() is None: + self.figyelem.setText("A driverfelismerő szkript nincs telepítve.") + self.figyelem.show() + for azon, nev in driverek.KATEGORIAK: + sajat = [e for e in elemek if e["kategoria"] == azon] + if not sajat: + continue + csoport = QWidget() + cs = QVBoxLayout(csoport) + cs.setContentsMargins(0, 0, 0, 0) + cs.setSpacing(10) + cs.addWidget(cimke(nev.upper(), "h2")) + kartya = Kartya(terkoz=0, margo=0) + for i, e in enumerate(sajat): + sor = EszkozSor(e, self._telepit) + sor.setProperty("utolso", i == len(sajat) - 1) + kartya.elrendezes.addWidget(sor) + cs.addWidget(kartya) + self.lista.addWidget(csoport) + if not elemek: + self.lista.addWidget(cimke("Nem található kezelhető eszköz.", "halvany")) + hianyzo = [e for e in elemek if e["hianyzik"]] + self.mind.setVisible(len(hianyzo) > 1) + self.mind.setEnabled(muveletek.helper_elerheto()) + + def _telepit(self, elemek): + if not elemek: + return + lepesek = [] + egyeb = [] + if any(e["gpu"] for e in elemek): + lepesek.append(muveletek.Lepes("Videokártya driverek", muveletek.root("driverek"))) + for e in elemek: + if not e["gpu"]: + egyeb += [p for p in e["hianyzik"] if p not in egyeb] + if egyeb: + lepesek.append(muveletek.Lepes("További driverek", muveletek.root("telepit", *egyeb))) + ablak = FolyamatAblak(self, "Driverek telepítése", lepesek, "A driverek telepítve.") + ablak.exec() + if ablak.rendben and any(driverek.ujrainditas_kell(e) for e in elemek): + doboz = QMessageBox(self) + doboz.setWindowTitle("Újraindítás szükséges") + doboz.setText("Az új videokártya-driver az újraindítás után töltődik be.") + most = doboz.addButton("Újraindítás most", QMessageBox.ButtonRole.AcceptRole) + doboz.addButton("Később", QMessageBox.ButtonRole.RejectRole) + doboz.exec() + if doboz.clickedButton() is most: + muveletek.Futtato(self).indit([muveletek.Lepes("Újraindítás", ["systemctl", "reboot"])]) + self.frissit() + + +FUL = Driverek diff --git a/raveos-center/raveos_center/oldalak/rendszer/gaming.py b/raveos-center/raveos_center/oldalak/rendszer/gaming.py new file mode 100644 index 0000000..5d410e9 --- /dev/null +++ b/raveos-center/raveos_center/oldalak/rendszer/gaming.py @@ -0,0 +1,306 @@ +from PyQt6.QtCore import QObject, Qt, pyqtSignal +from PyQt6.QtWidgets import QComboBox, QHBoxLayout, QMessageBox, QProgressBar, QVBoxLayout, QWidget + +from raveos_center import gaming, muveletek, proton +from raveos_center.elemek import Kapcsolo, Kartya, cimke, gomb +from raveos_center.folyamat import FolyamatAblak +from raveos_center.hatter import ervenytelenit, gyorsitott, hatterben, tarolt + +AZON = "gaming" +CIM = "Gaming" + +BEALLITASOK = [ + ("gamemode", "GameMode", "CPU és I/O prioritás játék közben. A Lutris és a Heroic magától használja, Steamben a " + "játék indítási opciójába írd: gamemoderun %command%"), + ("mangohud", "MangoHud alapból", "FPS, hőmérséklet és terhelés kijelzése minden Vulkan és OpenGL játékban. " + "Játék közben a jobb Shift + F12 elrejti, a jobb Shift + F10 vált a kijelző módok között."), + ("utemezo", "Játékra hangolt ütemező", "Az scx_lavd ütemező gaming módban: egyenletesebb képkockaidő, amikor a " + "háttérben más is fut. Kikapcsolva a kernel saját BORE ütemezője dolgozik."), + ("gamescope", "Gamescope session", "Külön, konzolszerű Steam játékmenet, a bejelentkező képernyőn választható."), + ("governor", "Performance CPU governor", "Játék közben teljes órajel, a játék bezárása után visszaáll."), + ("ntsync", "NTSync", "Gyorsabb Windows-szinkronizáció Wine és Proton alatt."), +] + + +class _Jelzo(QObject): + haladas = pyqtSignal(int) + + +def alkalmaz(szulo, valtozasok): + lepesek = [] + helyi = [] + for azon, be in valtozasok: + l, h = gaming.lepesek(azon, be) + lepesek += l + if h: + helyi.append(h) + if lepesek: + ablak = FolyamatAblak(szulo, "Gaming beállítások", lepesek, "A beállítás elkészült.") + ablak.exec() + if not ablak.rendben: + return "A beállítás nem sikerült teljesen, a részleteket a napló mutatja." + for h in helyi: + try: + h() + except OSError as e: + return f"A beállítás nem sikerült: {e}" + return None + + +class Sor(QWidget): + def __init__(self, nev, leiras, utolso=False): + super().__init__() + self.setObjectName("appsor") + self.setProperty("utolso", utolso) + self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True) + self.sor = QHBoxLayout(self) + self.sor.setContentsMargins(16, 14, 16, 14) + self.sor.setSpacing(16) + self.szovegek = QVBoxLayout() + self.szovegek.setSpacing(3) + cim = cimke(nev) + cim.setStyleSheet("font-size: 14px; font-weight: 600;") + self.szovegek.addWidget(cim) + self.szovegek.addWidget(cimke(leiras, "halvany", True)) + self.megjegyzes = cimke("", "monohalvany", True) + self.megjegyzes.hide() + self.szovegek.addWidget(self.megjegyzes) + self.sor.addLayout(self.szovegek, 1) + + def jegyzet(self, szoveg): + self.megjegyzes.setText(szoveg) + self.megjegyzes.setVisible(bool(szoveg)) + + +class BeallitasSor(Sor): + def __init__(self, azon, nev, leiras, valt, utolso=False): + super().__init__(nev, leiras, utolso) + self.azon = azon + self.kapcsolo = Kapcsolo() + self.kapcsolo.setAccessibleName(nev) + self.kapcsolo.clicked.connect(lambda be: valt(self.azon, be)) + self.sor.addWidget(self.kapcsolo, 0, Qt.AlignmentFlag.AlignVCenter) + + def beallit(self, adat, foglalt): + self.kapcsolo.blockSignals(True) + self.kapcsolo.setChecked(adat["aktiv"]) + self.kapcsolo.blockSignals(False) + helper = muveletek.helper_elerheto() or not adat["root"] + self.kapcsolo.setEnabled(adat["elerheto"] and helper and not foglalt) + self.jegyzet(adat["megjegyzes"]) + self.kapcsolo.update() + + +class ProtonGeSor(Sor): + def __init__(self, szulo): + super().__init__( + "Proton-GE", + "A GloriousEggroll Proton-változata, több játékhoz tartalmaz javítást és videokodeket. A Steam " + "újraindítása után a játék Tulajdonságok > Kompatibilitás menüjében választható.", + ) + self.szulo = szulo + self.kiadas = None + self.fut = False + self.jelzo = _Jelzo() + self.sav = QProgressBar() + self.sav.setObjectName("sav") + self.sav.setTextVisible(False) + self.sav.setFixedHeight(6) + self.sav.hide() + self.jelzo.haladas.connect(self.sav.setValue) + self.szovegek.addWidget(self.sav) + gombok = QVBoxLayout() + gombok.setSpacing(6) + self.telepit_gomb = gomb("Legújabb telepítése", fo=True, kicsi=True) + self.telepit_gomb.clicked.connect(self._telepit) + self.regiek_gomb = gomb("Régiek törlése", kicsi=True) + self.regiek_gomb.clicked.connect(self._regiek) + self.torol_gomb = gomb("Mind törlése", kicsi=True) + self.torol_gomb.clicked.connect(self._mind) + for g in (self.telepit_gomb, self.regiek_gomb, self.torol_gomb): + gombok.addWidget(g) + gombok.addStretch(1) + self.sor.addLayout(gombok) + + def frissit(self): + if self.fut: + return + self._mutat() + gyorsitott("proton_ge", proton.legujabb, kesz=self._kiadas, hiba=lambda _: self._kiadas(None), kor=3600) + + def _kiadas(self, kiadas): + self.kiadas = kiadas or self.kiadas + if not self.fut: + self._mutat() + + def _mutat(self, szoveg=None): + lista = proton.telepitett() + van_steam = bool(proton.celmappak()) + naprakesz = bool(self.kiadas and lista and lista[0] == self.kiadas["nev"]) + if szoveg is None: + szoveg = f"Telepítve: {', '.join(lista)}" if lista else "Nincs telepítve." + if self.kiadas and not naprakesz: + szoveg += f" Legújabb: {self.kiadas['nev']}" + if not van_steam: + szoveg = "Nem található Steam. Telepítsd, és indítsd el egyszer." + self.jegyzet(szoveg) + self.telepit_gomb.setText("Naprakész" if naprakesz else "Legújabb telepítése") + self.telepit_gomb.setEnabled(not self.fut and not naprakesz and van_steam) + self.regiek_gomb.setVisible(bool(proton.regiek())) + self.regiek_gomb.setEnabled(not self.fut) + self.torol_gomb.setVisible(bool(lista)) + self.torol_gomb.setEnabled(not self.fut) + + def _telepit(self): + self.fut = True + self.sav.setValue(0) + self.sav.show() + self._mutat("Letöltés és ellenőrzés, ez néhány percig tarthat.") + hatterben(self._letolt, kesz=self._kesz, hiba=self._hiba) + + def _letolt(self): + kiadas = self.kiadas or proton.legujabb() + proton.telepit(kiadas, self.jelzo.haladas.emit) + return kiadas + + def _kesz(self, kiadas): + self.fut = False + self.kiadas = kiadas + self.sav.hide() + self._mutat() + + def _hiba(self, uzenet): + self.fut = False + self.sav.hide() + self._mutat() + QMessageBox.warning(self.szulo, "Proton-GE", f"A telepítés nem sikerült: {uzenet}") + + def _torles(self, parok, kerdes): + if not parok or QMessageBox.question(self.szulo, "Proton-GE", kerdes) != QMessageBox.StandardButton.Yes: + return + try: + for mappa, nev in parok: + proton.torol(nev, [mappa] if mappa else None) + except OSError as e: + QMessageBox.warning(self.szulo, "Proton-GE", f"A törlés nem sikerült: {e}") + self._mutat() + + def _regiek(self): + parok = proton.regiek() + nevek = ", ".join(sorted({n for _, n in parok})) + self._torles(parok, f"Törlöd a régebbi verziókat ({nevek})? Minden Steam-telepítésben a legújabb megmarad.") + + def _mind(self): + self._torles( + [(None, n) for n in proton.telepitett()], + "Törlöd az összes Proton-GE verziót? Az ezeket használó játékok a Steam alap Protonjára váltanak.", + ) + + +class Gaming(QWidget): + def __init__(self, kozpont): + super().__init__() + self.kozpont = kozpont + self.adat = None + self.foglalt = False + self.hibauzenet = "" + doboz = QVBoxLayout(self) + doboz.setContentsMargins(0, 20, 0, 0) + doboz.setSpacing(16) + doboz.addWidget( + cimke( + "Játékhoz hasznos beállítások. Mindegyik bármikor visszakapcsolható. Az Áttekintés Gaming mód " + "kapcsolója a GameMode-ot, a performance governort, az NTSync-et és a játékra hangolt ütemezőt " + "kapcsolja egyszerre.", + "masodlagos", + True, + ) + ) + self.figyelem = cimke("", "figyelem", True) + self.figyelem.hide() + doboz.addWidget(self.figyelem) + + kartya = Kartya(terkoz=0, margo=0) + self.sorok = {} + for i, (azon, nev, leiras) in enumerate(BEALLITASOK): + sor = BeallitasSor(azon, nev, leiras, self.valt, i == len(BEALLITASOK) - 1) + self.sorok[azon] = sor + kartya.elrendezes.addWidget(sor) + self.hud_mod = QComboBox() + for mod, nev in gaming.MANGOHUD_MODOK: + self.hud_mod.addItem(nev, mod) + self.hud_mod.activated.connect(self._hud_mod) + hud_sor = QHBoxLayout() + hud_sor.setSpacing(8) + hud_sor.addWidget(cimke("Kijelző:", "halvany")) + hud_sor.addWidget(self.hud_mod) + hud_sor.addStretch(1) + self.sorok["mangohud"].szovegek.addSpacing(6) + self.sorok["mangohud"].szovegek.addLayout(hud_sor) + doboz.addWidget(kartya) + + doboz.addSpacing(8) + doboz.addWidget(cimke("PROTON VERZIÓK", "h2")) + proton_kartya = Kartya(terkoz=0, margo=0) + self.proton_ge = ProtonGeSor(self) + proton_kartya.elrendezes.addWidget(self.proton_ge) + self.sorok["proton_cachyos"] = BeallitasSor( + "proton_cachyos", + "Proton-CachyOS", + "A CachyOS Proton-változata a rendszer csomagkezelőjéből, a rendszerfrissítéssel együtt frissül. " + "Kb. 1,6 GB. A Steam újraindítása után választható.", + self.valt, + True, + ) + proton_kartya.elrendezes.addWidget(self.sorok["proton_cachyos"]) + doboz.addWidget(proton_kartya) + doboz.addStretch(1) + + def megjelenik(self, *_): + self.frissit() + self.proton_ge.frissit() + + def frissit(self): + if tarolt("gaming") is None: + self.foglalt = True + for sor in self.sorok.values(): + sor.kapcsolo.setEnabled(False) + gyorsitott("gaming", gaming.allapot, kesz=self._kesz, hiba=lambda _: self._kesz(self.adat), kor=30) + + def _kesz(self, adat): + self.foglalt = False + index = self.hud_mod.findData(gaming.mangohud_mod()) + self.hud_mod.setCurrentIndex(max(0, index)) + if adat is None: + self._figyelmeztet("Az állapot nem olvasható be, próbáld újra a fül újbóli megnyitásával.") + return + self.adat = adat + for azon, sor in self.sorok.items(): + sor.beallit(adat[azon], self.foglalt) + if self.hibauzenet: + self._figyelmeztet(self.hibauzenet) + elif not muveletek.helper_elerheto(): + self._figyelmeztet("A RaveOS Center rendszerhelpere nincs telepítve, a legtöbb beállítás nem módosítható.") + else: + self.figyelem.hide() + + def _figyelmeztet(self, szoveg): + self.figyelem.setText(szoveg) + self.figyelem.show() + + def _hud_mod(self): + try: + gaming.mangohud_mod_beallit(self.hud_mod.currentData()) + except OSError as e: + QMessageBox.warning(self, "MangoHud", f"A beállítás nem sikerült: {e}") + + def valt(self, azon, be): + self.alkalmaz([(azon, be)]) + + def alkalmaz(self, valtozasok): + self.hibauzenet = alkalmaz(self, valtozasok) or "" + ervenytelenit("gaming") + self.frissit() + + +FUL = Gaming diff --git a/raveos-center/raveos_center/oldalak/rendszer/karbantartas.py b/raveos-center/raveos_center/oldalak/rendszer/karbantartas.py new file mode 100644 index 0000000..91b7113 --- /dev/null +++ b/raveos-center/raveos_center/oldalak/rendszer/karbantartas.py @@ -0,0 +1,177 @@ +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QDialog, QHBoxLayout, QListWidget, QListWidgetItem, QVBoxLayout, QWidget + +from raveos_center import karbantartas, muveletek +from raveos_center.elemek import Kartya, Racs, cimke, gomb +from raveos_center.folyamat import FolyamatAblak +from raveos_center.hatter import gyorsitott, tarolt + +AZON = "karbantartas" +CIM = "Karbantartás" + +MUVELETEK = [ + ("cache", "paccache -rk2", "Csomag cache ürítése", + "Minden csomagból csak az utolsó két verzió marad, az eltávolított csomagok fájljai törlődnek.", True), + ("arva", "pacman -Qdtq", "Árva csomagok", + "Már semmi által nem használt függőségek eltávolítása. Az előnézetben egyenként kiveheted, amit megtartanál.", True), + ("naplo", "journalctl --vacuum", "Naplók takarítása", + "A két hétnél régebbi rendszernaplók törlése, legfeljebb 100 MB marad.", True), + ("tukrok", "reflector", "Tükrök frissítése", + "A leggyorsabb közeli letöltési szerverek kiválasztása. A régi lista biztonsági másolatként megmarad.", False), + ("kulcsok", "pacman-key --populate", "Kulcsok frissítése", + "A csomagaláíró kulcsok újratöltése. Segít, ha a frissítés aláírási hibával áll le.", False), + ("flatpak", "flatpak uninstall --unused", "Flatpak takarítás", + "A már egyik alkalmazás által sem használt runtime-ok eltávolítása.", True), +] + + +class ElonezetAblak(QDialog): + def __init__(self, szulo, cim, szoveg, elemek, valaszthato, gomb_szoveg): + super().__init__(szulo) + self.setWindowTitle(cim) + self.resize(640, 480) + doboz = QVBoxLayout(self) + doboz.setContentsMargins(28, 24, 28, 20) + doboz.setSpacing(12) + doboz.addWidget(cimke("ELŐNÉZET", "eyebrow")) + doboz.addWidget(cimke(cim.upper(), "h2", True)) + doboz.addWidget(cimke(szoveg, "masodlagos", True)) + self.lista = QListWidget() + for elem in elemek: + sor = QListWidgetItem(elem) + if valaszthato: + sor.setFlags(sor.flags() | Qt.ItemFlag.ItemIsUserCheckable) + sor.setCheckState(Qt.CheckState.Checked) + self.lista.addItem(sor) + self.lista.setVisible(bool(elemek)) + doboz.addWidget(self.lista, 1) + if not elemek: + doboz.addStretch(1) + gombok = QHBoxLayout() + gombok.addStretch(1) + megse = gomb("Mégse") + megse.clicked.connect(self.reject) + gombok.addWidget(megse) + self.mehet = gomb(gomb_szoveg, fo=True) + self.mehet.clicked.connect(self.accept) + gombok.addWidget(self.mehet) + doboz.addLayout(gombok) + if valaszthato: + self.lista.itemChanged.connect(lambda _: self.mehet.setEnabled(bool(self.kivalasztott()))) + + def kivalasztott(self): + return [ + self.lista.item(i).text() + for i in range(self.lista.count()) + if self.lista.item(i).checkState() == Qt.CheckState.Checked + ] + + +class MuveletKartya(Kartya): + def __init__(self, parancs, nev, leiras, futtat): + super().__init__(terkoz=8, margo=20) + self.elrendezes.addWidget(cimke(parancs, "monohalvany")) + cim = cimke(nev) + cim.setStyleSheet("font-size: 15px; font-weight: 600;") + self.elrendezes.addWidget(cim) + self.elrendezes.addWidget(cimke(leiras, "halvany", True)) + self.elrendezes.addStretch(1) + self.osszegzes = cimke("Ellenőrzés...", "monozold", True) + self.elrendezes.addWidget(self.osszegzes) + sor = QHBoxLayout() + self.gomb = gomb("Futtatás", kicsi=True) + self.gomb.clicked.connect(futtat) + sor.addWidget(self.gomb) + sor.addStretch(1) + self.elrendezes.addLayout(sor) + + +class Karbantartas(QWidget): + def __init__(self, kozpont): + super().__init__() + self.kozpont = kozpont + self.adat = {} + doboz = QVBoxLayout(self) + doboz.setContentsMargins(0, 20, 0, 0) + doboz.setSpacing(16) + doboz.addWidget( + cimke( + "Rendszeres takarítás és javítás. A törléssel járó műveletek előtt megmutatjuk, mi kerülne törlésre, " + "és csak a megerősítésed után futnak.", + "masodlagos", + True, + ) + ) + self.figyelem = cimke("", "figyelem", True) + self.figyelem.hide() + doboz.addWidget(self.figyelem) + self.racs = Racs(260, 12) + self.kartyak = {} + for azon, parancs, nev, leiras, _ in MUVELETEK: + kartya = MuveletKartya(parancs, nev, leiras, lambda _=False, a=azon: self._futtat(a)) + self.kartyak[azon] = kartya + self.racs.hozzaad(kartya) + doboz.addWidget(self.racs) + doboz.addStretch(1) + + def megjelenik(self, *_): + helper = muveletek.helper_elerheto() + self.figyelem.setText("A RaveOS Center rendszerhelpere nincs telepítve, a műveletek nem futtathatók.") + self.figyelem.setVisible(not helper) + for azon in self.kartyak: + self._ellenoriz(azon) + + def _ellenoriz(self, azon): + kartya = self.kartyak[azon] + if tarolt(f"karbantartas_{azon}") is None: + kartya.gomb.setEnabled(False) + kartya.osszegzes.setText("Ellenőrzés...") + gyorsitott( + f"karbantartas_{azon}", + karbantartas.ELONEZETEK[azon], + kesz=lambda adat, a=azon: self._kesz(a, adat), + hiba=lambda uzenet, a=azon: self._kesz(a, {"elerheto": False, "osszegzes": uzenet, "elemek": []}), + kor=60, + ) + + def _kesz(self, azon, adat): + self.adat[azon] = adat + kartya = self.kartyak[azon] + kartya.osszegzes.setText(adat["osszegzes"]) + torlo = next(m[4] for m in MUVELETEK if m[0] == azon) + teendo = not torlo or azon == "naplo" or bool(adat["elemek"]) + kartya.gomb.setEnabled(adat["elerheto"] and teendo and muveletek.helper_elerheto()) + + def _futtat(self, azon): + adat = self.adat.get(azon) + if not adat: + return + nev = next(m[2] for m in MUVELETEK if m[0] == azon) + kivalasztott = None + if azon == "cache": + szoveg = f"Ezek a csomagfájlok törlődnek a cache-ből ({adat['osszegzes']}). A telepített programokat nem érinti." + elif azon == "arva": + szoveg = ( + "Pontosan ezek a csomagok törlődnek, más nem. Vedd ki a pipát annál, amit megtartanál. " + "Utána újabb árva függőségek jelenhetnek meg, ezeket a kártya újra megmutatja." + ) + elif azon == "naplo": + szoveg = f"{adat['osszegzes']}. A két hétnél régebbi naplók törlődnek, és legfeljebb 100 MB marad." + elif azon == "flatpak": + szoveg = "Ezek a runtime-ok törlődnek. Az alkalmazásaid továbbra is működnek." + else: + szoveg = "" + if szoveg: + ablak = ElonezetAblak(self, nev, szoveg, adat["elemek"], azon == "arva", "Törlés") + if ablak.exec() != QDialog.DialogCode.Accepted: + return + if azon == "arva": + kivalasztott = ablak.kivalasztott() + lepesek = karbantartas.lepesek(azon, adat, kivalasztott) + if not lepesek: + return + FolyamatAblak(self, nev, lepesek, "A művelet elkészült.").exec() + self._ellenoriz(azon) + + +FUL = Karbantartas diff --git a/raveos-center/raveos_center/oldalak/rendszer/mentes.py b/raveos-center/raveos_center/oldalak/rendszer/mentes.py new file mode 100644 index 0000000..6ad5967 --- /dev/null +++ b/raveos-center/raveos_center/oldalak/rendszer/mentes.py @@ -0,0 +1,283 @@ +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 diff --git a/raveos-center/raveos_center/oldalak/rendszer/secureboot.py b/raveos-center/raveos_center/oldalak/rendszer/secureboot.py new file mode 100644 index 0000000..00ca444 --- /dev/null +++ b/raveos-center/raveos_center/oldalak/rendszer/secureboot.py @@ -0,0 +1,256 @@ +import shutil +import subprocess + +from PyQt6.QtWidgets import QHBoxLayout, QMessageBox, QPlainTextEdit, QVBoxLayout, QWidget + +from raveos_center import muveletek +from raveos_center.elemek import Kartya, Racs, cimke, gomb +from raveos_center.hatter import ervenytelenit, gyorsitott, tarolt + +AZON = "secureboot" +CIM = "Secure Boot" + +SZKRIPT = "raveos-secureboot-setup" +UJRAINDITAS_KELL = 10 + +LEPESEK_SZOVEG = [ + "telepíti a szükséges eszközöket (sbsigntools, efitools),", + "létrehoz egy saját, csak ehhez a géphez tartozó aláíró kulcsot,", + "aláírja a rendszerbetöltőt, a kernelt és a külső kernelmodulokat (pl. NVIDIA),", + "beírja a firmware-be a RaveOS, a Microsoft és a saját géped kulcsát, így a Windows is tovább indul,", + "beállít egy automatikus aláírást, ami minden kernelfrissítés után újra aláír.", +] + + +def allapot_lekerdez(): + if not shutil.which(SZKRIPT): + return None + kimenet = subprocess.run([SZKRIPT, "--status"], capture_output=True, text=True, timeout=30) + adat = {} + for sor in kimenet.stdout.splitlines(): + if "=" in sor and not sor.startswith("["): + k, _, v = sor.partition("=") + adat[k.strip()] = v.strip() + if not adat and "Nem UEFI" in kimenet.stdout: + adat["uefi"] = "0" + return adat + + +class SecureBoot(QWidget): + def __init__(self, kozpont): + super().__init__() + self.kozpont = kozpont + doboz = QVBoxLayout(self) + doboz.setContentsMargins(0, 20, 0, 0) + doboz.setSpacing(16) + doboz.addWidget( + cimke( + "A Secure Boot csak aláírt rendszerbetöltőt és kernelt enged elindulni. Akkor hasznos, ha a gépen " + "Windows is van, és ott olyan játék vagy program fut, ami bekapcsolt Secure Bootot kér (például egyes " + "csalásvédelmek vagy a Windows 11). A beállítás után a RaveOS és a Windows is elindul.", + "masodlagos", + True, + ) + ) + oszlopok = QHBoxLayout() + oszlopok.setSpacing(24) + bal = QVBoxLayout() + bal.setSpacing(12) + oszlopok.addLayout(bal, 3) + doboz.addLayout(oszlopok, 1) + self.racs = Racs(110, 10) + self.ertekek = {} + for kulcs, nev in ( + ("secureboot", "Secure Boot"), + ("setupmode", "Setup Mode"), + ("keys", "Gépkulcs"), + ("signed", "Aláírások"), + ): + k = Kartya(nev, terkoz=6, margo=14) + ertek = cimke("...", "nagyszam") + k.elrendezes.addWidget(ertek) + self.ertekek[kulcs] = ertek + self.racs.hozzaad(k) + bal.addWidget(self.racs) + self.figyelem = cimke("", "figyelem", True) + self.figyelem.hide() + bal.addWidget(self.figyelem) + bal.addWidget( + cimke( + "FIGYELEM, BITLOCKER: ha a gépen Windows is van BitLockerrel, a beállítás előtt a Windowsban függeszd " + "fel a BitLockert (manage-bde -protectors -disable C: -rebootcount 2), vagy legyen kéznél a 48 jegyű " + "helyreállítási kulcs. Enélkül a Windows a következő indításkor ezt a kulcsot fogja kérni.", + "figyelem", + True, + ) + ) + + leiras = Kartya("A beállítás lépései", terkoz=6) + leiras.elrendezes.addWidget(cimke("A Beállítás gomb egymás után:", "masodlagos")) + for i, szoveg in enumerate(LEPESEK_SZOVEG, 1): + sor = QHBoxLayout() + sor.setSpacing(10) + jel = cimke(f"{i}.", "monozold") + jel.setFixedWidth(22) + sor.addWidget(jel) + sor.addWidget(cimke(szoveg, "masodlagos", True), 1) + leiras.elrendezes.addLayout(sor) + leiras.elrendezes.addSpacing(6) + leiras.elrendezes.addWidget( + cimke( + "Ehhez a firmware-nek Setup Mode-ban kell lennie: a BIOS/UEFI beállításokban töröld a Secure Boot " + "kulcsokat (Clear Secure Boot keys / Reset to Setup Mode). Ha nincs Setup Mode-ban, a Center szól, " + "és újraindítás után a beállítás magától folytatódik.", + "halvany", + True, + ) + ) + + leiras.setMinimumWidth(300) + leiras.setMaximumWidth(420) + jobb = QVBoxLayout() + jobb.addWidget(leiras) + jobb.addStretch(1) + oszlopok.addLayout(jobb, 2) + + gombok = QHBoxLayout() + gombok.setSpacing(8) + self.frissit_gomb = gomb("Állapot frissítése") + self.frissit_gomb.clicked.connect(self.frissit) + self.ujra_gomb = gomb("Újra aláírás") + self.ujra_gomb.setToolTip("Ha a gépkulcs már megvan, csak újra aláírja a rendszerbetöltőt, a kernelt és a modulokat.") + self.ujra_gomb.clicked.connect(lambda: self._futtat("resign", "Újra aláírás")) + self.beallit_gomb = gomb("Beállítás", fo=True) + self.beallit_gomb.clicked.connect(self._beallit) + gombok.addWidget(self.frissit_gomb) + gombok.addStretch(1) + gombok.addWidget(self.ujra_gomb) + gombok.addWidget(self.beallit_gomb) + bal.addLayout(gombok) + + bal.addWidget(cimke("NAPLÓ", "h2")) + self.naplo = QPlainTextEdit() + self.naplo.setObjectName("naplo") + self.naplo.setReadOnly(True) + self.naplo.setMinimumHeight(80) + bal.addWidget(self.naplo, 1) + + self.futtato = muveletek.Futtato(self) + self.futtato.sor.connect(self.naplo.appendPlainText) + self.futtato.kesz.connect(self._kesz) + self.adat = {} + + def megjelenik(self, *_): + self._betolt() + + def frissit(self): + ervenytelenit("secureboot") + self._betolt() + + def _betolt(self): + if tarolt("secureboot") is None: + for e in self.ertekek.values(): + e.setText("...") + gyorsitott( + "secureboot", allapot_lekerdez, kesz=self._allapot, + hiba=lambda u: self._hiba(f"Az állapot nem olvasható: {u}"), kor=60, + ) + + def _hiba(self, szoveg): + self.figyelem.setText(szoveg) + self.figyelem.show() + + def _allapot(self, adat): + self.adat = adat or {} + self.figyelem.hide() + if adat is None: + for e in self.ertekek.values(): + e.setText("-") + self._hiba("A Secure Boot beállító (raveos-secureboot-setup) nincs telepítve.") + self._gombok(False) + return + if adat.get("uefi") == "0": + for e in self.ertekek.values(): + e.setText("-") + self._hiba("Ez a gép nem UEFI módban indult, ezért a Secure Boot nem érhető el.") + self._gombok(False) + return + def ki(ertek, igen, nem): + return igen if ertek == "1" else nem if ertek == "0" else "?" + self._beir("secureboot", ki(adat.get("secureboot"), "BE", "KI"), adat.get("secureboot") == "1") + self._beir("setupmode", ki(adat.get("setupmode"), "IGEN", "NEM"), adat.get("setupmode") == "1") + self._beir("keys", ki(adat.get("keys"), "MEGVAN", "NINCS"), adat.get("keys") == "1") + self._beir("signed", ki(adat.get("signed"), "RENDBEN", "HIÁNYZIK"), adat.get("signed") == "1") + if adat.get("pending") == "1": + self._hiba("A beállítás félbemaradt, és a következő újraindításkor magától folytatódik.") + self._gombok(True) + + def _beir(self, kulcs, szoveg, zold): + e = self.ertekek[kulcs] + e.setText(szoveg) + e.setProperty("zold", zold) + e.style().unpolish(e) + e.style().polish(e) + + def _gombok(self, elerheto): + fut = self.futtato.fut() + helper = muveletek.helper_elerheto() + self.beallit_gomb.setEnabled(elerheto and helper and not fut) + self.ujra_gomb.setEnabled(elerheto and helper and not fut and self.adat.get("keys") == "1") + self.frissit_gomb.setEnabled(not fut) + + def _beallit(self): + valasz = QMessageBox.question( + self, + "Secure Boot beállítása", + "A beállítás kulcsokat ír a firmware-be, és aláírja a rendszerbetöltőt és a kernelt. " + "Ha Windows is van a gépen BitLockerrel, előtte függeszd fel a BitLockert.\n\nFolytatod?", + QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, + QMessageBox.StandardButton.No, + ) + if valasz == QMessageBox.StandardButton.Yes: + self._futtat("setup", "Secure Boot beállítása") + + def _futtat(self, mod, cimke_szoveg): + self.naplo.clear() + self._gombok(False) + self.futtato.indit([muveletek.Lepes(cimke_szoveg, muveletek.root("secureboot", mod))]) + + def _bios_ujrainditas(self, cim, szoveg): + doboz = QMessageBox(self) + doboz.setWindowTitle(cim) + doboz.setText(szoveg) + most = doboz.addButton("Újraindítás a BIOS-ba", QMessageBox.ButtonRole.AcceptRole) + doboz.addButton("Később", QMessageBox.ButtonRole.RejectRole) + doboz.exec() + if doboz.clickedButton() is most: + muveletek.Futtato(self).indit( + [ + muveletek.Lepes( + "Újraindítás a firmware beállításaiba", + ["bash", "-c", "systemctl reboot --firmware-setup || systemctl reboot"], + ) + ] + ) + + def _kesz(self, rendben, _hibasak): + kod = self.futtato.utolso_kod + if rendben: + self._bios_ujrainditas( + "Secure Boot", + "Az aláírások és a kulcsok készen vannak.\n\nA BIOS-ban állítsd a Secure Bootot Enabled-re, " + "majd mentsd el a beállítást és indítsd újra a gépet.", + ) + elif kod == UJRAINDITAS_KELL: + self._bios_ujrainditas( + "Újraindítás szükséges", + "A firmware nincs Setup Mode-ban.\n\nA BIOS-ban a Secure Boot menüben töröld a kulcsokat " + "(Key Management, Clear Secure Boot keys), így a gép Setup Mode-ba kerül. Mentés után indítsd újra " + "a gépet: a beállítás indítás után magától befejeződik.", + ) + else: + QMessageBox.warning(self, "Secure Boot", "A művelet nem sikerült. A részleteket a napló mutatja.") + self.frissit() + + +FUL = SecureBoot diff --git a/raveos-center/raveos_center/oldalak/rendszer/snapshotok.py b/raveos-center/raveos_center/oldalak/rendszer/snapshotok.py new file mode 100644 index 0000000..8d9b08c --- /dev/null +++ b/raveos-center/raveos_center/oldalak/rendszer/snapshotok.py @@ -0,0 +1,247 @@ +from PyQt6.QtCore import QProcess, Qt +from PyQt6.QtWidgets import QHBoxLayout, QInputDialog, QLineEdit, QMessageBox, QVBoxLayout, QWidget + +from raveos_center import muveletek, snapshotok +from raveos_center.elemek import Kartya, cimke, gomb +from raveos_center.folyamat import FolyamatAblak +from raveos_center.hatter import ervenytelenit, gyorsitott, tarolt + +AZON = "snapshotok" +CIM = "Snapshotok" + + +class SnapshotSor(QWidget): + def __init__(self, elem, utolso, visszaallit, torol): + super().__init__() + self.setObjectName("appsor") + self.setProperty("utolso", utolso) + self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True) + sor = QHBoxLayout(self) + sor.setContentsMargins(16, 12, 16, 12) + sor.setSpacing(16) + datum = cimke(elem["datum"], "mono") + datum.setFixedWidth(150) + sor.addWidget(datum) + szovegek = QVBoxLayout() + szovegek.setSpacing(2) + szovegek.addWidget(cimke(elem["leiras"] or "-", None, True)) + szovegek.addWidget(cimke(f"#{elem['szam']} {elem['tipus_nev']}", "monohalvany")) + sor.addLayout(szovegek, 1) + helper = muveletek.helper_elerheto() + vissza = gomb("Visszaállítás", kicsi=True) + vissza.setEnabled(helper) + vissza.clicked.connect(lambda: visszaallit(elem)) + sor.addWidget(vissza, 0, Qt.AlignmentFlag.AlignVCenter) + torles = gomb("Törlés", kicsi=True) + torles.setEnabled(helper) + torles.clicked.connect(lambda: torol(elem)) + sor.addWidget(torles, 0, Qt.AlignmentFlag.AlignVCenter) + + +class Snapshotok(QWidget): + def __init__(self, kozpont): + super().__init__() + self.kozpont = kozpont + self.adat = None + doboz = QVBoxLayout(self) + doboz.setContentsMargins(0, 20, 0, 0) + doboz.setSpacing(16) + fej = QHBoxLayout() + fej.setSpacing(16) + self.leiras = cimke( + "A btrfs snapshot a rendszer egy pillanatnyi állapota. Ha egy frissítés után gond van, egy korábbi " + "állapotra vissza tudsz állni. A saját fájljaidat (/home) a visszaállítás nem érinti.", + "masodlagos", + True, + ) + fej.addWidget(self.leiras, 1) + self.uj_gomb = gomb("Új snapshot", fo=True) + self.uj_gomb.clicked.connect(self.uj) + fej.addWidget(self.uj_gomb, 0, Qt.AlignmentFlag.AlignTop) + doboz.addLayout(fej) + self.info = cimke("", "monozold", True) + self.info.hide() + doboz.addWidget(self.info) + self.figyelem = cimke("", "figyelem", True) + self.figyelem.hide() + doboz.addWidget(self.figyelem) + self.beallitas_gomb = gomb("Snapper beállítása", fo=True) + self.beallitas_gomb.clicked.connect(self._beallitas) + self.beallitas_gomb.hide() + gs = QHBoxLayout() + gs.addWidget(self.beallitas_gomb) + gs.addStretch(1) + doboz.addLayout(gs) + self.kartya = Kartya(terkoz=0, margo=0) + doboz.addWidget(self.kartya) + doboz.addStretch(1) + + def megjelenik(self, *args): + if tarolt("snapshotok") is None: + self.uj_gomb.setEnabled(False) + self._info("Betöltés...") + gyorsitott("snapshotok", snapshotok.allapot, kesz=self._kesz, hiba=self._hiba, kor=30) + if args and args[0] == "uj": + self.uj() + + def frissit(self): + ervenytelenit("snapshotok", "snapshot") + gyorsitott("snapshotok", snapshotok.allapot, kesz=self._kesz, hiba=self._hiba) + + def _hiba(self, uzenet): + self._figyelmeztet(f"A snapshotok nem olvashatók: {uzenet}") + + def _info(self, szoveg): + self.info.setText(szoveg) + self.info.setVisible(bool(szoveg)) + + def _figyelmeztet(self, szoveg): + self.figyelem.setText(szoveg) + self.figyelem.setVisible(bool(szoveg)) + + def _kesz(self, adat): + self.adat = adat + helper = muveletek.helper_elerheto() + kesz = adat["fajlrendszer"] == "btrfs" and adat["snapper"] + self.uj_gomb.setVisible(kesz) + self.uj_gomb.setEnabled(kesz and helper) + self.beallitas_gomb.setVisible(snapshotok.snapper_telepitheto(adat)) + self.beallitas_gomb.setEnabled(helper) + self.kartya.setVisible(kesz) + if adat["fajlrendszer"] != "btrfs": + self._info("") + self._figyelmeztet( + f"Snapshothoz btrfs fájlrendszer kell. Ez a gép {adat['fajlrendszer'] or 'ismeretlen'} fájlrendszert " + "használ, ezért itt nem érhető el. A RaveOS telepítésekor a lemez partícionálásánál ext4 és btrfs " + "közül lehet választani: ha snapshotot szeretnél, a btrfs-t válaszd." + ) + return + if not adat["snapper"]: + self._info("") + if snapshotok.snapper_telepitheto(adat): + self._figyelmeztet( + "A gép btrfs-t használ, de a snapper még nincs beállítva. Egy kattintással beállítható: " + "utána minden csomagművelet előtt automatikusan snapshot készül." + ) + else: + self._figyelmeztet( + "A gép btrfs-t használ, de az alvolumen-elrendezése eltér a RaveOS-étól (@ és @snapshots), " + "ezért a snapper itt nem állítható be automatikusan." + ) + return + if adat["alvolumen"] != "/@": + self._figyelmeztet("A rendszer most nem a fő alvolumenről (@) fut, ezért visszaállítás nem indítható.") + elif adat["hiba"]: + self._figyelmeztet(adat["hiba"]) + elif not helper: + self._figyelmeztet("A RaveOS Center rendszerhelpere nincs telepítve, ezért snapshot nem kezelhető.") + else: + self._figyelmeztet("") + self._info( + ("Automatikus snapshot minden csomagművelet előtt és után (snap-pac). " if adat["snap_pac"] else "") + + f"{len(adat['lista'])} snapshot, a régiek automatikusan törlődnek." + ) + self._lista(adat) + + def _lista(self, adat): + elrendezes = self.kartya.elrendezes + while elrendezes.count(): + w = elrendezes.takeAt(0).widget() + if w: + w.deleteLater() + if not adat["lista"]: + ures = cimke("Még nincs snapshot.", "halvany") + ures.setContentsMargins(16, 16, 16, 16) + elrendezes.addWidget(ures) + return + for i, elem in enumerate(adat["lista"]): + elrendezes.addWidget(SnapshotSor(elem, i == len(adat["lista"]) - 1, self.visszaallit, self.torol)) + + def _futtat(self, cim, lepes, siker): + ablak = FolyamatAblak(self, cim, [lepes], siker) + ablak.exec() + self.frissit() + return ablak.rendben + + def uj(self): + if not self.adat or not self.uj_gomb.isEnabled(): + return + leiras, ok = QInputDialog.getText( + self, "Új snapshot", "Leírás (például: Driver csere előtt):", QLineEdit.EchoMode.Normal, "Kézi snapshot" + ) + leiras = leiras.strip() + if not ok: + return + if not snapshotok.ervenyes_leiras(leiras): + QMessageBox.warning(self, "Új snapshot", "A leírás 1-80 karakter lehet: betűk, számok, szóköz és . _ : , ( ) -") + return + self._futtat("Új snapshot", muveletek.Lepes("Snapshot készítése", muveletek.root("snapshot", leiras)), "A snapshot elkészült.") + + def torol(self, elem): + if QMessageBox.question( + self, "Snapshot törlése", f"Törlöd a(z) #{elem['szam']} snapshotot?\n{elem['datum']} {elem['leiras']}" + ) != QMessageBox.StandardButton.Yes: + return + self._futtat( + "Snapshot törlése", + muveletek.Lepes("Snapshot törlése", muveletek.root("snapshot-torles", str(elem["szam"]))), + "A snapshot törölve.", + ) + + def visszaallit(self, elem): + kernelek = snapshotok.kernel_valtozas(elem["szam"]) + ellenorizheto = kernelek is not None + kernelek = kernelek or [] + hianyzo = [k for k in kernelek if not k["cache"]] + if hianyzo: + QMessageBox.warning( + self, + "Visszaállítás", + "Ennek a snapshotnak a kernelcsomagja már nincs meg a csomag-cache-ben " + f"({', '.join(k['nev'] + ' ' + k['regi'] for k in hianyzo)}), ezért a visszaállított rendszer nem " + "indulna el. Válassz újabb snapshotot.", + ) + return + kernel_szoveg = "".join(f"\n- {k['nev']}: {k['most'] or 'nincs'} -> {k['regi']}" for k in kernelek) + szoveg = ( + f"A rendszer visszaáll erre az állapotra:\n#{elem['szam']} {elem['datum']} {elem['leiras']}\n\n" + "A saját fájljaid (/home) nem változnak. A mostani rendszer a következő visszaállításig megmarad " + "tartalékként. A változás újraindítás után lép életbe." + + (f"\n\nA kernel is visszaáll:{kernel_szoveg}" if kernelek else "") + + ("" if ellenorizheto else "\n\nA snapshot kernelverziója innen nem olvasható, a visszaállítás előtt a rendszer " + "ellenőrzi, és ha a kernelcsomag hiányzik, nem végzi el.") + + "\n\nFolytatod?" + ) + if QMessageBox.question(self, "Visszaállítás", szoveg) != QMessageBox.StandardButton.Yes: + return + rendben = self._futtat( + "Visszaállítás", + muveletek.Lepes("Snapshot visszaállítása", muveletek.root("snapshot-visszaallit", str(elem["szam"]))), + "A visszaállítás elkészült. Indítsd újra a gépet.", + ) + if not rendben: + return + doboz = QMessageBox(self) + doboz.setWindowTitle("Visszaállítás") + doboz.setIcon(QMessageBox.Icon.Warning) + doboz.setText( + "A visszaállítás újraindítás után lép életbe. Amit addig a gépen változtatsz (telepítés, beállítás, " + "rendszerfájlok), az a tartalék rendszerbe kerül, és elvész. A /home-ban lévő fájljaid megmaradnak.\n\n" + "Javasolt most újraindítani." + ) + most = doboz.addButton("Újraindítás most", QMessageBox.ButtonRole.AcceptRole) + doboz.addButton("Később", QMessageBox.ButtonRole.RejectRole) + doboz.setDefaultButton(most) + doboz.exec() + if doboz.clickedButton() is most: + QProcess.startDetached("systemctl", ["reboot"]) + + def _beallitas(self): + self._futtat( + "Snapper beállítása", + muveletek.Lepes("Snapper beállítása", muveletek.root("snapper-beallitas")), + "A snapper beállítva, az első snapshot elkészült.", + ) + + +FUL = Snapshotok |