Added existing sources

This commit is contained in:
0xFEEDC0DE64
2017-12-02 10:50:30 +01:00
parent fbf5946ece
commit df3657911a
35 changed files with 3866 additions and 29 deletions

92
.gitignore vendored
View File

@@ -1,39 +1,73 @@
# C++ objects and libs
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*.slo
*.lo
*.o
*~
*.autosave
*.a
*.la
*.lai
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.dll
*.dylib
# Qt-es
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.qbs.user
*.qbs.user.*
*.moc
moc_*.cpp
moc_*.h
qrc_*.cpp
ui_*.h
Makefile*
*build-*
# QtCreator
# qtcreator generated files
*.pro.user*
*.autosave
# xemacs temporary files
*.flc
# QtCtreator Qml
*.qmlproject.user
*.qmlproject.user.*
# Vim temporary files
.*.swp
# QtCtreator CMake
CMakeLists.txt.user*
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

21
dialogs/aboutmedialog.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include "aboutmedialog.h"
#include "ui_aboutmedialog.h"
AboutMeDialog::AboutMeDialog(const Zeiterfassung::UserInfo &userInfo, QWidget *parent) :
QDialog(parent),
ui(new Ui::AboutMeDialog),
m_userInfo(userInfo)
{
ui->setupUi(this);
ui->spinBoxUserId->setValue(userInfo.userId);
ui->lineEditEmail->setText(userInfo.email);
ui->lineEditLongUsername->setText(userInfo.longUsername);
ui->lineEditText->setText(userInfo.text);
ui->lineEditUsername->setText(userInfo.username);
}
AboutMeDialog::~AboutMeDialog()
{
delete ui;
}

23
dialogs/aboutmedialog.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef ABOUTMEDIALOG_H
#define ABOUTMEDIALOG_H
#include <QDialog>
#include "zeiterfassung.h"
namespace Ui { class AboutMeDialog; }
class AboutMeDialog : public QDialog
{
Q_OBJECT
public:
explicit AboutMeDialog(const Zeiterfassung::UserInfo &userInfo, QWidget *parent = 0);
~AboutMeDialog();
private:
Ui::AboutMeDialog *ui;
const Zeiterfassung::UserInfo &m_userInfo;
};
#endif // ABOUTMEDIALOG_H

120
dialogs/aboutmedialog.ui Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutMeDialog</class>
<widget class="QDialog" name="AboutMeDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
<item>
<widget class="QLabel" name="labelTitle">
<property name="text">
<string>&lt;h1&gt;About me&lt;/h1&gt;</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelUserId">
<property name="text">
<string>User-ID:</string>
</property>
<property name="buddy">
<cstring>spinBoxUserId</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelEmail">
<property name="text">
<string>E-Mail:</string>
</property>
<property name="buddy">
<cstring>lineEditEmail</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelLongUsername">
<property name="text">
<string>Long username:</string>
</property>
<property name="buddy">
<cstring>lineEditLongUsername</cstring>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelText">
<property name="text">
<string>Text:</string>
</property>
<property name="buddy">
<cstring>lineEditText</cstring>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelUsername">
<property name="text">
<string>Username:</string>
</property>
<property name="buddy">
<cstring>lineEditUsername</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spinBoxUserId">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="maximum">
<number>16777215</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditEmail">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEditLongUsername">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEditText">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEditUsername">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,34 @@
#include "authenticationdialog.h"
#include "ui_authenticationdialog.h"
AuthenticationDialog::AuthenticationDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AuthenticationDialog)
{
ui->setupUi(this);
}
AuthenticationDialog::~AuthenticationDialog()
{
delete ui;
}
QString AuthenticationDialog::username() const
{
return ui->lineEditUsername->text();
}
void AuthenticationDialog::setUsername(const QString &username)
{
ui->lineEditUsername->setText(username);
}
QString AuthenticationDialog::password() const
{
return ui->lineEditPassword->text();
}
void AuthenticationDialog::setPassword(const QString &password)
{
ui->lineEditPassword->setText(password);
}

View File

@@ -0,0 +1,28 @@
#ifndef AUTHENTICATIONDIALOG_H
#define AUTHENTICATIONDIALOG_H
#include <QDialog>
namespace Ui {
class AuthenticationDialog;
}
class AuthenticationDialog : public QDialog
{
Q_OBJECT
public:
explicit AuthenticationDialog(QWidget *parent = 0);
~AuthenticationDialog();
QString username() const;
void setUsername(const QString &username);
QString password() const;
void setPassword(const QString &password);
private:
Ui::AuthenticationDialog *ui;
};
#endif // AUTHENTICATIONDIALOG_H

View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AuthenticationDialog</class>
<widget class="QDialog" name="AuthenticationDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>394</width>
<height>169</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="labelLogo">
<property name="minimumSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/zeiterfassung/images/authentication.png</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelTitle">
<property name="text">
<string>&lt;h1&gt;Authentication&lt;/h1&gt;</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="1" column="0">
<widget class="QLabel" name="labelUsername">
<property name="text">
<string>Username:</string>
</property>
<property name="buddy">
<cstring>lineEditUsername</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelPassword">
<property name="text">
<string>Password:</string>
</property>
<property name="buddy">
<cstring>lineEditPassword</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineEditUsername"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEditPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AuthenticationDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AuthenticationDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

55
dialogs/buchungdialog.cpp Normal file
View File

@@ -0,0 +1,55 @@
#include "buchungdialog.h"
#include "ui_buchungdialog.h"
BuchungDialog::BuchungDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::BuchungDialog)
{
ui->setupUi(this);
ui->timeEditTime->setTime(QTime::currentTime());
}
BuchungDialog::~BuchungDialog()
{
delete ui;
}
QTime BuchungDialog::getTime() const
{
return ui->timeEditTime->time();
}
void BuchungDialog::setTime(const QTime &time)
{
ui->timeEditTime->setTime(time);
}
QTime BuchungDialog::getTimespan() const
{
return ui->timeEditTimespan->time();
}
void BuchungDialog::setTimespan(const QTime &timespan)
{
ui->timeEditTimespan->setTime(timespan);
}
QString BuchungDialog::getType() const
{
return ui->comboBoxType->currentText();
}
void BuchungDialog::setType(const QString &type)
{
ui->comboBoxType->setCurrentText(type);
}
QString BuchungDialog::getText() const
{
return ui->lineEditText->text();
}
void BuchungDialog::setText(const QString &text)
{
ui->lineEditText->setText(text);
}

34
dialogs/buchungdialog.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef BUCHUNGDIALOG_H
#define BUCHUNGDIALOG_H
#include <QDialog>
namespace Ui {
class BuchungDialog;
}
class BuchungDialog : public QDialog
{
Q_OBJECT
public:
explicit BuchungDialog(QWidget *parent = 0);
~BuchungDialog();
QTime getTime() const;
void setTime(const QTime &time);
QTime getTimespan() const;
void setTimespan(const QTime &timespan);
QString getType() const;
void setType(const QString &type);
QString getText() const;
void setText(const QString &text);
private:
Ui::BuchungDialog *ui;
};
#endif // BUCHUNGDIALOG_H

139
dialogs/buchungdialog.ui Normal file
View File

@@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BuchungDialog</class>
<widget class="QDialog" name="BuchungDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0">
<item>
<widget class="QLabel" name="labelTitle">
<property name="text">
<string>&lt;h1&gt;Buchung&lt;/h1&gt;</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelTime">
<property name="text">
<string>Time:</string>
</property>
<property name="buddy">
<cstring>timeEditTime</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelTimespan">
<property name="text">
<string>Timespan:</string>
</property>
<property name="buddy">
<cstring>timeEditTimespan</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelType">
<property name="text">
<string>Type:</string>
</property>
<property name="buddy">
<cstring>comboBoxType</cstring>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelText">
<property name="text">
<string>Text:</string>
</property>
<property name="buddy">
<cstring>lineEditText</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QTimeEdit" name="timeEditTime">
<property name="displayFormat">
<string>HH:mm:ss</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QTimeEdit" name="timeEditTimespan">
<property name="displayFormat">
<string>HH:mm:ss</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEditText"/>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxType">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>BuchungDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>BuchungDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,88 @@
#include "kontierungdialog.h"
#include "ui_kontierungdialog.h"
#include <QMessageBox>
#include <QStringBuilder>
#include <QDebug>
KontierungDialog::KontierungDialog(Zeiterfassung &erfassung, const Zeiterfassung::UserInfo &userInfo,
const QVector<Zeiterfassung::Projekt> &projekte, QWidget *parent) :
QDialog(parent),
ui(new Ui::KontierungDialog),
m_erfassung(erfassung),
m_userInfo(userInfo)
{
ui->setupUi(this);
for(const auto& projekt : projekte)
ui->comboBoxProjekt->addItem(projekt.label % " (" % projekt.value % ')', projekt.value);
}
KontierungDialog::~KontierungDialog()
{
delete ui;
}
QTime KontierungDialog::getTime() const
{
return ui->timeEditTime->time();
}
void KontierungDialog::setTime(const QTime &time)
{
ui->timeEditTime->setTime(time);
}
QTime KontierungDialog::getTimespan() const
{
return ui->timeEditTimespan->time();
}
void KontierungDialog::setTimespan(const QTime &timespan)
{
ui->timeEditTimespan->setTime(timespan);
}
QString KontierungDialog::getProjekt() const
{
return ui->comboBoxProjekt->currentData().toString();
}
void KontierungDialog::setProjekt(const QString &projekt)
{
auto index = ui->comboBoxProjekt->findData(projekt);
if(index >= 0)
ui->comboBoxProjekt->setCurrentIndex(index);
else
qWarning() << "could not find projekt" << projekt;
}
QString KontierungDialog::getSubprojekt() const
{
return ui->lineEditSubprojekt->text();
}
void KontierungDialog::setSubprojekt(const QString &subprojekt)
{
ui->lineEditSubprojekt->setText(subprojekt);
}
QString KontierungDialog::getWorkpackage() const
{
return ui->lineEditWorkpackage->text();
}
void KontierungDialog::setWorkpackage(const QString &workpackage)
{
ui->lineEditWorkpackage->setText(workpackage);
}
QString KontierungDialog::getText() const
{
return ui->lineEditText->text();
}
void KontierungDialog::setText(const QString &text)
{
ui->lineEditText->setText(text);
}

View File

@@ -0,0 +1,43 @@
#ifndef KONTIERUNGDIALOG_H
#define KONTIERUNGDIALOG_H
#include <QDialog>
#include "zeiterfassung.h"
namespace Ui { class KontierungDialog; }
class KontierungDialog : public QDialog
{
Q_OBJECT
public:
explicit KontierungDialog(Zeiterfassung &erfassung, const Zeiterfassung::UserInfo &userInfo,
const QVector<Zeiterfassung::Projekt> &projekte, QWidget *parent = 0);
~KontierungDialog();
QTime getTime() const;
void setTime(const QTime &time);
QTime getTimespan() const;
void setTimespan(const QTime &timespan);
QString getProjekt() const;
void setProjekt(const QString &projekt);
QString getSubprojekt() const;
void setSubprojekt(const QString &subprojekt);
QString getWorkpackage() const;
void setWorkpackage(const QString &workpackage);
QString getText() const;
void setText(const QString &text);
private:
Ui::KontierungDialog *ui;
Zeiterfassung &m_erfassung;
const Zeiterfassung::UserInfo &m_userInfo;
};
#endif // KONTIERUNGDIALOG_H

168
dialogs/kontierungdialog.ui Normal file
View File

@@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KontierungDialog</class>
<widget class="QDialog" name="KontierungDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0">
<item>
<widget class="QLabel" name="labelTitle">
<property name="text">
<string>&lt;h1&gt;Kontierung&lt;/h1&gt;</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="labelTime">
<property name="text">
<string>Time:</string>
</property>
<property name="buddy">
<cstring>timeEditTime</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelTimespan">
<property name="text">
<string>Timespan:</string>
</property>
<property name="buddy">
<cstring>timeEditTimespan</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelProjekt">
<property name="text">
<string>Projekt:</string>
</property>
<property name="buddy">
<cstring>comboBoxProjekt</cstring>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelSubprojekt">
<property name="text">
<string>Subprojekt:</string>
</property>
<property name="buddy">
<cstring>lineEditSubprojekt</cstring>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="labelWorkpackage">
<property name="text">
<string>Workpackage:</string>
</property>
<property name="buddy">
<cstring>lineEditWorkpackage</cstring>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="labelText">
<property name="text">
<string>Text:</string>
</property>
<property name="buddy">
<cstring>lineEditText</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QTimeEdit" name="timeEditTime">
<property name="displayFormat">
<string>HH:mm:ss</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QTimeEdit" name="timeEditTimespan">
<property name="displayFormat">
<string>HH:mm:ss</string>
</property>
<property name="time">
<time>
<hour>1</hour>
<minute>0</minute>
<second>0</second>
</time>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxProjekt"/>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEditSubprojekt"/>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEditWorkpackage"/>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="lineEditText"/>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>KontierungDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>KontierungDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

24
eventloopwithstatus.cpp Normal file
View File

@@ -0,0 +1,24 @@
#include "eventloopwithstatus.h"
EventLoopWithStatus::EventLoopWithStatus(QObject *parent) :
QEventLoop(parent)
{
}
bool EventLoopWithStatus::success() const
{
return m_success;
}
const QString &EventLoopWithStatus::message() const
{
return m_message;
}
void EventLoopWithStatus::quitWithStatus(bool success, const QString &message)
{
m_success = success;
m_message = message;
quit();
}

24
eventloopwithstatus.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef EVENTLOOPWITHSTATUS_H
#define EVENTLOOPWITHSTATUS_H
#include <QEventLoop>
class EventLoopWithStatus : public QEventLoop
{
Q_OBJECT
public:
EventLoopWithStatus(QObject *parent = Q_NULLPTR);
bool success() const;
const QString &message() const;
public Q_SLOTS:
void quitWithStatus(bool success, const QString &message);
private:
bool m_success;
QString m_message;
};
#endif // EVENTLOOPWITHSTATUS_H

BIN
images/authentication.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
images/next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
images/previous.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
images/quit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
images/refresh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
images/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
images/today.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

135
main.cpp Executable file
View File

@@ -0,0 +1,135 @@
#include <QApplication>
#include <QSplashScreen>
#include <QPixmap>
#include <QSettings>
#include <QInputDialog>
#include <QMessageBox>
#include "zeiterfassung.h"
#include "eventloopwithstatus.h"
#include "dialogs/authenticationdialog.h"
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QCoreApplication::setOrganizationDomain(QStringLiteral("brunner.ninja"));
QCoreApplication::setOrganizationName(QStringLiteral("db-software"));
QCoreApplication::setApplicationName(QStringLiteral("zeiterfassung"));
QCoreApplication::setApplicationVersion(QStringLiteral("1.0"));
QSplashScreen splashScreen(QPixmap(":/zeiterfassung/images/splash.png"));
splashScreen.showMessage(QObject::tr("Loading settings..."));
splashScreen.show();
QSettings settings;
if(settings.value("url").isNull())
{
bool ok;
auto url = QInputDialog::getText(&splashScreen, QObject::tr("Base url"),
QObject::tr("Please enter the base url to the Zeiterfassung:"),
QLineEdit::Normal, QString(), &ok);
if(!ok)
return -1;
settings.setValue("url", url);
}
splashScreen.showMessage(QObject::tr("Loading login page..."));
Zeiterfassung erfassung(settings.value("url").toString());
{
EventLoopWithStatus eventLoop;
QObject::connect(&erfassung, &Zeiterfassung::loginPageFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
again1:
erfassung.doLoginPage();
eventLoop.exec();
if(!eventLoop.success())
{
bool ok;
QMessageBox::warning(&splashScreen, QObject::tr("Could not access Zeiterfassung"),
QObject::tr("The Zeiterfassung could not be accessed:\n\n%0").arg(eventLoop.message()));
auto url = QInputDialog::getText(&splashScreen, QObject::tr("Base url"),
QObject::tr("Please enter the base url to the Zeiterfassung:"),
QLineEdit::Normal, settings.value("url").toString(), &ok);
if(!ok)
return -1;
settings.setValue("url", url);
erfassung.setUrl(url);
goto again1;
}
}
splashScreen.showMessage(QObject::tr("Authenticating..."));
if(settings.value("username").isNull() || settings.value("password").isNull())
{
AuthenticationDialog dialog(&splashScreen);
if(dialog.exec() != QDialog::Accepted)
return -1;
settings.setValue("username", dialog.username());
settings.setValue("password", dialog.password());
}
{
EventLoopWithStatus eventLoop;
QObject::connect(&erfassung, &Zeiterfassung::loginFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
again2:
erfassung.doLogin(settings.value("username").toString(), settings.value("password").toString());
eventLoop.exec();
if(!eventLoop.success())
{
QMessageBox::warning(&splashScreen, QObject::tr("Could not authenticate with Zeiterfassung"),
QObject::tr("The Zeiterfassung authentication was not successful:\n\n%0").arg(eventLoop.message()));
AuthenticationDialog dialog(&splashScreen);
dialog.setUsername(settings.value("username").toString());
dialog.setPassword(settings.value("password").toString());
if(dialog.exec() != QDialog::Accepted)
return -1;
settings.setValue("username", dialog.username());
settings.setValue("password", dialog.password());
goto again2;
}
}
splashScreen.showMessage(QObject::tr("Getting user information..."));
Zeiterfassung::UserInfo userInfo;
{
EventLoopWithStatus eventLoop;
QObject::connect(&erfassung, &Zeiterfassung::userInfoFinished,
[&](bool success, const QString &message, const Zeiterfassung::UserInfo &_userInfo) {
Q_UNUSED(message)
if(success)
userInfo = _userInfo;
});
QObject::connect(&erfassung, &Zeiterfassung::userInfoFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
erfassung.doUserInfo();
eventLoop.exec();
if(!eventLoop.success())
{
QMessageBox::warning(&splashScreen, QObject::tr("Could not get user information!"),
QObject::tr("Could not get user information:\n\n%0").arg(eventLoop.message()));
return -1;
}
}
MainWindow mainWindow(settings, erfassung, userInfo);
mainWindow.show();
splashScreen.finish(&mainWindow);
return app.exec();
}

978
mainwindow.cpp Normal file
View File

@@ -0,0 +1,978 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QLineEdit>
#include <QMessageBox>
#include <QSettings>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QStringBuilder>
#include <QMenu>
#include <QDebug>
#include "eventloopwithstatus.h"
#include "dialogs/aboutmedialog.h"
#include "dialogs/buchungdialog.h"
#include "dialogs/kontierungdialog.h"
#include "models/buchungenmodel.h"
#include "models/kontierungenmodel.h"
MainWindow::MainWindow(QSettings &settings, Zeiterfassung &erfassung, const Zeiterfassung::UserInfo &userInfo, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
m_settings(settings),
m_erfassung(erfassung),
m_userInfo(userInfo),
m_buchungenModel(new BuchungenModel(erfassung, this)),
m_kontierungenModel(new KontierungenModel(erfassung, this)),
m_flag(false)
{
ui->setupUi(this);
setWindowTitle(tr("Zeiterfassung - %0").arg(m_userInfo.text));
ui->actionQuit->setShortcut(QKeySequence::Quit);
connect(ui->actionToday, &QAction::triggered, [=](){ ui->dateEditDate->setDate(QDate::currentDate()); });
ui->actionRefresh->setShortcut(QKeySequence::Refresh);
connect(ui->actionRefresh, &QAction::triggered, this, &MainWindow::refresh);
connect(ui->actionAboutMe, &QAction::triggered, [=](){ AboutMeDialog(userInfo, this).exec(); });
connect(ui->actionAboutQt, &QAction::triggered, [=](){ QMessageBox::aboutQt(this); });
ui->dateEditDate->setDate(QDate::currentDate());
connect(ui->dateEditDate, &QDateTimeEdit::dateChanged, this, &MainWindow::refresh);
refresh();
connect(ui->pushButtonPrev, &QAbstractButton::pressed, this, &MainWindow::pushButtonPrevPressed);
connect(ui->pushButtonNext, &QAbstractButton::pressed, this, &MainWindow::pushButtonNextPressed);
ui->timeEditTime->setTime(timeNormalise(QTime::currentTime()));
connect(&m_erfassung, &Zeiterfassung::getProjekteFinished,
this, &MainWindow::getProjekteFinished);
erfassung.doGetProjekte(userInfo.userId);
ui->comboBoxProjekt->setMaxVisibleItems(10);
ui->comboBoxSubprojekt->lineEdit()->setPlaceholderText(tr("Subprojekt"));
ui->comboBoxWorkpackage->lineEdit()->setPlaceholderText(tr("Workpackage"));
ui->comboBoxText->lineEdit()->setPlaceholderText(tr("Text"));
updateComboboxes();
connect(ui->pushButtonStart, &QAbstractButton::pressed, this, &MainWindow::pushButtonStartPressed);
connect(ui->pushButtonEnd, &QAbstractButton::pressed, this, &MainWindow::pushButtonEndPressed);
ui->treeViewBuchungen->setModel(m_buchungenModel);
ui->treeViewKontierungen->setModel(m_kontierungenModel);
connect(ui->treeViewBuchungen, &QWidget::customContextMenuRequested,
this, &MainWindow::contextMenuBuchung);
connect(ui->treeViewKontierungen, &QWidget::customContextMenuRequested,
this, &MainWindow::contextMenuKontierung);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::refresh()
{
ui->actionToday->setEnabled(false);
ui->actionRefresh->setEnabled(false);
ui->dateEditDate->setReadOnly(true);
ui->timeEditTime->setEnabled(false);
ui->comboBoxProjekt->setEnabled(false);
ui->comboBoxSubprojekt->setEnabled(false);
ui->comboBoxWorkpackage->setEnabled(false);
ui->comboBoxText->setEnabled(false);
ui->pushButtonStart->setEnabled(false);
ui->pushButtonEnd->setEnabled(false);
ui->treeViewBuchungen->setEnabled(false);
ui->treeViewKontierungen->setEnabled(false);
auto waitForBuchugen = m_buchungenModel->refresh(m_userInfo.userId, ui->dateEditDate->date(), ui->dateEditDate->date());
if(waitForBuchugen)
{
connect(m_buchungenModel, &BuchungenModel::refreshFinished,
this, &MainWindow::refreshBuchungenFinished);
}
auto waitForKontierungen = m_kontierungenModel->refresh(m_userInfo.userId, ui->dateEditDate->date(), ui->dateEditDate->date());
if(waitForKontierungen)
{
connect(m_kontierungenModel, &KontierungenModel::refreshFinished,
this, &MainWindow::refreshKontierungenFinished);
}
if(!waitForBuchugen || !waitForKontierungen)
QMessageBox::warning(this, tr("Unknown error occured."), tr("An unknown error occured."));
if(waitForBuchugen || waitForKontierungen)
m_flag = waitForBuchugen == waitForKontierungen;
else
{
ui->actionToday->setEnabled(true);
ui->actionRefresh->setEnabled(true);
ui->dateEditDate->setReadOnly(false);
}
}
void MainWindow::getProjekteFinished(bool success, const QString &message, const QVector<Zeiterfassung::Projekt> &projekte)
{
disconnect(&m_erfassung, &Zeiterfassung::getProjekteFinished,
this, &MainWindow::getProjekteFinished);
if(!success)
{
QMessageBox::warning(this, tr("Could not load Buchungen!"), tr("Could not load Buchungen:\n\n%0").arg(message));
return;
}
m_projekte = projekte;
updateComboboxes();
}
void MainWindow::refreshBuchungenFinished(bool success, const QString &message)
{
disconnect(m_buchungenModel, &BuchungenModel::refreshFinished,
this, &MainWindow::refreshBuchungenFinished);
if(success)
ui->treeViewBuchungen->setEnabled(true);
if(m_flag)
m_flag = false;
else
validateEntries();
if(!success)
QMessageBox::warning(Q_NULLPTR, tr("Could not refresh Buchungen!"), tr("Could not refresh Buchungen:\n\n%0").arg(message));
}
void MainWindow::refreshKontierungenFinished(bool success, const QString &message)
{
disconnect(m_kontierungenModel, &KontierungenModel::refreshFinished,
this, &MainWindow::refreshKontierungenFinished);
if(success)
ui->treeViewKontierungen->setEnabled(true);
if(m_flag)
m_flag = false;
else
validateEntries();
if(!success)
QMessageBox::warning(Q_NULLPTR, tr("Could not refresh Kontierungen!"), tr("Could not refresh Kontierungen:\n\n%0").arg(message));
}
void MainWindow::contextMenuBuchung(const QPoint &pos)
{
auto index = ui->treeViewBuchungen->indexAt(pos);
if(index.isValid())
{
auto buchung = m_buchungenModel->getBuchung(index);
QMenu menu;
auto editAction = menu.addAction(tr("Edit"));
auto deleteAction = menu.addAction(tr("Delete"));
auto selectedAction = menu.exec(ui->treeViewBuchungen->viewport()->mapToGlobal(pos));
if(selectedAction == editAction)
{
BuchungDialog dialog(this);
dialog.setTime(buchung.time);
dialog.setTimespan(buchung.timespan);
dialog.setType(buchung.type);
dialog.setText(buchung.text);
again1:
if(dialog.exec() == QDialog::Accepted)
{
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::updateBuchungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
m_erfassung.doUpdateBuchung(buchung.id, m_userInfo.userId, ui->dateEditDate->date(),
dialog.getTime(), dialog.getTimespan(),
dialog.getType(), dialog.getText());
eventLoop.exec();
if(eventLoop.success())
{
ui->actionToday->setEnabled(false);
ui->actionRefresh->setEnabled(false);
ui->dateEditDate->setReadOnly(true);
ui->timeEditTime->setEnabled(false);
ui->comboBoxProjekt->setEnabled(false);
ui->comboBoxSubprojekt->setEnabled(false);
ui->comboBoxWorkpackage->setEnabled(false);
ui->comboBoxText->setEnabled(false);
ui->pushButtonStart->setEnabled(false);
ui->pushButtonEnd->setEnabled(false);
ui->treeViewBuchungen->setEnabled(false);
if(m_buchungenModel->refresh(m_userInfo.userId, ui->dateEditDate->date(), ui->dateEditDate->date()))
{
connect(m_buchungenModel, &BuchungenModel::refreshFinished,
this, &MainWindow::refreshBuchungenFinished);
m_flag = false;
}
else
{
ui->actionToday->setEnabled(true);
ui->actionRefresh->setEnabled(true);
ui->dateEditDate->setReadOnly(false);
}
}
else
{
QMessageBox::warning(this, tr("Could not update Buchung!"), tr("Could not update Buchung:\n\n%0").arg(eventLoop.message()));
goto again1;
}
}
}
else if(selectedAction == deleteAction)
{
QMessageBox msgBox;
msgBox.setText("Do you really want to delete the Buchung?");
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
if(msgBox.exec() == QMessageBox::Yes)
{
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::deleteBuchungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
m_erfassung.doDeleteBuchung(buchung.id);
eventLoop.exec();
if(eventLoop.success())
{
ui->actionToday->setEnabled(false);
ui->actionRefresh->setEnabled(false);
ui->dateEditDate->setReadOnly(true);
ui->timeEditTime->setEnabled(false);
ui->comboBoxProjekt->setEnabled(false);
ui->comboBoxSubprojekt->setEnabled(false);
ui->comboBoxWorkpackage->setEnabled(false);
ui->comboBoxText->setEnabled(false);
ui->pushButtonStart->setEnabled(false);
ui->pushButtonEnd->setEnabled(false);
ui->treeViewBuchungen->setEnabled(false);
if(m_buchungenModel->refresh(m_userInfo.userId, ui->dateEditDate->date(), ui->dateEditDate->date()))
{
connect(m_buchungenModel, &BuchungenModel::refreshFinished,
this, &MainWindow::refreshBuchungenFinished);
m_flag = false;
}
else
{
ui->actionToday->setEnabled(true);
ui->actionRefresh->setEnabled(true);
ui->dateEditDate->setReadOnly(false);
}
}
else
QMessageBox::warning(this, tr("Could not delete Buchung!"), tr("Could not delete Buchung:\n\n%0").arg(eventLoop.message()));
}
}
}
else
{
QMenu menu;
auto createAction = menu.addAction(tr("Create"));
auto selectedAction = menu.exec(ui->treeViewBuchungen->viewport()->mapToGlobal(pos));
if(selectedAction == createAction)
{
BuchungDialog dialog(this);
dialog.setTime(QTime::currentTime());
again2:
if(dialog.exec() == QDialog::Accepted)
{
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::createBuchungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
m_erfassung.doCreateBuchung(m_userInfo.userId, ui->dateEditDate->date(),
dialog.getTime(), dialog.getTimespan(),
dialog.getType(), dialog.getText());
eventLoop.exec();
if(eventLoop.success())
{
ui->actionToday->setEnabled(false);
ui->actionRefresh->setEnabled(false);
ui->dateEditDate->setReadOnly(true);
ui->timeEditTime->setEnabled(false);
ui->comboBoxProjekt->setEnabled(false);
ui->comboBoxSubprojekt->setEnabled(false);
ui->comboBoxWorkpackage->setEnabled(false);
ui->comboBoxText->setEnabled(false);
ui->pushButtonStart->setEnabled(false);
ui->pushButtonEnd->setEnabled(false);
ui->treeViewBuchungen->setEnabled(false);
if(m_buchungenModel->refresh(m_userInfo.userId, ui->dateEditDate->date(), ui->dateEditDate->date()))
{
connect(m_buchungenModel, &BuchungenModel::refreshFinished,
this, &MainWindow::refreshBuchungenFinished);
m_flag = false;
}
else
{
ui->actionToday->setEnabled(true);
ui->actionRefresh->setEnabled(true);
ui->dateEditDate->setReadOnly(false);
}
}
else
{
QMessageBox::warning(this, tr("Could not create Buchung!"), tr("Could not create Buchung:\n\n%0").arg(eventLoop.message()));
goto again2;
}
}
}
}
}
void MainWindow::contextMenuKontierung(const QPoint &pos)
{
auto index = ui->treeViewKontierungen->indexAt(pos);
if(index.isValid())
{
auto kontierung = m_kontierungenModel->getKontierung(index);
QMenu menu;
auto editAction = menu.addAction(tr("Edit"));
auto deleteAction = menu.addAction(tr("Delete"));
auto selectedAction = menu.exec(ui->treeViewKontierungen->viewport()->mapToGlobal(pos));
if(selectedAction == editAction)
{
KontierungDialog dialog(m_erfassung, m_userInfo, m_projekte, this);
dialog.setTime(kontierung.time);
dialog.setTimespan(kontierung.timespan);
dialog.setProjekt(kontierung.projekt);
dialog.setSubprojekt(kontierung.subprojekt);
dialog.setWorkpackage(kontierung.workpackage);
dialog.setText(kontierung.text);
again1:
if(dialog.exec() == QDialog::Accepted)
{
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::updateKontierungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
m_erfassung.doUpdateKontierung(kontierung.id, m_userInfo.userId, ui->dateEditDate->date(),
dialog.getTime(), dialog.getTimespan(),
dialog.getProjekt(), dialog.getSubprojekt(),
dialog.getWorkpackage(), dialog.getText());
eventLoop.exec();
if(eventLoop.success())
{
ui->actionToday->setEnabled(false);
ui->actionRefresh->setEnabled(false);
ui->dateEditDate->setReadOnly(true);
ui->timeEditTime->setEnabled(false);
ui->comboBoxProjekt->setEnabled(false);
ui->comboBoxSubprojekt->setEnabled(false);
ui->comboBoxWorkpackage->setEnabled(false);
ui->comboBoxText->setEnabled(false);
ui->pushButtonStart->setEnabled(false);
ui->pushButtonEnd->setEnabled(false);
ui->treeViewKontierungen->setEnabled(false);
if(m_kontierungenModel->refresh(m_userInfo.userId, ui->dateEditDate->date(), ui->dateEditDate->date()))
{
connect(m_kontierungenModel, &KontierungenModel::refreshFinished,
this, &MainWindow::refreshKontierungenFinished);
m_flag = false;
}
else
{
ui->actionToday->setEnabled(true);
ui->actionRefresh->setEnabled(true);
ui->dateEditDate->setReadOnly(false);
}
}
else
{
QMessageBox::warning(this, tr("Could not update Kontierung!"), tr("Could not update Kontierung:\n\n%0").arg(eventLoop.message()));
goto again1;
}
}
}
else if(selectedAction == deleteAction)
{
QMessageBox msgBox;
msgBox.setText("Do you really want to delete the Kontierung?");
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
if(msgBox.exec() == QMessageBox::Yes)
{
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::deleteKontierungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
m_erfassung.doDeleteKontierung(kontierung.id);
eventLoop.exec();
if(eventLoop.success())
{
ui->actionToday->setEnabled(false);
ui->actionRefresh->setEnabled(false);
ui->dateEditDate->setReadOnly(true);
ui->timeEditTime->setEnabled(false);
ui->comboBoxProjekt->setEnabled(false);
ui->comboBoxSubprojekt->setEnabled(false);
ui->comboBoxWorkpackage->setEnabled(false);
ui->comboBoxText->setEnabled(false);
ui->pushButtonStart->setEnabled(false);
ui->pushButtonEnd->setEnabled(false);
ui->treeViewKontierungen->setEnabled(false);
if(m_kontierungenModel->refresh(m_userInfo.userId, ui->dateEditDate->date(), ui->dateEditDate->date()))
{
connect(m_kontierungenModel, &KontierungenModel::refreshFinished,
this, &MainWindow::refreshKontierungenFinished);
m_flag = false;
}
else
{
ui->actionToday->setEnabled(true);
ui->actionRefresh->setEnabled(true);
ui->dateEditDate->setReadOnly(false);
}
}
else
QMessageBox::warning(this, tr("Could not delete Kontierung!"), tr("Could not delete Kontierung:\n\n%0").arg(eventLoop.message()));
}
}
}
else
{
QMenu menu;
auto createAction = menu.addAction(tr("Create"));
auto selectedAction = menu.exec(ui->treeViewKontierungen->viewport()->mapToGlobal(pos));
if(selectedAction == createAction)
{
KontierungDialog dialog(m_erfassung, m_userInfo, m_projekte, this);
again2:
if(dialog.exec() == QDialog::Accepted)
{
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::createKontierungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
m_erfassung.doCreateKontierung(m_userInfo.userId, ui->dateEditDate->date(),
dialog.getTime(), dialog.getTimespan(),
dialog.getProjekt(), dialog.getSubprojekt(),
dialog.getWorkpackage(), dialog.getText());
eventLoop.exec();
if(eventLoop.success())
{
ui->actionToday->setEnabled(false);
ui->actionRefresh->setEnabled(false);
ui->dateEditDate->setReadOnly(true);
ui->timeEditTime->setEnabled(false);
ui->comboBoxProjekt->setEnabled(false);
ui->comboBoxSubprojekt->setEnabled(false);
ui->comboBoxWorkpackage->setEnabled(false);
ui->comboBoxText->setEnabled(false);
ui->pushButtonStart->setEnabled(false);
ui->pushButtonEnd->setEnabled(false);
ui->treeViewKontierungen->setEnabled(false);
if(m_kontierungenModel->refresh(m_userInfo.userId, ui->dateEditDate->date(), ui->dateEditDate->date()))
{
connect(m_kontierungenModel, &KontierungenModel::refreshFinished,
this, &MainWindow::refreshKontierungenFinished);
m_flag = false;
}
else
{
ui->actionToday->setEnabled(true);
ui->actionRefresh->setEnabled(true);
ui->dateEditDate->setReadOnly(false);
}
}
else
{
QMessageBox::warning(this, tr("Could not create Kontierung!"), tr("Could not create Kontierung:\n\n%0").arg(eventLoop.message()));
goto again2;
}
}
}
}
}
void MainWindow::pushButtonPrevPressed()
{
ui->dateEditDate->setDate(ui->dateEditDate->date().addDays(-1));
}
void MainWindow::pushButtonNextPressed()
{
ui->dateEditDate->setDate(ui->dateEditDate->date().addDays(1));
}
void MainWindow::pushButtonStartPressed()
{
if(m_buchungenModel->rbegin() == m_buchungenModel->rend() ||
m_buchungenModel->rbegin()->type == QStringLiteral("G"))
{
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::createBuchungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
m_erfassung.doCreateBuchung(m_userInfo.userId, ui->dateEditDate->date(),
timeNormalise(ui->timeEditTime->time()), QTime(0, 0),
QStringLiteral("K"), QStringLiteral(""));
eventLoop.exec();
if(!eventLoop.success())
{
QMessageBox::warning(this, tr("Could not create Buchung!"), tr("Could not create Buchung:\n\n%0").arg(eventLoop.message()));
refresh();
return;
}
}
if(m_kontierungenModel->rbegin() != m_kontierungenModel->rend())
{
auto kontierung = *m_kontierungenModel->rbegin();
if(kontierung.timespan == QTime(0, 0))
{
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::updateKontierungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
auto timespan = timeBetween(m_lastKontierungStart, ui->timeEditTime->time());
qDebug() << "timespan" << timespan;
m_erfassung.doUpdateKontierung(kontierung.id, m_userInfo.userId, kontierung.date,
kontierung.time, timespan,
kontierung.projekt, kontierung.subprojekt,
kontierung.workpackage, kontierung.text);
eventLoop.exec();
if(eventLoop.success())
m_kontierungTime = timeAdd(m_kontierungTime, timespan);
else
{
QMessageBox::warning(this, tr("Could not update Kontierung!"), tr("Could not update Kontierung:\n\n%0").arg(eventLoop.message()));
refresh();
return;
}
}
}
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::createKontierungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
m_erfassung.doCreateKontierung(m_userInfo.userId, ui->dateEditDate->date(),
m_kontierungTime, QTime(0, 0),
ui->comboBoxProjekt->currentData().toString(), ui->comboBoxSubprojekt->currentText(),
ui->comboBoxWorkpackage->currentText(), ui->comboBoxText->currentText());
eventLoop.exec();
if(!eventLoop.success())
{
QMessageBox::warning(this, tr("Could not create Kontierung!"), tr("Could not create Kontierung:\n\n%0").arg(eventLoop.message()));
refresh();
return;
}
{
QStringList projekte = m_settings.value("projekte", QStringList()).toStringList();
projekte.removeAll(ui->comboBoxProjekt->currentData().toString());
projekte.prepend(ui->comboBoxProjekt->currentData().toString());
m_settings.setValue("projekte", projekte);
}
if(!ui->comboBoxSubprojekt->currentText().trimmed().isEmpty())
{
QStringList subprojekte = m_settings.value("subprojekte", QStringList()).toStringList();
subprojekte.removeAll(ui->comboBoxSubprojekt->currentText());
subprojekte.prepend(ui->comboBoxSubprojekt->currentText());
m_settings.setValue("subprojekte", subprojekte);
}
if(!ui->comboBoxWorkpackage->currentText().trimmed().isEmpty())
{
QStringList workpackages = m_settings.value("workpackages", QStringList()).toStringList();
workpackages.removeAll(ui->comboBoxWorkpackage->currentText());
workpackages.prepend(ui->comboBoxWorkpackage->currentText());
m_settings.setValue("workpackages", workpackages);
}
if(!ui->comboBoxText->currentText().trimmed().isEmpty())
{
QStringList texte = m_settings.value("texte", QStringList()).toStringList();
texte.removeAll(ui->comboBoxText->currentText());
texte.prepend(ui->comboBoxText->currentText());
m_settings.setValue("texte", texte);
}
updateComboboxes();
refresh();
}
void MainWindow::pushButtonEndPressed()
{
{
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::createBuchungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
m_erfassung.doCreateBuchung(m_userInfo.userId, ui->dateEditDate->date(),
timeNormalise(ui->timeEditTime->time()), QTime(0, 0),
QStringLiteral("G"), QStringLiteral(""));
eventLoop.exec();
if(!eventLoop.success())
{
QMessageBox::warning(this, tr("Could not create Buchung!"), tr("Could not create Buchung:\n\n%0").arg(eventLoop.message()));
refresh();
return;
}
}
{
auto kontierung = *m_kontierungenModel->rbegin();
Q_ASSERT(kontierung.timespan == QTime(0, 0));
EventLoopWithStatus eventLoop;
connect(&m_erfassung, &Zeiterfassung::updateKontierungFinished, &eventLoop, &EventLoopWithStatus::quitWithStatus);
auto timespan = timeBetween(m_lastKontierungStart, ui->timeEditTime->time());
qDebug() << "timespan" << timespan;
m_erfassung.doUpdateKontierung(kontierung.id, m_userInfo.userId, kontierung.date,
kontierung.time, timespan,
kontierung.projekt, kontierung.subprojekt,
kontierung.workpackage, kontierung.text);
eventLoop.exec();
if(eventLoop.success())
m_kontierungTime = timeAdd(m_kontierungTime, timespan);
else
{
QMessageBox::warning(this, tr("Could not update Kontierung!"), tr("Could not update Kontierung:\n\n%0").arg(eventLoop.message()));
refresh();
return;
}
}
refresh();
}
void MainWindow::validateEntries()
{
ui->actionToday->setEnabled(true);
ui->actionRefresh->setEnabled(true);
ui->dateEditDate->setReadOnly(false);
ui->pushButtonStart->setText(tr("Start"));
if(!ui->treeViewBuchungen->isEnabled())
return;
if(!ui->treeViewKontierungen->isEnabled())
return;
auto buchungenIter = m_buchungenModel->constBegin();
auto kontierungenIter = m_kontierungenModel->constBegin();
m_kontierungTime = QTime(0, 0);
auto buchungTimespan = QTime(0, 0);
while(true)
{
if(buchungenIter == m_buchungenModel->constEnd() &&
kontierungenIter == m_kontierungenModel->constEnd())
{
ui->timeEditTime->setEnabled(true);
ui->comboBoxProjekt->setEnabled(true);
ui->comboBoxSubprojekt->setEnabled(true);
ui->comboBoxWorkpackage->setEnabled(true);
ui->comboBoxText->setEnabled(true);
ui->pushButtonStart->setEnabled(true);
return;
}
if(buchungenIter == m_buchungenModel->constEnd())
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("Missing Buchung.")));
return;
}
auto startBuchung = *buchungenIter++;
qDebug() << "startBuchung" << startBuchung.time;
if(startBuchung.type != QStringLiteral("K"))
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("Expected Buchung for Kommen, instead got type %0\nBuchung ID: %1").arg(startBuchung.type).arg(startBuchung.id)));
return;
}
m_lastKontierungStart = startBuchung.time;
if(kontierungenIter == m_kontierungenModel->constEnd())
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("Missing Kontierung.")));
return;
}
auto kontierung = *kontierungenIter++;
if(kontierung.time != m_kontierungTime)
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("Expected time %0 but got %1 Kontierung.\nKontierung ID: %2")
.arg(m_kontierungTime.toString("HH:mm:ss"))
.arg(kontierung.time.toString("HH:mm:ss"))
.arg(kontierung.id)));
return;
}
if(kontierung.timespan == QTime(0, 0))
{
if(buchungenIter != m_buchungenModel->constEnd())
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("There is another Buchung after an unfinished Kontierung.\nBuchung ID: %0\nKontierung ID: %1")
.arg(buchungenIter->id)
.arg(kontierung.id)));
return;
}
if(kontierungenIter != m_kontierungenModel->constEnd())
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("There is another Kontierung after an unfinished Kontierung.\nKontierung ID: %0\nKontierung ID: %1")
.arg(kontierungenIter->id)
.arg(kontierung.id)));
return;
}
ui->pushButtonStart->setText(tr("Switch"));
ui->pushButtonEnd->setEnabled(true);
goto after;
}
else
{
m_kontierungTime = timeAdd(m_kontierungTime, kontierung.timespan);
m_lastKontierungStart = timeAdd(m_lastKontierungStart, kontierung.timespan);
if(buchungenIter == m_buchungenModel->constEnd())
{
while(true)
{
if(kontierungenIter == m_kontierungenModel->constEnd())
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("The last Kontierung is finished without Gehen-Buchung\nKontierung ID: %0")
.arg(kontierung.id)));
return;
}
kontierung = *kontierungenIter++;
if(kontierung.time != m_kontierungTime)
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("Expected time %0 but got %1 Kontierung.\nKontierung ID: %2")
.arg(m_kontierungTime.toString("HH:mm:ss"))
.arg(kontierung.time.toString("HH:mm:ss"))
.arg(kontierung.id)));
return;
}
if(kontierung.timespan == QTime(0, 0))
{
if(kontierungenIter != m_kontierungenModel->constEnd())
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("There is another Kontierung after an unfinished Kontierung.\nKontierung ID: %0\nKontierung ID: %1")
.arg(kontierung.id)
.arg(kontierungenIter->id)));
return;
}
ui->pushButtonStart->setText(tr("Switch"));
ui->pushButtonEnd->setEnabled(true);
goto after;
}
else
{
m_kontierungTime = timeAdd(m_kontierungTime, kontierung.timespan);
m_lastKontierungStart = timeAdd(m_lastKontierungStart, kontierung.timespan);
}
}
}
else
{
auto endBuchung = *buchungenIter++;
qDebug() << "endBuchung" << endBuchung.time;
if(endBuchung.type != QStringLiteral("G"))
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("Expected Buchung for Gehen, instead got type %0\nBuchung ID: %1").arg(endBuchung.type).arg(endBuchung.id)));
return;
}
buchungTimespan = timeAdd(buchungTimespan, timeBetween(startBuchung.time, endBuchung.time));
qDebug() << "buchungTimespan" << buchungTimespan;
while(m_kontierungTime < buchungTimespan)
{
if(kontierungenIter == m_kontierungenModel->constEnd())
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("Missing Kontierung! Time not filled: %0 - %1")
.arg(m_kontierungTime.toString("HH:mm:ss"))
.arg(buchungTimespan.toString("HH:mm:ss"))));
return;
}
kontierung = *kontierungenIter++;
if(kontierung.time != m_kontierungTime)
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("Expected time %0 but got %1 Kontierung.\nKontierung ID: %2")
.arg(m_kontierungTime.toString("HH:mm:ss"))
.arg(kontierung.time.toString("HH:mm:ss"))
.arg(kontierung.id)));
return;
}
if(kontierung.timespan == QTime(0, 0))
{
if(buchungenIter != m_buchungenModel->constEnd())
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("There is another Buchung after an unfinished Kontierung.\nBuchung ID: %0\nKontierung ID: %1")
.arg(buchungenIter->id)
.arg(kontierung.id)));
return;
}
if(kontierungenIter != m_kontierungenModel->constEnd())
{
QMessageBox::warning(this, tr("Illegal state!"), tr("Your Buchungen and Kontierungen for this day are in an invalid state:\n\n%0")
.arg(tr("There is another Kontierung after an unfinished Kontierung.\nKontierung ID: %0\nKontierung ID: %1")
.arg(kontierungenIter->id)
.arg(kontierung.id)));
return;
}
ui->pushButtonStart->setText(tr("Switch"));
ui->pushButtonEnd->setEnabled(true);
goto after;
}
else
{
m_kontierungTime = timeAdd(m_kontierungTime, kontierung.timespan);
}
}
}
}
}
after:
qDebug() << "m_kontierTime" << m_kontierungTime;
ui->timeEditTime->setEnabled(true);
ui->comboBoxProjekt->setEnabled(true);
ui->comboBoxSubprojekt->setEnabled(true);
ui->comboBoxWorkpackage->setEnabled(true);
ui->comboBoxText->setEnabled(true);
ui->pushButtonStart->setEnabled(true);
}
void MainWindow::updateComboboxes()
{
ui->comboBoxProjekt->clear();
{
auto preferedProjekte = m_settings.value("projekte", QStringList()).toStringList();
for(const auto &preferedProjekt : preferedProjekte)
{
for(const auto &projekt : m_projekte)
{
if(preferedProjekt == projekt.value)
ui->comboBoxProjekt->addItem(projekt.label % " (" % projekt.value % ')', projekt.value);
}
}
if(preferedProjekte.count())
{
ui->comboBoxProjekt->addItem(QStringLiteral("--------------"));
auto model = qobject_cast<const QStandardItemModel*>(ui->comboBoxProjekt->model());
auto item = model->item(ui->comboBoxProjekt->count() - 1);
item->setFlags(item->flags() & ~(Qt::ItemIsSelectable|Qt::ItemIsEnabled));
}
for(const auto &projekt : m_projekte)
{
if(!preferedProjekte.contains(projekt.value))
ui->comboBoxProjekt->addItem(projekt.label % " (" % projekt.value % ')', projekt.value);
}
}
ui->comboBoxSubprojekt->clear();
{
auto subprojekte = m_settings.value("subprojekte", QStringList()).toStringList();
for(const auto &subprojekt : subprojekte)
ui->comboBoxSubprojekt->addItem(subprojekt);
if(subprojekte.count())
ui->comboBoxSubprojekt->setCurrentText(QString());
}
ui->comboBoxWorkpackage->clear();
{
auto workpackages = m_settings.value("workpackages", QStringList()).toStringList();
for(const auto &workpackage : workpackages)
ui->comboBoxWorkpackage->addItem(workpackage);
if(workpackages.count())
ui->comboBoxWorkpackage->setCurrentText(QString());
}
ui->comboBoxText->clear();
{
auto texte = m_settings.value("texte", QStringList()).toStringList();
for(const auto &text : texte)
ui->comboBoxText->addItem(text);
if(texte.count())
ui->comboBoxText->setCurrentText(QString());
}
}
int MainWindow::timeToSeconds(const QTime &time)
{
return QTime(0, 0).secsTo(time);
}
QTime MainWindow::timeBetween(const QTime &l, const QTime &r)
{
Q_ASSERT(l <= r);
return QTime(0, 0).addSecs(l.secsTo(r));
}
QTime MainWindow::timeAdd(const QTime &l, const QTime &r)
{
Q_ASSERT(timeToSeconds(l) + timeToSeconds(r) < 86400);
return l.addSecs(QTime(0, 0).secsTo(r));
}
QTime MainWindow::timeNormalise(const QTime &time)
{
return time.addSecs(-time.second());
}

57
mainwindow.h Normal file
View File

@@ -0,0 +1,57 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "zeiterfassung.h"
namespace Ui { class MainWindow; }
class BuchungenModel;
class KontierungenModel;
class QSettings;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QSettings &settings, Zeiterfassung &erfassung, const Zeiterfassung::UserInfo &userInfo, QWidget *parent = 0);
~MainWindow();
private Q_SLOTS:
void refresh();
void getProjekteFinished(bool success, const QString &message, const QVector<Zeiterfassung::Projekt> &projekte);
void refreshBuchungenFinished(bool success, const QString &message);
void refreshKontierungenFinished(bool success, const QString &message);
void contextMenuBuchung(const QPoint &pos);
void contextMenuKontierung(const QPoint &pos);
void pushButtonPrevPressed();
void pushButtonNextPressed();
void pushButtonStartPressed();
void pushButtonEndPressed();
private:
void validateEntries();
void updateComboboxes();
static int timeToSeconds(const QTime &time);
static QTime timeBetween(const QTime &l, const QTime &r);
static QTime timeAdd(const QTime &l, const QTime &r);
static QTime timeNormalise(const QTime &time);
Ui::MainWindow *ui;
QSettings &m_settings;
Zeiterfassung &m_erfassung;
const Zeiterfassung::UserInfo &m_userInfo;
QVector<Zeiterfassung::Projekt> m_projekte;
BuchungenModel *m_buchungenModel;
KontierungenModel *m_kontierungenModel;
bool m_flag;
QTime m_kontierungTime;
QTime m_lastKontierungStart;
};
#endif // MAINWINDOW_H

322
mainwindow.ui Normal file
View File

@@ -0,0 +1,322 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1242</width>
<height>413</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QDateEdit" name="dateEditDate">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonPrev">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/zeiterfassung/images/previous.png</normaloff>:/zeiterfassung/images/previous.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonNext">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/zeiterfassung/images/next.png</normaloff>:/zeiterfassung/images/next.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QTimeEdit" name="timeEditTime">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxProjekt">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxSubprojekt">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxWorkpackage">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBoxText">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="insertPolicy">
<enum>QComboBox::NoInsert</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButtonStart">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButtonEnd">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>End</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QGroupBox" name="groupBoxBuchungen">
<property name="title">
<string>Buchungen</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeView" name="treeViewBuchungen">
<property name="enabled">
<bool>false</bool>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="groupBoxKontierungen">
<property name="title">
<string>Kontierungen</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QTreeView" name="treeViewKontierungen">
<property name="enabled">
<bool>false</bool>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1242</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>&amp;File</string>
</property>
<addaction name="actionQuit"/>
</widget>
<widget class="QMenu" name="menu_About">
<property name="title">
<string>&amp;About</string>
</property>
<addaction name="actionAboutMe"/>
<addaction name="actionAboutzeiterfassung"/>
<addaction name="actionAboutQt"/>
</widget>
<widget class="QMenu" name="menu_View">
<property name="title">
<string>&amp;View</string>
</property>
<addaction name="actionToday"/>
<addaction name="actionRefresh"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menu_View"/>
<addaction name="menu_About"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionQuit">
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/zeiterfassung/images/quit.png</normaloff>:/zeiterfassung/images/quit.png</iconset>
</property>
<property name="text">
<string>&amp;Quit</string>
</property>
</action>
<action name="actionAboutMe">
<property name="text">
<string>About &amp;Me</string>
</property>
</action>
<action name="actionAboutzeiterfassung">
<property name="text">
<string>About &amp;zeiterfassung</string>
</property>
</action>
<action name="actionAboutQt">
<property name="text">
<string>About &amp;Qt</string>
</property>
</action>
<action name="actionToday">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/zeiterfassung/images/today.png</normaloff>:/zeiterfassung/images/today.png</iconset>
</property>
<property name="text">
<string>&amp;Today</string>
</property>
</action>
<action name="actionRefresh">
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset resource="resources.qrc">
<normaloff>:/zeiterfassung/images/refresh.png</normaloff>:/zeiterfassung/images/refresh.png</iconset>
</property>
<property name="text">
<string>&amp;Refresh</string>
</property>
</action>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections>
<connection>
<sender>actionQuit</sender>
<signal>triggered()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>-1</x>
<y>-1</y>
</hint>
<hint type="destinationlabel">
<x>458</x>
<y>296</y>
</hint>
</hints>
</connection>
</connections>
</ui>

106
models/buchungenmodel.cpp Normal file
View File

@@ -0,0 +1,106 @@
#include "buchungenmodel.h"
BuchungenModel::BuchungenModel(Zeiterfassung &erfassung, QObject *parent) :
QAbstractListModel(parent),
m_erfassung(erfassung)
{
}
int BuchungenModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_buchungen.count();
}
int BuchungenModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 5;
}
QVariant BuchungenModel::data(const QModelIndex &index, int role) const
{
Q_ASSERT(index.row() < m_buchungen.count());
const auto &buchung = m_buchungen.at(index.row());
switch(role)
{
case Qt::DisplayRole:
case Qt::EditRole:
switch(index.column())
{
case 0: return buchung.id;
case 1: return buchung.time;
case 2: return buchung.timespan;
case 3: return buchung.type;
case 4: return buchung.text;
}
}
return QVariant();
}
QVariant BuchungenModel::headerData(int section, Qt::Orientation orientation, int role) const
{
switch(orientation)
{
case Qt::Horizontal:
switch(role)
{
case Qt::DisplayRole:
case Qt::EditRole:
switch(section)
{
case 0: return tr("ID");
case 1: return tr("Time");
case 2: return tr("Timespan");
case 3: return tr("Type");
case 4: return tr("Text");
}
}
}
return QVariant();
}
Zeiterfassung::Buchung BuchungenModel::getBuchung(const QModelIndex &index) const
{
if(!index.isValid())
return Zeiterfassung::Buchung();
Q_ASSERT(index.row() <= m_buchungen.count());
return m_buchungen.at(index.row());
}
bool BuchungenModel::refresh(int userId, const QDate &from, const QDate &to)
{
if(!m_erfassung.doGetBuchungen(userId, from, to))
return false;
beginResetModel();
m_buchungen.clear();
endResetModel();
connect(&m_erfassung, &Zeiterfassung::getBuchungenFinished,
this, &BuchungenModel::getBuchungenFinished);
return true;
}
void BuchungenModel::getBuchungenFinished(bool success, const QString &message, const QVector<Zeiterfassung::Buchung> &buchungen)
{
disconnect(&m_erfassung, &Zeiterfassung::getBuchungenFinished,
this, &BuchungenModel::getBuchungenFinished);
if(success)
{
beginResetModel();
m_buchungen = buchungen;
endResetModel();
}
Q_EMIT refreshFinished(success, message);
}

68
models/buchungenmodel.h Normal file
View File

@@ -0,0 +1,68 @@
#ifndef BUCHUNGENMODEL_H
#define BUCHUNGENMODEL_H
#include <QAbstractListModel>
#include <QVector>
#include "zeiterfassung.h"
class BuchungenModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit BuchungenModel(Zeiterfassung &erfassung, QObject *parent = nullptr);
// QAbstractItemModel interface
int rowCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
Zeiterfassung::Buchung getBuchung(const QModelIndex &index) const;
bool refresh(int userId, const QDate &from, const QDate &to);
typedef QVector<Zeiterfassung::Buchung>::iterator iterator;
typedef QVector<Zeiterfassung::Buchung>::const_iterator const_iterator;
typedef QVector<Zeiterfassung::Buchung>::reverse_iterator reverse_iterator;
typedef QVector<Zeiterfassung::Buchung>::const_reverse_iterator const_reverse_iterator;
#if !defined(QT_STRICT_ITERATORS) || defined(Q_QDOC)
//inline iterator begin() { return m_buchungen.begin(); }
inline const_iterator begin() const Q_DECL_NOTHROW { return m_buchungen.begin(); }
inline const_iterator cbegin() const Q_DECL_NOTHROW { return m_buchungen.cbegin(); }
inline const_iterator constBegin() const Q_DECL_NOTHROW { return m_buchungen.constBegin(); }
//inline iterator end() { return m_buchungen.end(); }
inline const_iterator end() const Q_DECL_NOTHROW { return m_buchungen.end(); }
inline const_iterator cend() const Q_DECL_NOTHROW { return m_buchungen.cend(); }
inline const_iterator constEnd() const Q_DECL_NOTHROW { return m_buchungen.constEnd(); }
#else
//inline iterator begin(iterator = iterator()) { return m_buchungen.begin(); }
inline const_iterator begin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_buchungen.begin(); }
inline const_iterator cbegin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constBegin(); }
inline const_iterator constBegin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_buchungen.constBegin(); }
//inline iterator end(iterator = iterator()) { return m_buchungen.end(); }
inline const_iterator end(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_buchungen.end(); }
inline const_iterator cend(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_buchungen.cend(); }
inline const_iterator constEnd(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_buchungen.constEnd(); }
#endif
//reverse_iterator rbegin() { return m_buchungen.rbegin(); }
//reverse_iterator rend() { return m_buchungen.rbegin(); }
const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return m_buchungen.rbegin(); }
const_reverse_iterator rend() const Q_DECL_NOTHROW { return m_buchungen.rend(); }
const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return m_buchungen.crbegin(); }
const_reverse_iterator crend() const Q_DECL_NOTHROW { return m_buchungen.crend(); }
Q_SIGNALS:
void refreshFinished(bool success, const QString &message);
private Q_SLOTS:
void getBuchungenFinished(bool success, const QString &message, const QVector<Zeiterfassung::Buchung> &buchungen);
private:
Zeiterfassung &m_erfassung;
QVector<Zeiterfassung::Buchung> m_buchungen;
};
#endif // BUCHUNGENMODEL_H

View File

@@ -0,0 +1,110 @@
#include "kontierungenmodel.h"
KontierungenModel::KontierungenModel(Zeiterfassung &erfassung, QObject *parent) :
QAbstractListModel(parent),
m_erfassung(erfassung)
{
}
int KontierungenModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_kontierungen.count();
}
int KontierungenModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 7;
}
QVariant KontierungenModel::data(const QModelIndex &index, int role) const
{
Q_ASSERT(index.row() < m_kontierungen.count());
const auto &kontierung = m_kontierungen.at(index.row());
switch(role)
{
case Qt::DisplayRole:
case Qt::EditRole:
switch(index.column())
{
case 0: return kontierung.id;
case 1: return kontierung.time;
case 2: return kontierung.timespan;
case 3: return kontierung.projekt;
case 4: return kontierung.subprojekt;
case 5: return kontierung.workpackage;
case 6: return kontierung.text;
}
}
return QVariant();
}
QVariant KontierungenModel::headerData(int section, Qt::Orientation orientation, int role) const
{
switch(orientation)
{
case Qt::Horizontal:
switch(role)
{
case Qt::DisplayRole:
case Qt::EditRole:
switch(section)
{
case 0: return tr("ID");
case 1: return tr("Time");
case 2: return tr("Timespan");
case 3: return tr("Projekt");
case 4: return tr("Subprojekt");
case 5: return tr("Workpackage");
case 6: return tr("Text");
}
}
}
return QVariant();
}
Zeiterfassung::Kontierung KontierungenModel::getKontierung(const QModelIndex &index) const
{
if(!index.isValid())
return Zeiterfassung::Kontierung();
Q_ASSERT(index.row() <= m_kontierungen.count());
return m_kontierungen.at(index.row());
}
bool KontierungenModel::refresh(int userId, const QDate &from, const QDate &to)
{
if(!m_erfassung.doGetKontierungen(userId, from, to))
return false;
beginResetModel();
m_kontierungen.clear();
endResetModel();
connect(&m_erfassung, &Zeiterfassung::getKontierungenFinished,
this, &KontierungenModel::getKontierungenFinished);
return true;
}
void KontierungenModel::getKontierungenFinished(bool success, const QString &message, const QVector<Zeiterfassung::Kontierung> &kontierungen)
{
disconnect(&m_erfassung, &Zeiterfassung::getKontierungenFinished,
this, &KontierungenModel::getKontierungenFinished);
if(success)
{
beginResetModel();
m_kontierungen = kontierungen;
endResetModel();
}
Q_EMIT refreshFinished(success, message);
}

View File

@@ -0,0 +1,68 @@
#ifndef KONTIERUNGENMODEL_H
#define KONTIERUNGENMODEL_H
#include <QAbstractListModel>
#include <QVector>
#include "zeiterfassung.h"
class KontierungenModel : public QAbstractListModel
{
Q_OBJECT
public:
explicit KontierungenModel(Zeiterfassung &erfassung, QObject *parent = nullptr);
// QAbstractItemModel interface
int rowCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
Zeiterfassung::Kontierung getKontierung(const QModelIndex &index) const;
bool refresh(int userId, const QDate &from, const QDate &to);
typedef QVector<Zeiterfassung::Kontierung>::iterator iterator;
typedef QVector<Zeiterfassung::Kontierung>::const_iterator const_iterator;
typedef QVector<Zeiterfassung::Kontierung>::reverse_iterator reverse_iterator;
typedef QVector<Zeiterfassung::Kontierung>::const_reverse_iterator const_reverse_iterator;
#if !defined(QT_STRICT_ITERATORS) || defined(Q_QDOC)
//inline iterator begin() { return m_kontierungen.begin(); }
inline const_iterator begin() const Q_DECL_NOTHROW { return m_kontierungen.begin(); }
inline const_iterator cbegin() const Q_DECL_NOTHROW { return m_kontierungen.cbegin(); }
inline const_iterator constBegin() const Q_DECL_NOTHROW { return m_kontierungen.constBegin(); }
//inline iterator end() { return m_kontierungen.end(); }
inline const_iterator end() const Q_DECL_NOTHROW { return m_kontierungen.end(); }
inline const_iterator cend() const Q_DECL_NOTHROW { return m_kontierungen.cend(); }
inline const_iterator constEnd() const Q_DECL_NOTHROW { return m_kontierungen.constEnd(); }
#else
//inline iterator begin(iterator = iterator()) { return m_kontierungen.begin(); }
inline const_iterator begin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_kontierungen.begin(); }
inline const_iterator cbegin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return d->constBegin(); }
inline const_iterator constBegin(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_kontierungen.constBegin(); }
//inline iterator end(iterator = iterator()) { return m_kontierungen.end(); }
inline const_iterator end(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_kontierungen.end(); }
inline const_iterator cend(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_kontierungen.cend(); }
inline const_iterator constEnd(const_iterator = const_iterator()) const Q_DECL_NOTHROW { return m_kontierungen.constEnd(); }
#endif
//reverse_iterator rbegin() { return m_kontierungen.rbegin(); }
//reverse_iterator rend() { return m_kontierungen.rbegin(); }
const_reverse_iterator rbegin() const Q_DECL_NOTHROW { return m_kontierungen.rbegin(); }
const_reverse_iterator rend() const Q_DECL_NOTHROW { return m_kontierungen.rend(); }
const_reverse_iterator crbegin() const Q_DECL_NOTHROW { return m_kontierungen.crbegin(); }
const_reverse_iterator crend() const Q_DECL_NOTHROW { return m_kontierungen.crend(); }
Q_SIGNALS:
void refreshFinished(bool success, const QString &message);
private Q_SLOTS:
void getKontierungenFinished(bool success, const QString &message, const QVector<Zeiterfassung::Kontierung> &kontierungen);
private:
Zeiterfassung &m_erfassung;
QVector<Zeiterfassung::Kontierung> m_kontierungen;
};
#endif // KONTIERUNGENMODEL_H

11
resources.qrc Normal file
View File

@@ -0,0 +1,11 @@
<RCC>
<qresource prefix="/zeiterfassung">
<file>images/splash.png</file>
<file>images/authentication.png</file>
<file>images/next.png</file>
<file>images/previous.png</file>
<file>images/quit.png</file>
<file>images/refresh.png</file>
<file>images/today.png</file>
</qresource>
</RCC>

8
zeiterfassung.conf Normal file
View File

@@ -0,0 +1,8 @@
[General]
password=HAHA
projekte=0000001142, 0000010001, SONSTIGES
subprojekte=
texte=
url=http://localhost:8080/evoApps/
username=danielb
workpackages=[D.1315], [M.0200]

817
zeiterfassung.cpp Normal file
View File

@@ -0,0 +1,817 @@
#include "zeiterfassung.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonParseError>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QStringBuilder>
QString QJsonValue::toString() const{ return toString(QString()); }
Zeiterfassung::Zeiterfassung(const QString &url, QObject *parent) :
QObject(parent),
m_url(url),
m_manager(new QNetworkAccessManager(this)),
m_replies { Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR,
Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR }
{
}
const QString &Zeiterfassung::url() const
{
return m_url;
}
void Zeiterfassung::setUrl(const QString &url)
{
if(m_url != url)
Q_EMIT urlChanged(m_url = url);
}
bool Zeiterfassung::doLoginPage()
{
if(m_replies.login)
{
qWarning() << "another loginPage already processing!";
return false;
}
QNetworkRequest request(QUrl(m_url % "pages/login.jsp"));
m_replies.loginPage = m_manager->get(request);
connect(m_replies.loginPage, &QNetworkReply::finished, this, &Zeiterfassung::loginPageRequestFinished);
return true;
}
bool Zeiterfassung::doLogin(const QString &username, const QString &password)
{
if(m_replies.login)
{
qWarning() << "another login already processing!";
return false;
}
QNetworkRequest request(QUrl(m_url % "pages/j_spring_security_check"));
request.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/x-www-form-urlencoded"));
request.setMaximumRedirectsAllowed(0);
m_replies.login = m_manager->post(request, QStringLiteral("j_username=%0&j_password=%1&login=Anmelden").arg(username).arg(password).toUtf8());
connect(m_replies.login, &QNetworkReply::finished, this, &Zeiterfassung::loginRequestFinished);
return true;
}
bool Zeiterfassung::doUserInfo()
{
if(m_replies.userInfo)
{
qWarning() << "another userInfo already processing!";
return false;
}
QNetworkRequest request(QUrl(m_url % "json/evoAppsUserInfoDialogController/load-EvoAppsUserInfoTO"));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("home"));
m_replies.userInfo = m_manager->get(request);
connect(m_replies.userInfo, &QNetworkReply::finished, this, &Zeiterfassung::userInfoRequestFinished);
return true;
}
bool Zeiterfassung::doGetBuchungen(int userId, const QDate &start, const QDate &end)
{
if(m_replies.getBuchungen)
{
qWarning() << "another getBuchungen already processing!";
return false;
}
QNetworkRequest request(QUrl(QStringLiteral("%0json/bookings?start=%1&end=%2&pnrLst=%3")
.arg(m_url)
.arg(start.toString(QStringLiteral("yyyyMMdd")))
.arg(end.toString(QStringLiteral("yyyyMMdd")))
.arg(userId)));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("bookingCalendar"));
m_replies.getBuchungen = m_manager->get(request);
connect(m_replies.getBuchungen, &QNetworkReply::finished,
this, &Zeiterfassung::getBuchungenRequestFinished);
return true;
}
bool Zeiterfassung::doCreateBuchung(int userId, const QDate &date, const QTime &time, const QTime &timespan, const QString &type, const QString &text)
{
if(m_replies.createBuchung)
{
qWarning() << "another createBuchung already processing!";
return false;
}
QNetworkRequest request(QUrl(m_url % "json/booking"));
request.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("bookingCalendar"));
QJsonObject obj;
obj[QStringLiteral("persNr")] = userId;
obj[QStringLiteral("bookingDate")] = date.toString("yyyyMMdd").toInt();
obj[QStringLiteral("bookingTime")] = time.toString("Hmmss").toInt();
obj[QStringLiteral("bookingTimespan")] = timespan.toString("Hmmss").toInt();
obj[QStringLiteral("bookingType")] = type;
obj[QStringLiteral("hourCategory")] = QStringLiteral("");
obj[QStringLiteral("empfEinh")] = QStringLiteral("");
obj[QStringLiteral("bewEinh")] = QStringLiteral("");
obj[QStringLiteral("text")] = text;
m_replies.createBuchung = m_manager->post(request, QJsonDocument(obj).toJson());
connect(m_replies.createBuchung, &QNetworkReply::finished,
this, &Zeiterfassung::createBuchungRequestFinished);
return true;
}
bool Zeiterfassung::doUpdateBuchung(int buchungId, int userId, const QDate &date, const QTime &time, const QTime &timespan, const QString &type, const QString &text)
{
if(m_replies.updateBuchung)
{
qWarning() << "another updateBuchung already processing!";
return false;
}
QNetworkRequest request(QUrl(QStringLiteral("%0json/booking/%1").arg(m_url).arg(buchungId)));
request.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("bookingCalendar"));
QJsonObject obj;
obj[QStringLiteral("bookingNr")] = buchungId;
obj[QStringLiteral("persNr")] = userId;
obj[QStringLiteral("bookingDate")] = date.toString("yyyyMMdd").toInt();
obj[QStringLiteral("bookingTime")] = time.toString("Hmmss").toInt();
obj[QStringLiteral("bookingTimespan")] = timespan.toString("Hmmss").toInt();
obj[QStringLiteral("bookingType")] = type;
obj[QStringLiteral("hourCategory")] = QStringLiteral("");
obj[QStringLiteral("empfEinh")] = QStringLiteral("");
obj[QStringLiteral("bewEinh")] = QStringLiteral("");
obj[QStringLiteral("text")] = text;
m_replies.updateBuchung = m_manager->put(request, QJsonDocument(obj).toJson());
connect(m_replies.updateBuchung, &QNetworkReply::finished,
this, &Zeiterfassung::updateBuchungRequestFinished);
return true;
}
bool Zeiterfassung::doDeleteBuchung(int buchungId)
{
if(m_replies.deleteBuchung)
{
qWarning() << "another deleteBuchung already processing!";
return false;
}
QNetworkRequest request(QUrl(QStringLiteral("%0json/booking/%1?text=")
.arg(m_url)
.arg(buchungId)));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("bookingCalendar"));
m_replies.deleteBuchung = m_manager->deleteResource(request);
connect(m_replies.deleteBuchung, &QNetworkReply::finished,
this, &Zeiterfassung::deleteBuchungRequestFinished);
return true;
}
bool Zeiterfassung::doGetKontierungen(int userId, const QDate &start, const QDate &end)
{
if(m_replies.getKontierungen)
{
qWarning() << "another getKontierungen already processing!";
return false;
}
QNetworkRequest request(QUrl(QStringLiteral("%0json/azebooking?start=%1&end=%2&pnrLst=%3")
.arg(m_url)
.arg(start.toString(QStringLiteral("yyyyMMdd")))
.arg(end.toString(QStringLiteral("yyyyMMdd")))
.arg(userId)));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("bookingCalendar"));
m_replies.getKontierungen = m_manager->get(request);
connect(m_replies.getKontierungen, &QNetworkReply::finished,
this, &Zeiterfassung::getKontierungenRequestFinished);
return true;
}
bool Zeiterfassung::doCreateKontierung(int userId, const QDate &date, const QTime &time, const QTime &timespan, const QString &projekt, const QString &subprojekt, const QString &workpackage, const QString &text)
{
if(m_replies.createKontierung)
{
qWarning() << "another createKontierung already processing!";
return false;
}
QNetworkRequest request(QUrl(m_url % "json/azebooking"));
request.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("bookingCalendar"));
QJsonObject obj;
obj[QStringLiteral("bookingNr")] = QJsonValue::Null;
obj[QStringLiteral("persNr")] = userId;
obj[QStringLiteral("bookingDate")] = date.toString("yyyyMMdd").toInt();
obj[QStringLiteral("bookingTime")] = time.toString("Hmmss").toInt();
obj[QStringLiteral("bookingTimespan")] = timespan.toString("Hmmss").toInt();
obj[QStringLiteral("text")] = text;
{
QJsonArray koWertList;
{
QJsonObject obj;
obj[QStringLiteral("value")] = projekt;
koWertList << obj;
}
{
QJsonObject obj;
obj[QStringLiteral("value")] = subprojekt;
koWertList << obj;
}
{
QJsonObject obj;
obj[QStringLiteral("value")] = workpackage;
koWertList << obj;
}
obj[QStringLiteral("koWertList")] = koWertList;
}
m_replies.createKontierung = m_manager->post(request, QJsonDocument(obj).toJson());
connect(m_replies.createKontierung, &QNetworkReply::finished,
this, &Zeiterfassung::createKontierungRequestFinished);
return true;
}
bool Zeiterfassung::doUpdateKontierung(int kontierungId, int userId, const QDate &date, const QTime &time, const QTime &timespan, const QString &projekt, const QString &subprojekt, const QString &workpackage, const QString &text)
{
if(m_replies.updateKontierung)
{
qWarning() << "another updateKontierung already processing!";
return false;
}
QNetworkRequest request(QUrl(QStringLiteral("%0json/azebooking/%1").arg(m_url).arg(kontierungId)));
request.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json"));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("bookingCalendar"));
QJsonObject obj;
obj[QStringLiteral("bookingNr")] = kontierungId;
obj[QStringLiteral("persNr")] = userId;
obj[QStringLiteral("bookingDate")] = date.toString("yyyyMMdd").toInt();
obj[QStringLiteral("bookingTime")] = time.toString("Hmmss").toInt();
obj[QStringLiteral("bookingTimespan")] = timespan.toString("Hmmss").toInt();
obj[QStringLiteral("bookingType")] = QJsonValue::Null;
obj[QStringLiteral("hourCategory")] = QJsonValue::Null;
obj[QStringLiteral("bewEinh")] = QJsonValue::Null;
obj[QStringLiteral("empfEinh")] = QJsonValue::Null;
obj[QStringLiteral("einstuf")] = 0;
obj[QStringLiteral("text")] = text;
{
QJsonArray koWertList;
{
QJsonObject obj;
obj[QStringLiteral("value")] = projekt;
koWertList << obj;
}
{
QJsonObject obj;
obj[QStringLiteral("value")] = subprojekt;
koWertList << obj;
}
{
QJsonObject obj;
obj[QStringLiteral("value")] = workpackage;
koWertList << obj;
}
obj[QStringLiteral("koWertList")] = koWertList;
}
m_replies.updateKontierung = m_manager->put(request, QJsonDocument(obj).toJson());
connect(m_replies.updateKontierung, &QNetworkReply::finished,
this, &Zeiterfassung::updateKontierungRequestFinished);
return true;
}
bool Zeiterfassung::doDeleteKontierung(int kontierungId)
{
if(m_replies.deleteKontierung)
{
qWarning() << "another deleteKontierung already processing!";
return false;
}
QNetworkRequest request(QUrl(QStringLiteral("%0json/azebooking/%1")
.arg(m_url)
.arg(kontierungId)));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("bookingCalendar"));
m_replies.deleteKontierung = m_manager->deleteResource(request);
connect(m_replies.deleteKontierung, &QNetworkReply::finished,
this, &Zeiterfassung::deleteKontierungRequestFinished);
return true;
}
bool Zeiterfassung::doGetProjekte(int userId, QDate date)
{
if(m_replies.getProjekte)
{
qWarning() << "another getProjekte already processing!";
return false;
}
QNetworkRequest request(QUrl(QStringLiteral("%0json/combobox?persnr=%1&date=%2&dqkey=KOST&kowert0=&kowert1=&kowert2=&term=")
.arg(m_url)
.arg(userId)
.arg(date.toString(QStringLiteral("yyyyMMdd")))));
request.setRawHeader(QByteArrayLiteral("sisAppName"), QByteArrayLiteral("bookingCalendar"));
m_replies.getProjekte = m_manager->get(request);
connect(m_replies.getProjekte, &QNetworkReply::finished, this, &Zeiterfassung::getProjekteRequestFinished);
return true;
}
void Zeiterfassung::loginPageRequestFinished()
{
if(m_replies.loginPage->error() != QNetworkReply::NoError)
{
Q_EMIT loginPageFinished(false, tr("Request error occured: %0").arg(m_replies.loginPage->error()));
goto end;
}
if(!m_replies.loginPage->readAll().contains(QByteArrayLiteral("evoApps Anmeldung")))
{
Q_EMIT loginPageFinished(false, tr("Could not find necessary keywords in login page!"));
goto end;
}
Q_EMIT loginPageFinished(true, QString());
end:
m_replies.loginPage->deleteLater();
m_replies.loginPage = Q_NULLPTR;
}
void Zeiterfassung::loginRequestFinished()
{
if(m_replies.login->error() != QNetworkReply::NoError)
{
Q_EMIT loginFinished(false, tr("Request error occured: %0").arg(m_replies.login->error()));
goto end;
}
if(!m_replies.login->hasRawHeader(QByteArrayLiteral("Location")))
{
Q_EMIT loginFinished(false, tr("Request did not contain a Location header."));
goto end;
}
{
auto location = m_replies.login->rawHeader(QByteArrayLiteral("Location"));
if(location == QByteArrayLiteral("/evoApps/pages/home.jsp"))
{
Q_EMIT loginFinished(true, QString());
goto end;
}
else if(location == QByteArrayLiteral("/evoApps/pages/login.jsp?error=user"))
{
Q_EMIT loginFinished(false, tr("Authentication failure. Please check username and password."));
goto end;
}
else
{
Q_EMIT loginFinished(false, tr("An unknown authentication failure occured. Redirected to: %0").arg(QString(location)));
goto end;
}
}
end:
m_replies.login->deleteLater();
m_replies.login = Q_NULLPTR;
}
void Zeiterfassung::userInfoRequestFinished()
{
if(m_replies.userInfo->error() != QNetworkReply::NoError)
{
Q_EMIT userInfoFinished(false, tr("Request error occured: %0").arg(m_replies.userInfo->error()), UserInfo());
goto end;
}
{
QJsonParseError error;
auto document = QJsonDocument::fromJson(m_replies.userInfo->readAll(), &error);
if(error.error != QJsonParseError::NoError)
{
Q_EMIT userInfoFinished(false, tr("Parsing JSON failed: %0").arg(error.errorString()), UserInfo());
goto end;
}
if(!document.isObject())
{
Q_EMIT userInfoFinished(false, tr("JSON document is not an object!"), UserInfo());
goto end;
}
auto rootObj = document.object();
if(!rootObj.contains(QStringLiteral("evoAppsUser")))
{
Q_EMIT userInfoFinished(false, tr("JSON does not contain evoAppsUser!"), UserInfo());
goto end;
}
auto evoAppsUser = rootObj.value(QStringLiteral("evoAppsUser"));
if(!evoAppsUser.isObject())
{
Q_EMIT userInfoFinished(false, tr("evoAppsUser is not an object!"), UserInfo());
goto end;
}
auto evoAppsUserObj = evoAppsUser.toObject();
Q_EMIT userInfoFinished(true, QString(), {
evoAppsUserObj.value(QStringLiteral("persNr")).toInt(),
evoAppsUserObj.value(QStringLiteral("email")).toString(),
evoAppsUserObj.value(QStringLiteral("longUsername")).toString(),
evoAppsUserObj.value(QStringLiteral("text")).toString(),
evoAppsUserObj.value(QStringLiteral("username")).toString()
});
}
end:
m_replies.userInfo->deleteLater();
m_replies.userInfo = Q_NULLPTR;
}
void Zeiterfassung::getBuchungenRequestFinished()
{
if(m_replies.getBuchungen->error() != QNetworkReply::NoError)
{
Q_EMIT getBuchungenFinished(false, tr("Request error occured: %0").arg(m_replies.getBuchungen->error()), {});
goto end;
}
{
QJsonParseError error;
QJsonDocument document = QJsonDocument::fromJson(m_replies.getBuchungen->readAll(), &error);
if(error.error != QJsonParseError::NoError)
{
Q_EMIT getBuchungenFinished(false, tr("Parsing JSON failed: %0").arg(error.errorString()), {});
goto end;
}
if(!document.isArray())
{
Q_EMIT getBuchungenFinished(false, tr("JSON document is not an array!"), {});
goto end;
}
auto arr = document.array();
QVector<Buchung> buchungen;
for(const auto &val : arr)
{
auto obj = val.toObject();
buchungen.append({
obj.value(QStringLiteral("bookingNr")).toInt(),
QDate::fromString(QString::number(obj.value(QStringLiteral("bookingDate")).toInt()), QStringLiteral("yyyyMMdd")),
QTime::fromString(QString("%0").arg(obj.value(QStringLiteral("bookingTime")).toInt(), 6, 10, QChar('0')), QStringLiteral("HHmmss")),
QTime::fromString(QString("%0").arg(obj.value(QStringLiteral("bookingTimespan")).toInt(), 6, 10, QChar('0')), QStringLiteral("HHmmss")),
obj.value(QStringLiteral("bookingType")).toString(),
obj.value(QStringLiteral("text")).toString()
});
}
Q_EMIT getBuchungenFinished(true, QString(), buchungen);
}
end:
m_replies.getBuchungen->deleteLater();
m_replies.getBuchungen = Q_NULLPTR;
}
void Zeiterfassung::createBuchungRequestFinished()
{
if(m_replies.createBuchung->error() != QNetworkReply::NoError)
{
Q_EMIT createBuchungFinished(false, tr("Request error occured: %0").arg(m_replies.createBuchung->error()), -1);
goto end;
}
{
QJsonParseError error;
QJsonDocument document = QJsonDocument::fromJson(m_replies.createBuchung->readAll(), &error);
if(error.error != QJsonParseError::NoError)
{
Q_EMIT createBuchungFinished(false, tr("Parsing JSON failed: %0").arg(error.errorString()), -1);
goto end;
}
if(!document.isObject())
{
Q_EMIT createBuchungFinished(false, tr("JSON document is not an object!"), -1);
goto end;
}
auto obj = document.object();
if(!obj.contains(QStringLiteral("bookingNr")))
{
Q_EMIT createBuchungFinished(false, tr("JSON does not contain bookingNr!"), -1);
goto end;
}
auto buchungId = obj.value(QStringLiteral("bookingNr")).toInt();
Q_EMIT createBuchungFinished(true, QString(), buchungId);
}
end:
m_replies.createBuchung->deleteLater();
m_replies.createBuchung = Q_NULLPTR;
}
void Zeiterfassung::updateBuchungRequestFinished()
{
if(m_replies.updateBuchung->error() != QNetworkReply::NoError)
{
Q_EMIT updateBuchungFinished(false, tr("Request error occured: %0").arg(m_replies.updateBuchung->error()), -1);
goto end;
}
{
QJsonParseError error;
QJsonDocument document = QJsonDocument::fromJson(m_replies.updateBuchung->readAll(), &error);
if(error.error != QJsonParseError::NoError)
{
Q_EMIT updateBuchungFinished(false, tr("Parsing JSON failed: %0").arg(error.errorString()), -1);
goto end;
}
if(!document.isObject())
{
Q_EMIT updateBuchungFinished(false, tr("JSON document is not an object!"), -1);
goto end;
}
auto obj = document.object();
if(!obj.contains(QStringLiteral("bookingNr")))
{
Q_EMIT updateBuchungFinished(false, tr("JSON does not contain bookingNr!"), -1);
goto end;
}
auto buchungId = obj.value(QStringLiteral("bookingNr")).toInt();
Q_EMIT updateBuchungFinished(true, QString(), buchungId);
}
end:
m_replies.updateBuchung->deleteLater();
m_replies.updateBuchung = Q_NULLPTR;
}
void Zeiterfassung::deleteBuchungRequestFinished()
{
if(m_replies.deleteBuchung->error() != QNetworkReply::NoError)
{
Q_EMIT deleteBuchungFinished(false, tr("Request error occured: %0").arg(m_replies.deleteBuchung->error()));
goto end;
}
//should be empty, so nothing to check...
Q_EMIT deleteBuchungFinished(true, QString());
end:
m_replies.deleteBuchung->deleteLater();
m_replies.deleteBuchung = Q_NULLPTR;
}
void Zeiterfassung::getKontierungenRequestFinished()
{
if(m_replies.getKontierungen->error() != QNetworkReply::NoError)
{
Q_EMIT getKontierungenFinished(false, tr("Request error occured: %0").arg(m_replies.getKontierungen->error()), {});
goto end;
}
{
QJsonParseError error;
QJsonDocument document = QJsonDocument::fromJson(m_replies.getKontierungen->readAll(), &error);
if(error.error != QJsonParseError::NoError)
{
Q_EMIT getKontierungenFinished(false, tr("Parsing JSON failed: %0").arg(error.errorString()), {});
goto end;
}
if(!document.isArray())
{
Q_EMIT getKontierungenFinished(false, tr("JSON document is not an array!"), {});
goto end;
}
auto arr = document.array();
QVector<Kontierung> kontierungen;
for(const auto &val : arr)
{
auto obj = val.toObject();
auto koWertList = obj.value(QStringLiteral("koWertList")).toArray();
kontierungen.append({
obj.value(QStringLiteral("bookingNr")).toInt(),
QDate::fromString(QString::number(obj.value(QStringLiteral("bookingDate")).toInt()), QStringLiteral("yyyyMMdd")),
QTime::fromString(QString("%0").arg(obj.value(QStringLiteral("bookingTime")).toInt(), 6, 10, QChar('0')), QStringLiteral("HHmmss")),
QTime::fromString(QString("%0").arg(obj.value(QStringLiteral("bookingTimespan")).toInt(), 6, 10, QChar('0')), QStringLiteral("HHmmss")),
obj.value(QStringLiteral("text")).toString(),
koWertList.at(0).toObject().value(QStringLiteral("value")).toString(),
koWertList.at(1).toObject().value(QStringLiteral("value")).toString(),
koWertList.at(2).toObject().value(QStringLiteral("value")).toString()
});
}
Q_EMIT getKontierungenFinished(true, QString(), kontierungen);
}
end:
m_replies.getKontierungen->deleteLater();
m_replies.getKontierungen = Q_NULLPTR;
}
void Zeiterfassung::createKontierungRequestFinished()
{
if(m_replies.createKontierung->error() != QNetworkReply::NoError)
{
Q_EMIT createKontierungFinished(false, tr("Request error occured: %0").arg(m_replies.createKontierung->error()), -1);
goto end;
}
{
QJsonParseError error;
QJsonDocument document = QJsonDocument::fromJson(m_replies.createKontierung->readAll(), &error);
if(error.error != QJsonParseError::NoError)
{
Q_EMIT createKontierungFinished(false, tr("Parsing JSON failed: %0").arg(error.errorString()), -1);
goto end;
}
if(!document.isObject())
{
Q_EMIT createKontierungFinished(false, tr("JSON document is not an object!"), -1);
goto end;
}
auto obj = document.object();
if(!obj.contains(QStringLiteral("bookingNr")))
{
Q_EMIT createKontierungFinished(false, tr("JSON does not contain bookingNr!"), -1);
goto end;
}
auto kontierungId = obj.value(QStringLiteral("bookingNr")).toInt();
Q_EMIT createKontierungFinished(true, QString(), kontierungId);
}
end:
m_replies.createKontierung->deleteLater();
m_replies.createKontierung = Q_NULLPTR;
}
void Zeiterfassung::updateKontierungRequestFinished()
{
if(m_replies.updateKontierung->error() != QNetworkReply::NoError)
{
Q_EMIT updateKontierungFinished(false, tr("Request error occured: %0").arg(m_replies.updateKontierung->error()), -1);
goto end;
}
{
QJsonParseError error;
QJsonDocument document = QJsonDocument::fromJson(m_replies.updateKontierung->readAll(), &error);
if(error.error != QJsonParseError::NoError)
{
Q_EMIT updateKontierungFinished(false, tr("Parsing JSON failed: %0").arg(error.errorString()), -1);
goto end;
}
if(!document.isObject())
{
Q_EMIT updateKontierungFinished(false, tr("JSON document is not an object!"), 0);
goto end;
}
auto obj = document.object();
if(!obj.contains(QStringLiteral("bookingNr")))
{
Q_EMIT updateKontierungFinished(false, tr("JSON does not contain bookingNr!"), 0);
goto end;
}
auto kontierungId = obj.value(QStringLiteral("bookingNr")).toInt();
Q_EMIT updateKontierungFinished(true, QString(), kontierungId);
}
end:
m_replies.updateKontierung->deleteLater();
m_replies.updateKontierung = Q_NULLPTR;
}
void Zeiterfassung::deleteKontierungRequestFinished()
{
if(m_replies.deleteKontierung->error() != QNetworkReply::NoError)
{
Q_EMIT deleteKontierungFinished(false, tr("Request error occured: %0").arg(m_replies.deleteKontierung->error()));
goto end;
}
//only contains deleted id, so nothing to check here
Q_EMIT deleteKontierungFinished(true, QString());
end:
m_replies.deleteKontierung->deleteLater();
m_replies.deleteKontierung = Q_NULLPTR;
}
void Zeiterfassung::getProjekteRequestFinished()
{
if(m_replies.getProjekte->error() != QNetworkReply::NoError)
{
Q_EMIT getProjekteFinished(false, tr("Request error occured: %0").arg(m_replies.getProjekte->error()), {});
goto end;
}
{
QJsonParseError error;
QJsonDocument document = QJsonDocument::fromJson(m_replies.getProjekte->readAll(), &error);
if(error.error != QJsonParseError::NoError)
{
Q_EMIT getProjekteFinished(false, tr("Parsing JSON failed: %0").arg(error.errorString()), {});
goto end;
}
if(!document.isObject())
{
Q_EMIT getProjekteFinished(false, tr("JSON document is not an object!"), {});
goto end;
}
auto rootObj = document.object();
if(!rootObj.contains(QStringLiteral("elements")))
{
Q_EMIT getProjekteFinished(false, tr("JSON does not contain elements!"), {});
goto end;
}
auto elements = rootObj.value(QStringLiteral("elements"));
if(!elements.isArray())
{
Q_EMIT getProjekteFinished(false, tr("elements is not an array!"), {});
goto end;
}
auto elementsArr = elements.toArray();
QVector<Projekt> projekte;
for(const auto &val : elementsArr)
{
auto obj = val.toObject();
projekte.append({
obj.value(QStringLiteral("label")).toString(),
obj.value(QStringLiteral("value")).toString()
});
}
Q_EMIT getProjekteFinished(true, QString(), projekte);
}
end:
m_replies.getProjekte->deleteLater();
m_replies.getProjekte = Q_NULLPTR;
}

142
zeiterfassung.h Normal file
View File

@@ -0,0 +1,142 @@
#ifndef ZEITERFASSUNG_H
#define ZEITERFASSUNG_H
#include <QObject>
#include <QString>
#include <QDate>
#include <QTime>
class QNetworkAccessManager;
class QNetworkReply;
class Zeiterfassung : public QObject
{
Q_OBJECT
Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
public:
explicit Zeiterfassung(const QString &url, QObject *parent = 0);
const QString &url() const;
void setUrl(const QString &url);
struct UserInfo
{
int userId;
QString email;
QString longUsername;
QString text;
QString username;
};
struct Buchung
{
int id;
QDate date;
QTime time;
QTime timespan;
QString type;
QString text;
};
struct Kontierung
{
int id;
QDate date;
QTime time;
QTime timespan;
QString text;
QString projekt;
QString subprojekt;
QString workpackage;
};
struct Projekt
{
QString label;
QString value;
};
public Q_SLOTS:
bool doLoginPage();
bool doLogin(const QString &username, const QString &password);
bool doUserInfo();
bool doGetBuchungen(int userId, const QDate &start, const QDate &end);
bool doCreateBuchung(int userId, const QDate &date, const QTime &time, const QTime &timespan,
const QString &type, const QString &text);
bool doUpdateBuchung(int buchungId, int userId, const QDate &date, const QTime &time,
const QTime &timespan, const QString &type, const QString &text);
bool doDeleteBuchung(int buchungId);
bool doGetKontierungen(int userId, const QDate &start, const QDate &end);
bool doCreateKontierung(int userId, const QDate &date, const QTime &time, const QTime &timespan,
const QString &projekt, const QString &subprojekt, const QString &workpackage,
const QString &text);
bool doUpdateKontierung(int kontierungId, int userId, const QDate &date, const QTime &time,
const QTime &timespan, const QString &projekt, const QString &subprojekt,
const QString &workpackage, const QString &text);
bool doDeleteKontierung(int kontierungId);
bool doGetProjekte(int userId, QDate date = QDate::currentDate());
Q_SIGNALS:
void urlChanged(const QString &url);
void loginPageFinished(bool success, const QString &message);
void loginFinished(bool success, const QString &message);
void userInfoFinished(bool success, const QString &message, const UserInfo &userInfo);
void getBuchungenFinished(bool success, const QString &message, const QVector<Buchung> &buchungen);
void createBuchungFinished(bool success, const QString &message, int buchungId);
void updateBuchungFinished(bool success, const QString &message, int buchungId);
void deleteBuchungFinished(bool success, const QString &message);
void getKontierungenFinished(bool success, const QString &message, const QVector<Kontierung> &kontierungen);
void createKontierungFinished(bool success, const QString &message, int buchungId);
void updateKontierungFinished(bool success, const QString &message, int buchungId);
void deleteKontierungFinished(bool success, const QString &message);
void getProjekteFinished(bool success, const QString &message, const QVector<Projekt> &projekte);
private Q_SLOTS:
void loginPageRequestFinished();
void loginRequestFinished();
void userInfoRequestFinished();
void getBuchungenRequestFinished();
void createBuchungRequestFinished();
void updateBuchungRequestFinished();
void deleteBuchungRequestFinished();
void getKontierungenRequestFinished();
void createKontierungRequestFinished();
void updateKontierungRequestFinished();
void deleteKontierungRequestFinished();
void getProjekteRequestFinished();
private:
QString m_url;
QNetworkAccessManager *m_manager;
struct {
QNetworkReply *loginPage;
QNetworkReply *login;
QNetworkReply *userInfo;
QNetworkReply *getBuchungen;
QNetworkReply *createBuchung;
QNetworkReply *updateBuchung;
QNetworkReply *deleteBuchung;
QNetworkReply *getKontierungen;
QNetworkReply *createKontierung;
QNetworkReply *updateKontierung;
QNetworkReply *deleteKontierung;
QNetworkReply *getProjekte;
} m_replies;
};
#endif // ZEITERFASSUNG_H

47
zeiterfassung.pro Executable file
View File

@@ -0,0 +1,47 @@
QT += network gui widgets
CONFIG += c++11
CONFIG -= app_bundle
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp \
zeiterfassung.cpp \
mainwindow.cpp \
dialogs/aboutmedialog.cpp \
dialogs/authenticationdialog.cpp \
dialogs/buchungdialog.cpp \
models/buchungenmodel.cpp \
dialogs/kontierungdialog.cpp \
models/kontierungenmodel.cpp \
eventloopwithstatus.cpp
HEADERS += \
zeiterfassung.h \
mainwindow.h \
dialogs/aboutmedialog.h \
dialogs/authenticationdialog.h \
dialogs/buchungdialog.h \
models/buchungenmodel.h \
dialogs/kontierungdialog.h \
models/kontierungenmodel.h \
eventloopwithstatus.h
RESOURCES += \
resources.qrc
FORMS += \
mainwindow.ui \
dialogs/aboutmedialog.ui \
dialogs/authenticationdialog.ui \
dialogs/buchungdialog.ui \
dialogs/kontierungdialog.ui