/** * Öffnen und Anzeigen von Dateien, die diese Anwendung selbst geschrieben hat. * * **Wozu.** Alle Druckausgaben und die Sicherung endeten bis 0.22.0 mit einem * reinen Textsatz samt Pfad: „Der Lernbericht wurde gespeichert: …“. Wer die * eben erzeugte Fragenliste drucken oder die Sicherung auf einen Stick ziehen * wollte, musste den Pfad ablesen und im Explorer selbst hinnavigieren — nach * „Speichern unter“ die unbequemste Fortsetzung, die ein Programm anbieten * kann. * * **Warum eine Merkliste und keine Pfadprüfung.** Der Renderer schickt keinen * Pfad, sondern eine Kennung: Wer einen Pfad mitbringen darf, darf auch einen * anderen mitbringen — dieselbe Überlegung wie beim unterbrochenen * Prüfungsbogen und beim Einspielweg der Sicherung. Der Hauptprozess merkt * sich, was er in dieser Sitzung selbst geschrieben hat, und öffnet * ausschließlich das. Eine Prüfung „liegt der Pfad unter Dokumente?“ wäre * schwächer: Auch dort kann etwas liegen, das diese Anwendung nichts angeht. * * **Was hier nicht passiert.** `shell.openPath` überlässt dem Betriebssystem, * womit eine Datei geöffnet wird. Das ist bei einem PDF gewollt und bei einer * Datei unbekannter Herkunft eine Einladung — deshalb kommt in die Merkliste * nur, was diese Anwendung soeben selbst erzeugt hat. */ import { existsSync } from 'node:fs'; import { shell } from 'electron'; /** * Was in dieser Sitzung geschrieben wurde, mit Kennung. * * Nur im Arbeitsspeicher: Nach einem Neustart ist die Liste leer, und ein * alter Verweis führt dann nirgendwohin — richtig so, die Datei kann * inzwischen verschoben oder gelöscht sein. */ const geschrieben = new Map(); let zaehler = 0; /** * Merkt einen geschriebenen Pfad und gibt die Kennung zurück, unter der der * Renderer ihn öffnen lassen darf. */ export function geschriebenMerken(pfad: string): string { zaehler += 1; const kennung = `datei-${String(zaehler)}`; geschrieben.set(kennung, pfad); return kennung; } /** Was zu tun ist. */ export type Dateiwunsch = 'oeffnen' | 'ordner'; /** * Öffnet die Datei oder zeigt sie im Dateimanager. * * @returns `false`, wenn die Kennung unbekannt ist oder das System die Datei * nicht öffnen konnte – etwa weil sie inzwischen verschoben wurde. */ export async function dateiZeigen(kennungRoh: unknown, wunsch: Dateiwunsch): Promise { const kennung = typeof kennungRoh === 'string' ? kennungRoh : ''; const pfad = geschrieben.get(kennung); if (pfad === undefined) { return false; } if (wunsch === 'ordner') { /* Zeigt den Ordner und markiert die Datei darin. Liefert nichts zurück – ob es geklappt hat, ist von hier aus nicht feststellbar. */ shell.showItemInFolder(pfad); return true; } /* `openPath` liefert eine leere Zeichenkette bei Erfolg und sonst die Fehlermeldung des Systems. */ const fehler = await shell.openPath(pfad); if (fehler !== '') { console.warn(`[datei] konnte nicht geöffnet werden: ${fehler}`); return false; } return true; } /** * Öffnet einen Ordner im Dateimanager. * * **Warum ein Pfad und keine Kennung.** {@link dateiZeigen} nimmt bewusst nur * eine Kennung entgegen: Was der Renderer schickt, darf nie ein Pfad sein. * Diese Funktion ist das Gegenstück für den umgekehrten Fall – der Pfad * stammt aus dem Hauptprozess selbst und wird nie aus einer Anfrage gebildet. * Wer sie ruft, muss dafür einstehen; der Kanal darüber nimmt deshalb gar * kein Argument an. * * @returns `false`, wenn es den Ordner nicht gibt oder das System ihn nicht * öffnen konnte. Der Ordner der selbsttätigen Kopien entsteht erst mit der * ersten Kopie – bis dahin gibt es nichts zu zeigen, und das ist kein * Fehler, sondern eine Auskunft. */ export async function ordnerZeigen(pfad: string): Promise { if (!existsSync(pfad)) { return false; } const fehler = await shell.openPath(pfad); if (fehler !== '') { console.warn(`[datei] Ordner ließ sich nicht öffnen: ${fehler}`); return false; } return true; } /** Gegenstück für Tests. */ export function geschriebeneVergessen(): void { geschrieben.clear(); zaehler = 0; }