fixed an error with calculation per midnight, added a remove pause button and made the Readme better

This commit is contained in:
Tronax 2026-05-30 23:21:56 +02:00
parent 605fe9a77e
commit 65af7f060b
3 changed files with 212 additions and 49 deletions

View file

@ -6,16 +6,25 @@
#include <QSettings>
#include <QMessageBox>
#include <QStyleFactory>
#include <QCoreApplication>
#include <QShortcut>
#include <QKeySequence>
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");
WorkTimeCalculator::WorkTimeCalculator() {
// Hauptlayout
QWidget *mainWidget = new QWidget;
QVBoxLayout *layout = new QVBoxLayout(mainWidget);
mainWidget->setLayout(layout); // Setze das Layout für das Widget
// Einstempelzeit
QLabel *startTimeLabel = new QLabel("Einstempelzeit:");
startTimeEdit = new QTimeEdit;
startTimeEdit->setDisplayFormat("hh:mm");
startTimeEdit->setTime(QTime::currentTime());
layout->addWidget(startTimeLabel);
layout->addWidget(startTimeEdit);
@ -24,17 +33,26 @@ WorkTimeCalculator::WorkTimeCalculator() {
QLabel *breaksLabel = new QLabel("Pausenzeiten (Minuten):");
layout->addWidget(breaksLabel);
addBreakButton = new QPushButton("Pause hinzufügen");
layout->addWidget(addBreakButton);
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(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);
@ -61,6 +79,7 @@ WorkTimeCalculator::WorkTimeCalculator() {
layout->addWidget(calculateButton);
resultLabel = new QLabel;
resultLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
layout->addWidget(resultLabel);
connect(calculateButton, &QPushButton::clicked, this, &WorkTimeCalculator::calculateWorkTime);
@ -75,7 +94,6 @@ WorkTimeCalculator::WorkTimeCalculator() {
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);
@ -88,60 +106,127 @@ WorkTimeCalculator::~WorkTimeCalculator() {
saveSettings();
}
void WorkTimeCalculator::addBreak() {
bool ok;
int breakTime = QInputDialog::getInt(this, "Pause hinzufügen", "Pause (Minuten):", 0, 0, 1440, 1, &ok);
if (ok && breakTime > 0) {
breakList->addItem(QString::number(breakTime) + " Minuten");
}
// --- 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::calculateWorkTime() {
QTime startTime = startTimeEdit->time();
int totalBreakMinutes = 0;
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);
}
for (int i = 0; i < breakList->count(); ++i) {
totalBreakMinutes += breakList->item(i)->text().split(" ")[0].toInt();
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;
}
// Gesamte Pausenzeit anzeigen
QString breakTimeMessage = QString("Gesamte Pausenzeit: %1 Minuten").arg(totalBreakMinutes);
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 {
// Ausstempelzeit berechnen, wenn nicht angegeben
int dailyMinutes = dailyHoursSpin->value() * 60 + dailyMinutesSpin->value();
endTime = startTime.addSecs((dailyMinutes + totalBreakMinutes) * 60);
// Vorschlag: Anwesenheit = Soll-Netto + Pausen.
const int presenceMinutes = dailyMinutes + breaks;
endTime = startTime.addSecs(presenceMinutes * 60);
endIsNextDay = (startTime.secsTo(endTime) < 0) || (presenceMinutes >= 24 * 60);
}
int workedMinutes = startTime.secsTo(endTime) / 60 - totalBreakMinutes;
// Vergangene Anwesenheit inkl. korrekter Mitternachts-Behandlung.
bool crossesMidnight = false;
const int presenceMinutes = minutesBetween(startTime, endTime, &crossesMidnight);
if (includeEndTimeCheckbox->isChecked())
endIsNextDay = crossesMidnight;
int dailyMinutes = dailyHoursSpin->value() * 60 + dailyMinutesSpin->value();
int balanceMinutes = workedMinutes - dailyMinutes;
const int workedMinutes = presenceMinutes - breaks;
QString result = QString("Netto-Arbeitszeit: %1 Stunden %2 Minuten\n")
.arg(workedMinutes / 60)
.arg(workedMinutes % 60);
result += QString("Zeitkonto: %1 Minuten\n").arg(balanceMinutes);
result += breakTimeMessage; // Gesamte Pausenzeit hinzufügen
// 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").arg(endTime.toString("hh:mm"));
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("ArbeitszeitRechner", "Settings");
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("ArbeitszeitRechner", "Settings");
QSettings settings;
settings.setValue("dailyHours", dailyHoursSpin->value());
settings.setValue("dailyMinutes", dailyMinutesSpin->value());
}