Files
QtZeiterfassung/stripswidget.cpp
T

596 lines
19 KiB
C++
Raw Permalink Normal View History

2017-12-09 01:48:18 +01:00
#include "stripswidget.h"
#include <QVBoxLayout>
#include <QVector>
#include <QLabel>
#include <QMap>
#include <QStringBuilder>
#include <QDebug>
#include "timeutils.h"
2017-12-09 04:33:52 +01:00
#include "stripfactory.h"
2017-12-09 01:48:18 +01:00
2017-12-10 23:29:12 +01:00
StripsWidget::StripsWidget(ZeiterfassungApi &erfassung, int userId, StripFactory &stripFactory,
const QMap<QString, QString> &projects, QWidget *parent) :
2017-12-09 01:48:18 +01:00
QWidget(parent),
2017-12-10 23:10:27 +01:00
m_erfassung(erfassung),
m_userId(userId),
2017-12-10 23:29:12 +01:00
m_stripFactory(stripFactory),
2017-12-09 01:48:18 +01:00
m_projects(projects),
2017-12-10 23:10:27 +01:00
m_layout(new QVBoxLayout(this)),
2017-12-10 23:44:44 +01:00
m_refreshing(false),
2017-12-11 00:23:48 +01:00
m_refreshingBookings(false),
m_refreshingTimeAssignments(false),
2017-12-10 23:10:27 +01:00
m_startEnabled(false),
m_endEnabled(false),
m_getBookingsReply(Q_NULLPTR),
m_getTimeAssignmentsReply(Q_NULLPTR)
2017-12-09 01:48:18 +01:00
{
setLayout(m_layout);
}
2017-12-10 23:10:27 +01:00
const QDate &StripsWidget::date() const
{
return m_date;
}
void StripsWidget::setDate(const QDate &date)
{
2017-12-10 23:23:00 +01:00
m_date = date;
refresh();
2017-12-10 23:10:27 +01:00
}
const QVector<ZeiterfassungApi::Booking> &StripsWidget::bookings() const
{
return m_bookings;
}
const QVector<ZeiterfassungApi::TimeAssignment> &StripsWidget::timeAssignments() const
{
return m_timeAssignments;
}
const QTime &StripsWidget::timeAssignmentTime() const
2017-12-10 23:10:27 +01:00
{
return m_timeAssignmentTime;
}
const QTime &StripsWidget::lastTimeAssignmentStart() const
2017-12-10 23:10:27 +01:00
{
return m_lastTimeAssignmentStart;
}
const QTime &StripsWidget::minimumTime() const
2017-12-10 23:10:27 +01:00
{
return m_minimumTime;
}
2017-12-10 23:44:44 +01:00
bool StripsWidget::refreshing() const
{
return m_refreshing;
}
2017-12-11 00:23:48 +01:00
bool StripsWidget::refreshingBookings() const
{
return m_refreshingBookings;
}
bool StripsWidget::refreshingTimeAssignments() const
{
return m_refreshingTimeAssignments;
}
2017-12-10 23:10:27 +01:00
bool StripsWidget::startEnabled() const
{
return m_startEnabled;
}
bool StripsWidget::endEnabled() const
{
return m_endEnabled;
}
void StripsWidget::refresh()
{
clearStrips();
m_layout->addWidget(new QLabel(tr("Loading..."), this));
m_layout->addStretch(1);
2017-12-10 23:10:27 +01:00
refreshBookings();
refreshTimeAssignments();
}
void StripsWidget::refreshBookings()
{
if(!m_date.isValid())
{
qWarning() << "invalid date";
return;
}
if(m_bookings.count())
{
m_bookings.clear();
Q_EMIT bookingsChanged(m_bookings);
}
2017-12-11 00:23:48 +01:00
if(!m_refreshing)
Q_EMIT refreshingChanged(m_refreshing = true);
if(!m_refreshingBookings)
Q_EMIT refreshingBookingsChanged(m_refreshingBookings = true);
invalidateValues();
2017-12-10 23:10:27 +01:00
m_getBookingsReply = m_erfassung.doGetBookings(m_userId, m_date, m_date);
connect(m_getBookingsReply.get(), &ZeiterfassungReply::finished, this, &StripsWidget::getBookingsFinished);
2017-12-10 23:10:27 +01:00
}
void StripsWidget::refreshTimeAssignments()
{
if(!m_date.isValid())
{
qWarning() << "invalid date";
return;
}
if(m_timeAssignments.count())
{
m_timeAssignments.clear();
Q_EMIT timeAssignmentsChanged(m_timeAssignments);
}
2017-12-11 00:23:48 +01:00
if(!m_refreshing)
Q_EMIT refreshingChanged(m_refreshing = true);
if(!m_refreshingTimeAssignments)
Q_EMIT refreshingTimeAssignmentsChanged(m_refreshingTimeAssignments = true);
invalidateValues();
2017-12-10 23:10:27 +01:00
m_getTimeAssignmentsReply = m_erfassung.doGetTimeAssignments(m_userId, m_date, m_date);
connect(m_getTimeAssignmentsReply.get(), &ZeiterfassungReply::finished, this, &StripsWidget::getTimeAssignmentsFinished);
2017-12-10 23:10:27 +01:00
}
bool StripsWidget::createStrips()
{
2017-12-10 23:23:00 +01:00
clearStrips();
2017-12-10 23:36:59 +01:00
QTime timeAssignmentTime(0, 0);
QTime lastTimeAssignmentStart;
2017-12-11 00:23:48 +01:00
QTime minimumTime(0, 0);
2017-12-10 23:36:59 +01:00
bool endEnabled = false;
2017-12-10 23:10:27 +01:00
auto bookingsIter = m_bookings.constBegin();
auto timeAssignmentsIter = m_timeAssignments.constBegin();
2017-12-09 01:48:18 +01:00
auto bookingTimespan = QTime(0, 0);
2017-12-10 11:56:00 +01:00
const ZeiterfassungApi::Booking *lastBooking = Q_NULLPTR;
2017-12-09 01:48:18 +01:00
QString errorMessage;
while(true)
{
2017-12-10 23:10:27 +01:00
if(bookingsIter == m_bookings.constEnd() &&
timeAssignmentsIter == m_timeAssignments.constEnd())
2017-12-09 01:48:18 +01:00
{
goto after;
}
2017-12-10 23:10:27 +01:00
if(bookingsIter == m_bookings.constEnd())
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("Missing booking!");
goto after;
}
auto startBooking = *bookingsIter++;
if(startBooking.type != QStringLiteral("K"))
{
errorMessage = tr("Expected start booking, instead got type %0\nBooking ID: %1")
.arg(startBooking.type)
.arg(startBooking.id);
goto after;
}
if(lastBooking)
{
2017-12-11 00:23:48 +01:00
auto breakTime = timeBetween(lastBooking->time, startBooking.time);
auto label = new QLabel(tr("%0: %1").arg(tr("Break")).arg(tr("%0h").arg(breakTime.toString(tr("HH:mm")))), this);
2017-12-09 01:48:18 +01:00
m_layout->addWidget(label);
}
lastBooking = &startBooking;
2017-12-10 23:36:59 +01:00
lastTimeAssignmentStart = startBooking.time;
2017-12-09 04:33:52 +01:00
appendBookingStartStrip(startBooking.id, startBooking.time);
2017-12-09 01:48:18 +01:00
2017-12-10 23:10:27 +01:00
if(timeAssignmentsIter == m_timeAssignments.constEnd())
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("Missing time assignment!");
goto after;
}
auto timeAssignment = *timeAssignmentsIter++;
2017-12-10 23:36:59 +01:00
if(timeAssignment.time != timeAssignmentTime)
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("Expected %0 but received %1 in time assignment.\nTime assignment ID: %2")
.arg(timeAssignmentTime.toString(tr("HH:mm:ss")))
.arg(timeAssignment.time.toString(tr("HH:mm:ss")))
2017-12-09 01:48:18 +01:00
.arg(timeAssignment.id);
goto after;
}
2017-12-09 04:33:52 +01:00
appendTimeAssignmentStrip(timeAssignment.id, timeAssignment.timespan, buildProjectString(timeAssignment.project),
timeAssignment.subproject, timeAssignment.workpackage, timeAssignment.text);
2017-12-09 01:48:18 +01:00
if(timeAssignment.timespan == QTime(0, 0))
{
2017-12-10 23:10:27 +01:00
if(bookingsIter != m_bookings.constEnd())
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("There is another booking after an unfinished time assignment.\nBooking ID: %0\nTime assignment ID: %1")
.arg(bookingsIter->id)
.arg(timeAssignment.id);
goto after;
}
2017-12-10 23:10:27 +01:00
if(timeAssignmentsIter != m_timeAssignments.constEnd())
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("There is another time assignment after an unfinished time assignment.\nTime assignment ID: %0\nTime assignment ID: %1")
.arg(timeAssignmentsIter->id)
.arg(timeAssignment.id);
goto after;
}
2017-12-11 00:23:48 +01:00
minimumTime = timeAdd(lastTimeAssignmentStart, QTime(0, 1));
2017-12-10 23:36:59 +01:00
endEnabled = true;
2017-12-09 01:48:18 +01:00
goto after;
}
else
{
2017-12-10 23:36:59 +01:00
timeAssignmentTime = timeAdd(timeAssignmentTime, timeAssignment.timespan);
lastTimeAssignmentStart = timeAdd(lastTimeAssignmentStart, timeAssignment.timespan);
2017-12-09 01:48:18 +01:00
2017-12-10 23:10:27 +01:00
if(bookingsIter == m_bookings.constEnd())
2017-12-09 01:48:18 +01:00
{
while(true)
{
2017-12-10 23:10:27 +01:00
if(timeAssignmentsIter == m_timeAssignments.constEnd())
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("The last time assignment is finished without end booking\nTime assignment ID: %0")
.arg(timeAssignment.id);
goto after;
}
timeAssignment = *timeAssignmentsIter++;
2017-12-10 23:36:59 +01:00
if(timeAssignment.time != timeAssignmentTime)
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("Expected %0 but received %1 in time assignment.\nTime assignment ID: %2")
.arg(timeAssignmentTime.toString(tr("HH:mm:ss")))
.arg(timeAssignment.time.toString(tr("HH:mm:ss")))
2017-12-09 01:48:18 +01:00
.arg(timeAssignment.id);
goto after;
}
2017-12-09 04:33:52 +01:00
appendTimeAssignmentStrip(timeAssignment.id, timeAssignment.timespan, buildProjectString(timeAssignment.project),
timeAssignment.subproject, timeAssignment.workpackage, timeAssignment.text);
2017-12-09 01:48:18 +01:00
if(timeAssignment.timespan == QTime(0, 0))
{
2017-12-10 23:10:27 +01:00
if(timeAssignmentsIter != m_timeAssignments.constEnd())
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("There is another time assignment after an unfinished time assignment.\n"
"Time assignment ID: %0\nTime assignment ID: %1")
.arg(timeAssignment.id)
.arg(timeAssignmentsIter->id);
goto after;
}
2017-12-11 00:23:48 +01:00
minimumTime = timeAdd(lastTimeAssignmentStart, QTime(0, 1));
2017-12-10 23:36:59 +01:00
endEnabled = true;
2017-12-09 01:48:18 +01:00
goto after;
}
else
{
2017-12-10 23:36:59 +01:00
timeAssignmentTime = timeAdd(timeAssignmentTime, timeAssignment.timespan);
lastTimeAssignmentStart = timeAdd(lastTimeAssignmentStart, timeAssignment.timespan);
2017-12-09 01:48:18 +01:00
}
}
}
else
{
auto endBooking = *bookingsIter++;
if(endBooking.type != QStringLiteral("G"))
{
errorMessage = tr("Expected end booking, instead got type %0\nBooking ID: %1")
.arg(endBooking.type)
.arg(endBooking.id);
goto after;
}
lastBooking = &endBooking;
bookingTimespan = timeAdd(bookingTimespan, timeBetween(startBooking.time, endBooking.time));
2017-12-11 00:23:48 +01:00
minimumTime = timeAdd(endBooking.time, QTime(0, 1));
2017-12-09 01:48:18 +01:00
2017-12-10 23:36:59 +01:00
while(timeAssignmentTime < bookingTimespan)
2017-12-09 01:48:18 +01:00
{
2017-12-10 23:10:27 +01:00
if(timeAssignmentsIter == m_timeAssignments.constEnd())
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("Missing time assignment! Missing: %0")
.arg(tr("%0h").arg(timeBetween(timeAssignmentTime, bookingTimespan).toString(tr("HH:mm:ss"))));
2017-12-09 01:48:18 +01:00
2017-12-09 04:33:52 +01:00
appendBookingEndStrip(endBooking.id, endBooking.time);
2017-12-09 01:48:18 +01:00
goto after;
}
timeAssignment = *timeAssignmentsIter++;
2017-12-10 23:36:59 +01:00
if(timeAssignment.time != timeAssignmentTime)
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("Expected %0 but received %1 in time assignment.\nTime assignment ID: %2")
.arg(timeAssignmentTime.toString(tr("HH:mm:ss")))
.arg(timeAssignment.time.toString(tr("HH:mm:ss")))
2017-12-09 01:48:18 +01:00
.arg(timeAssignment.id);
goto after;
}
2017-12-09 04:33:52 +01:00
appendTimeAssignmentStrip(timeAssignment.id, timeAssignment.timespan, buildProjectString(timeAssignment.project),
timeAssignment.subproject, timeAssignment.workpackage, timeAssignment.text);
2017-12-09 01:48:18 +01:00
if(timeAssignment.timespan == QTime(0, 0))
{
2017-12-10 23:10:27 +01:00
if(bookingsIter != m_bookings.constEnd())
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("There is another booking after an unfinished time assignment.\n"
"Booking ID: %0\nTime assignment ID: %1")
.arg(bookingsIter->id)
.arg(timeAssignment.id);
goto after;
}
2017-12-10 23:10:27 +01:00
if(timeAssignmentsIter != m_timeAssignments.constEnd())
2017-12-09 01:48:18 +01:00
{
errorMessage = tr("There is another time assignment after an unfinished time assignment.\nTime assignment ID: %0\nTime assignment ID: %1")
.arg(timeAssignmentsIter->id)
.arg(timeAssignment.id);
goto after;
}
2017-12-11 00:23:48 +01:00
minimumTime = timeAdd(lastTimeAssignmentStart, QTime(0, 1));
2017-12-10 23:36:59 +01:00
endEnabled = true;
2017-12-09 01:48:18 +01:00
goto after;
}
else
{
2017-12-10 23:36:59 +01:00
timeAssignmentTime = timeAdd(timeAssignmentTime, timeAssignment.timespan);
2017-12-09 01:48:18 +01:00
}
}
2017-12-10 23:36:59 +01:00
if(timeAssignmentTime > bookingTimespan)
2017-12-09 01:48:18 +01:00
{
2017-12-13 23:14:37 +01:00
errorMessage = tr("Time assignment time longer than booking time!\nTime assignment: %0\nBooking: %1")
.arg(timeAssignmentTime.toString(tr("HH:mm:ss")))
.arg(bookingTimespan.toString(tr("HH:mm:ss")));
2017-12-09 01:48:18 +01:00
}
2017-12-09 04:33:52 +01:00
appendBookingEndStrip(endBooking.id, endBooking.time);
2017-12-09 01:48:18 +01:00
2017-12-10 23:36:59 +01:00
if(timeAssignmentTime > bookingTimespan)
2017-12-09 01:48:18 +01:00
goto after;
}
}
}
after:
auto startEnabled = errorMessage.isEmpty();
2017-12-11 00:23:48 +01:00
if(errorMessage.isEmpty())
{
auto label = new QLabel(tr("%0: %1")
.arg(tr("Assigned time"))
.arg(tr("%0h").arg(timeAssignmentTime.toString(tr("HH:mm")))), this);
2017-12-11 00:23:48 +01:00
m_layout->addWidget(label);
}
else
2017-12-09 01:48:18 +01:00
{
2017-12-10 23:36:59 +01:00
startEnabled = false;
endEnabled = false;
timeAssignmentTime = QTime();
lastTimeAssignmentStart = QTime();
2017-12-13 23:14:37 +01:00
auto label = new QLabel(tr("Strip rendering aborted due error.\n"
"Your bookings and time assignments for this day are in an illegal state!") % "\n" %
errorMessage, this);
label->setStyleSheet("color: red;");
2017-12-09 01:48:18 +01:00
m_layout->addWidget(label);
}
2017-12-10 23:36:59 +01:00
if(m_timeAssignmentTime != timeAssignmentTime)
Q_EMIT timeAssignmentTimeChanged(m_timeAssignmentTime = timeAssignmentTime);
2017-12-10 23:36:59 +01:00
if(m_lastTimeAssignmentStart != lastTimeAssignmentStart)
Q_EMIT lastTimeAssignmentStartChanged(m_lastTimeAssignmentStart = lastTimeAssignmentStart);
2017-12-11 00:23:48 +01:00
if(m_minimumTime != minimumTime)
Q_EMIT minimumTimeChanged(m_minimumTime = minimumTime);
if(m_startEnabled != startEnabled)
Q_EMIT startEnabledChanged(m_startEnabled = startEnabled);
if(m_endEnabled != endEnabled)
Q_EMIT endEnabledChanged(m_endEnabled = endEnabled);
m_layout->addStretch(1);
2017-12-10 23:36:59 +01:00
return !errorMessage.isEmpty();
2017-12-09 01:48:18 +01:00
}
void StripsWidget::clearStrips()
{
while(QLayoutItem *item = m_layout->takeAt(0))
{
delete item->widget();
delete item;
}
auto label = new QLabel(this);
if(m_date.isValid())
label->setText(tr("%0 (%1)")
.arg(std::array<QString, 7> { tr("Monday"), tr("Tuesday"), tr("Wednesday"), tr("Thursday"),
tr("Friday"), tr("Saturday"), tr("Sunday") }[m_date.dayOfWeek() - 1])
.arg(m_date.toString(tr("dd.MM.yyyy"))));
else
label->setText(tr("Invalid"));
{
auto font = label->font();
font.setBold(true);
label->setFont(font);
}
m_layout->addWidget(label);
2017-12-09 01:48:18 +01:00
}
2017-12-10 23:10:27 +01:00
void StripsWidget::getBookingsFinished()
2017-12-09 01:48:18 +01:00
{
2017-12-11 00:23:48 +01:00
Q_EMIT bookingsChanged(m_bookings = m_getBookingsReply->bookings());
if(m_refreshingBookings)
Q_EMIT refreshingBookingsChanged(m_refreshingBookings = false);
2017-12-10 23:10:27 +01:00
if(!m_getTimeAssignmentsReply)
2017-12-11 00:23:48 +01:00
{
if(m_refreshing)
Q_EMIT refreshingChanged(m_refreshing = false);
2017-12-10 23:10:27 +01:00
createStrips();
2017-12-11 00:23:48 +01:00
}
2017-12-10 23:10:27 +01:00
m_getBookingsReply = Q_NULLPTR;
2017-12-09 01:48:18 +01:00
}
2017-12-10 23:10:27 +01:00
void StripsWidget::getTimeAssignmentsFinished()
2017-12-09 01:48:18 +01:00
{
2017-12-11 00:23:48 +01:00
Q_EMIT timeAssignmentsChanged(m_timeAssignments = m_getTimeAssignmentsReply->timeAssignments());
if(m_refreshingTimeAssignments)
Q_EMIT refreshingTimeAssignmentsChanged(m_refreshingTimeAssignments = false);
2017-12-10 23:10:27 +01:00
if(!m_getBookingsReply)
2017-12-11 00:23:48 +01:00
{
if(m_refreshing)
Q_EMIT refreshingChanged(m_refreshing = false);
2017-12-10 23:10:27 +01:00
createStrips();
2017-12-11 00:23:48 +01:00
}
2017-12-10 23:10:27 +01:00
m_getTimeAssignmentsReply = Q_NULLPTR;
2017-12-09 01:48:18 +01:00
}
void StripsWidget::invalidateValues()
{
if(m_timeAssignmentTime.isValid())
Q_EMIT timeAssignmentTimeChanged(m_timeAssignmentTime = QTime());
if(m_lastTimeAssignmentStart.isValid())
Q_EMIT lastTimeAssignmentStartChanged(m_lastTimeAssignmentStart = QTime());
if(m_minimumTime.isValid())
Q_EMIT minimumTimeChanged(m_minimumTime = QTime());
if(m_startEnabled)
Q_EMIT startEnabledChanged(m_startEnabled = false);
if(m_endEnabled)
Q_EMIT endEnabledChanged(m_endEnabled = false);
}
2017-12-09 01:48:18 +01:00
QString StripsWidget::buildProjectString(const QString &project)
{
if(m_projects.contains(project))
2017-12-12 21:29:20 +01:00
return m_projects.value(project) % "\n" % project;
2017-12-09 01:48:18 +01:00
else
{
qWarning() << "could not find project" << project;
return project;
}
}
2017-12-09 04:33:52 +01:00
QWidget *StripsWidget::appendBookingStartStrip(int id, const QTime &time)
{
auto widget = m_stripFactory.createBookingStartStrip(this).release();
2017-12-09 04:33:52 +01:00
if(auto labelTime = widget->findChild<QWidget*>(QStringLiteral("labelTime")))
labelTime->setProperty("text", time.toString(tr("HH:mm")));
2017-12-09 04:33:52 +01:00
else
qWarning() << "no labelTime found!";
if(auto labelId = widget->findChild<QWidget*>(QStringLiteral("labelId")))
2017-12-09 04:33:52 +01:00
labelId->setProperty("text", QString::number(id));
else
qWarning() << "no labelId found!";
m_layout->addWidget(widget);
return widget;
}
QWidget *StripsWidget::appendBookingEndStrip(int id, const QTime &time)
{
auto widget = m_stripFactory.createBookingEndStrip(this).release();
2017-12-09 04:33:52 +01:00
if(auto labelTime = widget->findChild<QWidget*>(QStringLiteral("labelTime")))
labelTime->setProperty("text", time.toString(tr("HH:mm")));
2017-12-09 04:33:52 +01:00
else
qWarning() << "no labelTime found!";
if(auto labelId = widget->findChild<QWidget*>(QStringLiteral("labelId")))
2017-12-09 04:33:52 +01:00
labelId->setProperty("text", QString::number(id));
else
qWarning() << "no labelId found!";
m_layout->addWidget(widget);
return widget;
}
QWidget *StripsWidget::appendTimeAssignmentStrip(int id, const QTime &duration, const QString &project, const QString &subproject, const QString &workpackage, const QString &text)
{
auto widget = m_stripFactory.createTimeAssignmentStrip(this).release();
2017-12-09 04:33:52 +01:00
if(auto labelTime = widget->findChild<QWidget*>(QStringLiteral("labelTime")))
labelTime->setProperty("text", duration == QTime(0, 0) ? tr("Open") : duration.toString(tr("HH:mm")));
2017-12-09 04:33:52 +01:00
else
qWarning() << "no labelTime found!";
if(auto labelProject = widget->findChild<QWidget*>(QStringLiteral("labelProject")))
2017-12-09 04:33:52 +01:00
labelProject->setProperty("text", project);
else
qWarning() << "no labelProject found!";
if(auto labelId = widget->findChild<QWidget*>(QStringLiteral("labelId")))
2017-12-09 04:33:52 +01:00
labelId->setProperty("text", QString::number(id));
else
qWarning() << "no labelId found!";
if(auto labelSubproject = widget->findChild<QWidget*>(QStringLiteral("labelSubproject")))
2017-12-09 04:33:52 +01:00
labelSubproject->setProperty("text", subproject);
else
qWarning() << "no labelSubproject found!";
if(auto labelWorkpackage = widget->findChild<QWidget*>(QStringLiteral("labelWorkpackage")))
2017-12-09 04:33:52 +01:00
labelWorkpackage->setProperty("text", workpackage);
else
qWarning() << "no labelWorkpackage found!";
if(auto labelText = widget->findChild<QWidget*>(QStringLiteral("labelText")))
2017-12-09 04:33:52 +01:00
labelText->setProperty("text", text);
else
qWarning() << "no labelText found!";
m_layout->addWidget(widget);
return widget;
}