Ergebnis Code BOPRO2

Dieser Code stellt eine komplette Anwendung dar, die es ermöglicht, Fahrer und deren Fahrten zu verwalten. Die KilometerVerwaltung-Klasse liest die kilometer.csv-Datei ein und speichert die Daten in einer Map. Die FahrAwayGUI-Klasse stellt die Benutzeroberfläche bereit, in der Fahrer ausgewählt und deren Fahrten angezeigt werden können. Neue Fahrten können über die Eingabefelder und den „Fahrt erfassen“-Button hinzugefügt werden. Der FahrtenUpdater-Thread überwacht die addfahrten.csv-Datei, liest neue Fahrten ein und aktualisiert die Daten der Anwendung. Die GUI wird automatisch aktualisiert, wenn neue Fahrten hinzugefügt werden. Der FahrtenUpdater-Thread wird beim Schließen der Anwendung ordnungsgemäß gestoppt.

// FahrAway Kilometerverwaltung
// Version 3.11
// Datum 21.04.2024
// André Reichert-Creutz
 
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
 
// Klasse, um Informationen über einen Fahrer zu speichern
class Fahrer {
    private String personalnummer;
    private String vorname;
    private String nachname;
    private List<Fahrt> fahrten;
 
    public Fahrer(String personalnummer, String vorname, String nachname) {
        this.personalnummer = personalnummer;
        this.vorname = vorname;
        this.nachname = nachname;
        this.fahrten = new ArrayList<>();
    }
 
    // Getter-Methoden für Fahrerinformationen
    public String getPersonalnummer() {
        return personalnummer;
    }
 
    public String getVorname() {
        return vorname;
    }
 
    public String getNachname() {
        return nachname;
    }
 
    // Methode, um eine Fahrt zum Fahrer hinzuzufügen
    public void addFahrt(Fahrt fahrt) {
        fahrten.add(fahrt);
        fahrten.sort(null); // Sortiere die Fahrten nach Datum
    }
 
    // Getter-Methode für die Liste der Fahrten des Fahrers
    public List<Fahrt> getFahrten() {
        return fahrten;
    }
 
    // Überschriebene toString-Methode für die Darstellung eines Fahrers
    @Override
    public String toString() {
        return personalnummer + " - " + vorname + " " + nachname;
    }
}
 
// Klasse, um Informationen über eine Fahrt zu speichern
class Fahrt implements Comparable<Fahrt> {
    private String personalnummer;
    private LocalDate datum;
    private String startort;
    private int kilometer;
 
    public Fahrt(String personalnummer, LocalDate datum, String startort, int kilometer) {
        this.personalnummer = personalnummer;
        this.datum = datum;
        this.startort = startort;
        this.kilometer = kilometer;
    }
 
    // Getter-Methoden für Fahrtinformationen
    public String getPersonalnummer() {
        return personalnummer;
    }
 
    public LocalDate getDatum() {
        return datum;
    }
 
    public String getStartort() {
        return startort;
    }
 
    public int getKilometer() {
        return kilometer;
    }
 
    // Vergleichsmethode, um Fahrten nach Datum zu sortieren
    @Override
    public int compareTo(Fahrt other) {
        return this.datum.compareTo(other.datum);
    }
 
    // Überschriebene toString-Methode für die Darstellung einer Fahrt
    @Override
    public String toString() {
        return String.format("%s - %s - %d km", datum.format(DateTimeFormatter.ISO_LOCAL_DATE), startort, kilometer);
    }
}
 
// Klasse zur Verwaltung der Kilometerdaten
class KilometerVerwaltung {
    private static final String CSV_FILE = "kilometer.csv";
    private static final String ADD_FAHRTEN_CSV = "addfahrten.csv";
    private Map<String, Fahrer> fahrerMap = new HashMap<>();
 
    // Methode zum Einlesen der CSV-Datei
    public void einlesenCsvDatei() {
        try (BufferedReader br = new BufferedReader(new FileReader(CSV_FILE))) {
            String line;
            while ((line = br.readLine()) != null) {
                String[] data = line.split(",");
                if (data[0].equals("Fahrer")) {
                    Fahrer fahrer = new Fahrer(data[1], data[2], data[3]);
                    fahrerMap.put(data[1], fahrer);
                } else if (data[0].equals("Fahrt")) {
                    LocalDate datum = LocalDate.parse(data[2], DateTimeFormatter.ISO_LOCAL_DATE);
                    Fahrt fahrt = new Fahrt(data[1], datum, data[3], Integer.parseInt(data[4]));
                    Fahrer fahrer = fahrerMap.get(data[1]);
                    if (fahrer != null) {
                        fahrer.addFahrt(fahrt);
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    // Methode zum Speichern der CSV-Datei
    public void speichernCsvDatei() {
        try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(CSV_FILE)))) {
            out.println("Fahrer,Personalnummer,Vorname,Nachname");
            for (Fahrer fahrer : fahrerMap.values()) {
                out.printf("Fahrer,%s,%s,%s%n", fahrer.getPersonalnummer(), fahrer.getVorname(), fahrer.getNachname());
            }
            out.println("Fahrt,Personalnummer,Datum,Startort,Kilometer");
            for (Fahrer fahrer : fahrerMap.values()) {
                for (Fahrt fahrt : fahrer.getFahrten()) {
                    out.printf("Fahrt,%s,%s,%s,%d%n", fahrt.getPersonalnummer(), fahrt.getDatum().format(DateTimeFormatter.ISO_LOCAL_DATE), fahrt.getStartort(), fahrt.getKilometer());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    // Getter-Methode für die Fahrer-Map
    public Map<String, Fahrer> getFahrerMap() {
        return fahrerMap;
    }
 
    // Methode zur Überprüfung der Existenz einer Datei
    public boolean checkFileExistence(String filename) {
        File file = new File(filename);
        return file.exists() && file.isFile();
    }
 
    // Methode zur Überprüfung der Schreibbarkeit einer Datei
    public boolean checkFileWritable(String filename) {
        File file = new File(filename);
        return file.exists() && file.canWrite();
    }
}
 
// Klasse zur Aktualisierung der Fahrten im Hintergrund
class FahrtenUpdater implements Runnable {
    private KilometerVerwaltung kilometerVerwaltung;
 
    public FahrtenUpdater(KilometerVerwaltung kilometerVerwaltung) {
        this.kilometerVerwaltung = kilometerVerwaltung;
    }
 
    // Methode zum kontinuierlichen Aktualisieren der Fahrten
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                // Überprüfe, ob die CSV-Datei existiert und beschreibbar ist
                if (kilometerVerwaltung.checkFileExistence(KilometerVerwaltung.ADD_FAHRTEN_CSV) && kilometerVerwaltung.checkFileWritable(KilometerVerwaltung.ADD_FAHRTEN_CSV)) {
                    List<String> fahrtenLines = Files.readAllLines(Paths.get(KilometerVerwaltung.ADD_FAHRTEN_CSV));
                    for (String line : fahrtenLines) {
                        String[] data = line.split(",");
                        LocalDate datum = LocalDate.parse(data[1], DateTimeFormatter.ISO_LOCAL_DATE);
                        int kilometer = Integer.parseInt(data[3]);
                        if (kilometer < 0) {
                            throw new IllegalArgumentException("Negative Kilometeranzahl");
                        }
                        Fahrt fahrt = new Fahrt(data[0], datum, data[2], kilometer);
                        Fahrer fahrer = kilometerVerwaltung.getFahrerMap().get(data[0]);
                        if (fahrer != null) {
                            fahrer.addFahrt(fahrt);
                        } else {
                            System.out.println("Fahrer mit Personalnummer " + data[0] + " nicht gefunden.");
                        }
                    }
                    Files.delete(Paths.get(KilometerVerwaltung.ADD_FAHRTEN_CSV));
                    // Aktualisiere die GUI nach dem Einlesen neuer Fahrten
                    if (FahrAwayGUI.getInstance() != null) {
                        FahrAwayGUI.getInstance().aktualisiereGUI();
                    }
                }
                // Warte eine Minute, bevor der nächste Aktualisierungsschritt erfolgt
                Thread.sleep(60000);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
 
// Haupt-GUI-Klasse für die Benutzeroberfläche
public class FahrAwayGUI {
    private JFrame frame;
    private JComboBox<Fahrer> fahrerComboBox;
    private JTextArea fahrtenTextArea;
    private JTextField datumTextField, startortTextField, kilometerTextField;
    private JButton erfassenButton, beendenButton;
    private JLabel gesamtKilometerLabel;
    private KilometerVerwaltung kilometerVerwaltung;
    private static FahrAwayGUI instance;
    private Thread fahrtenUpdaterThread;
 
    // Konstruktor für die GUI
    public FahrAwayGUI(KilometerVerwaltung kilometerVerwaltung) {
        this.kilometerVerwaltung = kilometerVerwaltung;
        frame = new JFrame("FahrAway Kilometerverwaltung");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
 
        // Initialisiere GUI-Komponenten
        fahrerComboBox = new JComboBox<>();
        fahrtenTextArea = new JTextArea(10, 30);
        fahrtenTextArea.setEditable(false);
        datumTextField = new JTextField(10);
        startortTextField = new JTextField(10);
        kilometerTextField = new JTextField(10);
        erfassenButton = new JButton("Fahrt erfassen");
        beendenButton = new JButton("Beenden");
        gesamtKilometerLabel = new JLabel("Gesamtkilometer: 0");
 
        // Panel für Fahrer-Auswahl und Fahrt-Erfassung
        JPanel northPanel = new JPanel();
        northPanel.add(fahrerComboBox);
        northPanel.add(erfassenButton);
 
        // Panel für die Anzeige der Fahrten
        JPanel centerPanel = new JPanel();
        centerPanel.add(new JScrollPane(fahrtenTextArea));
 
        // Panel für die Eingabe neuer Fahrten und Beenden-Button
        JPanel southPanel = new JPanel();
        southPanel.add(new JLabel("Datum:"));
        southPanel.add(datumTextField);
        southPanel.add(new JLabel("Startort:"));
        southPanel.add(startortTextField);
        southPanel.add(new JLabel("Kilometer:"));
        southPanel.add(kilometerTextField);
        southPanel.add(beendenButton);
        southPanel.add(gesamtKilometerLabel);
 
        // Füge Panels zum Frame hinzu
        frame.add(northPanel, BorderLayout.NORTH);
        frame.add(centerPanel, BorderLayout.CENTER);
        frame.add(southPanel, BorderLayout.SOUTH);
 
        // ActionListener für Erfassen-Button und Beenden-Button
        erfassenButton.addActionListener(e -> erfasseFahrt());
        beendenButton.addActionListener(e -> {
            kilometerVerwaltung.speichernCsvDatei(); // Speichere Daten beim Beenden
            stoppeFahrtenUpdater(); // Stoppe den Hintergrundthread
            System.exit(0); // Beende die Anwendung
        });
 
        // ActionListener für die Auswahl eines Fahrers
        fahrerComboBox.addActionListener(e -> aktualisiereFahrtenAnzeige());
 
        // Packe und mache den Frame sichtbar
        frame.pack();
        frame.setVisible(true);
 
        // Lade verfügbare Fahrer in die ComboBox
        ladeFahrerInComboBox();
 
        // Setze die Instanz für die GUI
        instance = this;
    }
 
    // Methode zum Laden der verfügbaren Fahrer in die ComboBox
    private void ladeFahrerInComboBox() {
        kilometerVerwaltung.getFahrerMap().values().forEach(fahrerComboBox::addItem);
    }
 
    // Methode zur Aktualisierung der Anzeige der Fahrten
    private void aktualisiereFahrtenAnzeige() {
        Fahrer ausgewaehlterFahrer = (Fahrer) fahrerComboBox.getSelectedItem();
        if (ausgewaehlterFahrer != null) {
            fahrtenTextArea.setText(""); // Lösche vorherige Einträge
            ausgewaehlterFahrer.getFahrten().forEach(fahrt -> fahrtenTextArea.append(fahrt.toString() + "\n")); // Füge neue Einträge hinzu
            int gesamtKilometer = ausgewaehlterFahrer.getFahrten().stream().mapToInt(Fahrt::getKilometer).sum();
            gesamtKilometerLabel.setText("Gesamtkilometer: " + gesamtKilometer); // Aktualisiere Gesamtkilometer-Anzeige
        }
    }
 
    // Methode zur Erfassung einer neuen Fahrt
    private void erfasseFahrt() {
        try {
            Fahrer ausgewaehlterFahrer = (Fahrer) fahrerComboBox.getSelectedItem();
            if (ausgewaehlterFahrer != null) {
                LocalDate datum = LocalDate.parse(datumTextField.getText(), DateTimeFormatter.ISO_LOCAL_DATE);
                String startort = startortTextField.getText();
                int kilometer = Integer.parseInt(kilometerTextField.getText());
                if (kilometer < 0) {
                    throw new IllegalArgumentException("Negative Kilometeranzahl");
                }
                Fahrt neueFahrt = new Fahrt(ausgewaehlterFahrer.getPersonalnummer(), datum, startort, kilometer);
                ausgewaehlterFahrer.addFahrt(neueFahrt);
                aktualisiereFahrtenAnzeige(); // Aktualisiere die Anzeige nach Erfassung einer neuen Fahrt
            }
        } catch (NumberFormatException ex) {
            JOptionPane.showMessageDialog(frame, "Kilometer müssen eine ganze Zahl sein.", "Fehler", JOptionPane.ERROR_MESSAGE);
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(frame, "Fehler bei der Eingabe: " + ex.getMessage(), "Fehler", JOptionPane.ERROR_MESSAGE);
        }
    }
 
    // Methode zur Aktualisierung der GUI-Komponenten aus einem anderen Thread
    public void aktualisiereGUI() {
        SwingUtilities.invokeLater(this::aktualisiereFahrtenAnzeige);
    }
 
    // Methode zum Starten des Hintergrundthreads zur Aktualisierung der Fahrten
    public void starteFahrtenUpdater() {
        fahrtenUpdaterThread = new Thread(new FahrtenUpdater(kilometerVerwaltung));
        fahrtenUpdaterThread.start();
    }
 
    // Methode zum Stoppen des Hintergrundthreads zur Aktualisierung der Fahrten
    public void stoppeFahrtenUpdater() {
        if (fahrtenUpdaterThread != null) {
            fahrtenUpdaterThread.interrupt();
        }
    }
 
    // Hauptmethode zum Starten der Anwendung
    public static void main(String[] args) {
        KilometerVerwaltung kilometerVerwaltung = new KilometerVerwaltung();
        kilometerVerwaltung.einlesenCsvDatei(); // Lade vorhandene Daten aus der CSV-Datei
        SwingUtilities.invokeLater(() -> {
            FahrAwayGUI gui = new FahrAwayGUI(kilometerVerwaltung);
            gui.starteFahrtenUpdater(); // Starte den Hintergrundthread zur Aktualisierung der Fahrten
        });
    }
}
// Ende