#include "WorkTimeCalculator.h" #include #include #include #include #include #include #include #include #include #include WorkTimeCalculator::WorkTimeCalculator(QWidget *parent) : QMainWindow(parent) { // QSettings braucht Organisation + Anwendung. Einmal global setzen, // dann reicht QSettings() ohne Argumente überall in der App. QCoreApplication::setOrganizationName("DietzLabs"); QCoreApplication::setApplicationName("ArbeitszeitRechner"); // Hauptlayout QWidget *mainWidget = new QWidget; QVBoxLayout *layout = new QVBoxLayout(mainWidget); // Einstempelzeit QLabel *startTimeLabel = new QLabel("Einstempelzeit:"); startTimeEdit = new QTimeEdit; startTimeEdit->setDisplayFormat("hh:mm"); startTimeEdit->setTime(QTime::currentTime()); layout->addWidget(startTimeLabel); layout->addWidget(startTimeEdit); // Pausenzeiten QLabel *breaksLabel = new QLabel("Pausenzeiten (Minuten):"); layout->addWidget(breaksLabel); QHBoxLayout *breakButtonLayout = new QHBoxLayout(); addBreakButton = new QPushButton("Pause hinzufügen"); removeBreakButton = new QPushButton("Pause entfernen"); breakButtonLayout->addWidget(addBreakButton); breakButtonLayout->addWidget(removeBreakButton); layout->addLayout(breakButtonLayout); breakList = new QListWidget; layout->addWidget(breakList); connect(addBreakButton, &QPushButton::clicked, this, &WorkTimeCalculator::addBreak); connect(removeBreakButton, &QPushButton::clicked, this, &WorkTimeCalculator::removeSelectedBreak); // Komfort: Entf-Taste löscht die markierte Pause. QShortcut *del = new QShortcut(QKeySequence(Qt::Key_Delete), breakList); connect(del, &QShortcut::activated, this, &WorkTimeCalculator::removeSelectedBreak); // Ausstempelzeit (optional) includeEndTimeCheckbox = new QCheckBox("Ausstempelzeit angeben"); endTimeEdit = new QTimeEdit; endTimeEdit->setDisplayFormat("hh:mm"); endTimeEdit->setTime(QTime::currentTime()); endTimeEdit->setVisible(false); layout->addWidget(includeEndTimeCheckbox); layout->addWidget(endTimeEdit); connect(includeEndTimeCheckbox, &QCheckBox::toggled, endTimeEdit, &QTimeEdit::setVisible); // Regelarbeitszeit QLabel *workTimeLabel = new QLabel("Regelarbeitszeit (Std:Min):"); layout->addWidget(workTimeLabel); dailyHoursSpin = new QSpinBox; dailyHoursSpin->setRange(0, 24); dailyMinutesSpin = new QSpinBox; dailyMinutesSpin->setRange(0, 59); QHBoxLayout *workTimeLayout = new QHBoxLayout(); workTimeLayout->addWidget(dailyHoursSpin); workTimeLayout->addWidget(dailyMinutesSpin); layout->addLayout(workTimeLayout); // Berechnung starten calculateButton = new QPushButton("Berechnung starten"); layout->addWidget(calculateButton); resultLabel = new QLabel; resultLabel->setTextInteractionFlags(Qt::TextSelectableByMouse); layout->addWidget(resultLabel); connect(calculateButton, &QPushButton::clicked, this, &WorkTimeCalculator::calculateWorkTime); // Dark Mode qApp->setStyle(QStyleFactory::create("Fusion")); QPalette darkPalette; darkPalette.setColor(QPalette::Window, QColor(53, 53, 53)); darkPalette.setColor(QPalette::WindowText, Qt::white); darkPalette.setColor(QPalette::Base, QColor(25, 25, 25)); darkPalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53)); darkPalette.setColor(QPalette::Text, Qt::white); darkPalette.setColor(QPalette::Button, QColor(53, 53, 53)); darkPalette.setColor(QPalette::ButtonText, Qt::white); qApp->setPalette(darkPalette); setCentralWidget(mainWidget); setWindowTitle("Arbeitszeitrechner"); loadSettings(); } WorkTimeCalculator::~WorkTimeCalculator() { saveSettings(); } // --- Pausen ----------------------------------------------------------------- void WorkTimeCalculator::addBreakItem(int minutes) { auto *item = new QListWidgetItem(QString("%1 Minuten").arg(minutes)); item->setData(BreakRole, minutes); // echte Daten getrennt vom Anzeigetext breakList->addItem(item); } void WorkTimeCalculator::addBreak() { bool ok = false; int breakTime = QInputDialog::getInt( this, "Pause hinzufügen", "Pause (Minuten):", /*value*/ 30, /*min*/ 1, /*max*/ 1440, /*step*/ 1, &ok); if (ok) addBreakItem(breakTime); } void WorkTimeCalculator::removeSelectedBreak() { qDeleteAll(breakList->selectedItems()); // entfernt + löscht die markierten Items } int WorkTimeCalculator::totalBreakMinutes() const { int total = 0; for (int i = 0; i < breakList->count(); ++i) total += breakList->item(i)->data(BreakRole).toInt(); return total; } // --- Hilfsfunktionen -------------------------------------------------------- int WorkTimeCalculator::minutesBetween(const QTime &start, const QTime &end, bool *crossesMidnight) { int secs = start.secsTo(end); bool wrapped = false; if (secs < 0) { // Ende liegt am Folgetag (z. B. Spät-/Nachtschicht) secs += 24 * 3600; wrapped = true; } if (crossesMidnight) *crossesMidnight = wrapped; return secs / 60; } QString WorkTimeCalculator::formatDuration(int minutes) { int a = qAbs(minutes); return QString("%1:%2").arg(a / 60).arg(a % 60, 2, 10, QChar('0')); } QString WorkTimeCalculator::formatSignedDuration(int minutes) { const QString sign = minutes < 0 ? "-" : "+"; return sign + formatDuration(minutes); } // --- Berechnung ------------------------------------------------------------- void WorkTimeCalculator::calculateWorkTime() { const QTime startTime = startTimeEdit->time(); const int breaks = totalBreakMinutes(); const int dailyMinutes = dailyHoursSpin->value() * 60 + dailyMinutesSpin->value(); QTime endTime; bool endIsNextDay = false; if (includeEndTimeCheckbox->isChecked()) { endTime = endTimeEdit->time(); } else { // Vorschlag: Anwesenheit = Soll-Netto + Pausen. const int presenceMinutes = dailyMinutes + breaks; endTime = startTime.addSecs(presenceMinutes * 60); endIsNextDay = (startTime.secsTo(endTime) < 0) || (presenceMinutes >= 24 * 60); } // Vergangene Anwesenheit inkl. korrekter Mitternachts-Behandlung. bool crossesMidnight = false; const int presenceMinutes = minutesBetween(startTime, endTime, &crossesMidnight); if (includeEndTimeCheckbox->isChecked()) endIsNextDay = crossesMidnight; const int workedMinutes = presenceMinutes - breaks; // Plausibilitätsprüfung im manuellen Modus. if (includeEndTimeCheckbox->isChecked() && workedMinutes < 0) { QMessageBox::warning(this, "Ungültige Eingabe", "Die Pausenzeit ist länger als die Anwesenheit. " "Bitte Ein-/Ausstempelzeit und Pausen prüfen."); return; } const int balanceMinutes = workedMinutes - dailyMinutes; QString result; result += QString("Netto-Arbeitszeit: %1 Std\n").arg(formatDuration(workedMinutes)); result += QString("Zeitkonto: %1 Std\n").arg(formatSignedDuration(balanceMinutes)); result += QString("Gesamte Pausenzeit: %1 Minuten").arg(breaks); if (!includeEndTimeCheckbox->isChecked()) { result += QString("\nVorgeschlagene Ausstempelzeit: %1%2") .arg(endTime.toString("hh:mm"), endIsNextDay ? " (Folgetag)" : ""); } else if (endIsNextDay) { result += "\nHinweis: Ausstempelzeit liegt am Folgetag (über Mitternacht)."; } // Hinweis auf gesetzliche Mindestpausen nach ArbZG §4 (kein Rechtsrat). if (workedMinutes > 9 * 60 && breaks < 45) result += "\n\n⚠ Ab 9 Std Arbeitszeit sind mind. 45 Minuten Pause vorgesehen (ArbZG §4)."; else if (workedMinutes > 6 * 60 && breaks < 30) result += "\n\n⚠ Ab 6 Std Arbeitszeit sind mind. 30 Minuten Pause vorgesehen (ArbZG §4)."; resultLabel->setText(result); } // --- Persistenz ------------------------------------------------------------- void WorkTimeCalculator::loadSettings() { QSettings settings; // nutzt Organisation/Anwendung aus dem Konstruktor dailyHoursSpin->setValue(settings.value("dailyHours", 8).toInt()); dailyMinutesSpin->setValue(settings.value("dailyMinutes", 0).toInt()); } void WorkTimeCalculator::saveSettings() { QSettings settings; settings.setValue("dailyHours", dailyHoursSpin->value()); settings.setValue("dailyMinutes", dailyMinutesSpin->value()); }