Imported existing sources

This commit is contained in:
0xFEEDC0DE64
2018-09-17 19:34:33 +02:00
parent 552fe27936
commit af02fa79fd
15 changed files with 680 additions and 0 deletions

84
absencedialog.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include "absencedialog.h"
#include "ui_absencedialog.h"
#include <QDate>
#include <QLocale>
#include <QMessageBox>
#include <QStringBuilder>
#include <QMenu>
#include <QAction>
#include "absencesmodel.h"
AbsenceDialog::AbsenceDialog(int userId, const QDate &date, ZeiterfassungApi &erfassung, QWidget *parent) :
ZeiterfassungDialog(parent),
ui(new Ui::AbsenceDialog)
{
ui->setupUi(this);
ui->labelTitle->setText(tr("Absences for %0").arg(QLocale().toString(date)));
m_model = new AbsencesModel(userId, date, erfassung, this);
connect(m_model, &AbsencesModel::errorOccured, this, &AbsenceDialog::errorOccured);
ui->treeView->setModel(m_model);
ui->treeView->setEnabled(m_model->enabled());
connect(m_model, &AbsencesModel::enabledChanged, ui->treeView, &QWidget::setEnabled);
connect(ui->treeView, &QWidget::customContextMenuRequested, this, &AbsenceDialog::customContextMenuRequested);
}
AbsenceDialog::~AbsenceDialog()
{
delete ui;
}
void AbsenceDialog::errorOccured(const QString &message)
{
QMessageBox::warning(this, tr("Could not load absences!"), tr("Could not load absences!") % "\n\n" % message);
}
void AbsenceDialog::customContextMenuRequested(const QPoint &pos)
{
auto index = ui->treeView->indexAt(pos);
if(!index.isValid())
{
QMenu menu;
auto createAction = menu.addAction(tr("Create absence"));
auto refreshAction = menu.addAction(QIcon(QPixmap(QStringLiteral(":/zeiterfassungguilib/images/refresh.png"))), tr("Refresh absences"));
auto selectedAction = menu.exec(ui->treeView->viewport()->mapToGlobal(pos));
if(selectedAction == createAction)
{
//TODO
}
else if(selectedAction == refreshAction)
{
m_model->refresh();
}
}
else
{
auto absence = m_model->absences().at(index.row());
QMenu menu;
auto editAction = menu.addAction(tr("Edit absence"));
auto deleteAction = menu.addAction(tr("Delete absence"));
auto selectedAction = menu.exec(ui->treeView->viewport()->mapToGlobal(pos));
if(selectedAction == editAction)
{
//TODO
}
else if(selectedAction == deleteAction)
{
QMessageBox msgBox;
msgBox.setText(tr("Do you really want to delete the absence?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
if(msgBox.exec() == QMessageBox::Yes)
{
//TODO
}
}
}
}

28
absencedialog.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include "zeiterfassungdialog.h"
class QDate;
class ZeiterfassungApi;
class AbsencesModel;
namespace Ui { class AbsenceDialog; }
class AbsenceDialog : public ZeiterfassungDialog
{
Q_OBJECT
public:
explicit AbsenceDialog(int userId, const QDate &date, ZeiterfassungApi &erfassung, QWidget *parent = 0);
~AbsenceDialog();
private Q_SLOTS:
void errorOccured(const QString &message);
void customContextMenuRequested(const QPoint &pos);
private:
Ui::AbsenceDialog *ui;
AbsencesModel *m_model;
};

83
absencedialog.ui Normal file
View File

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AbsenceDialog</class>
<widget class="QDialog" name="AbsenceDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>947</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Absences</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,0">
<item>
<widget class="QLabel" name="labelTitle">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string notr="true">Absences for</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeView" name="treeView">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AbsenceDialog</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>AbsenceDialog</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>

38
absenceplugin.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include "absenceplugin.h"
#include <QDebug>
#include <QDir>
#include <QCoreApplication>
#include <QLocale>
#include <QBoxLayout>
#include "mainwindow.h"
#include "stripswidget.h"
#include "absencewidget.h"
AbsencePlugin::AbsencePlugin(QObject *parent) :
ZeiterfassungPlugin(parent)
{
qDebug() << "called";
static auto dir = QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(QStringLiteral("translations"));
if(m_translator.load(QLocale(), QStringLiteral("absenceplugin"), QStringLiteral("_"), dir))
{
if(!QCoreApplication::installTranslator(&m_translator))
{
qWarning() << "could not install translation absenceplugin";
}
}
else
{
qWarning() << "could not load translation absenceplugin";
}
}
void AbsencePlugin::attachTo(MainWindow &mainWindow)
{
for(auto stripsWidget : mainWindow.stripsWidgets())
stripsWidget->headerLayout()->addWidget(new AbsenceWidget(*stripsWidget));
}

24
absenceplugin.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include <QObject>
#include <QTranslator>
#include "zeiterfassungplugin.h"
class MainWindow;
class Q_DECL_EXPORT AbsencePlugin : public ZeiterfassungPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "dbsoftware.zeiterfassung.plugin/1.0" FILE "absenceplugin.json")
Q_INTERFACES(ZeiterfassungPlugin)
public:
explicit AbsencePlugin(QObject *parent = Q_NULLPTR);
// ZeiterfassungPlugin interface
void attachTo(MainWindow &mainWindow) Q_DECL_OVERRIDE;
private:
QTranslator m_translator;
};

0
absenceplugin.json Normal file
View File

26
absenceplugin.pro Normal file
View File

@@ -0,0 +1,26 @@
QT += core network gui widgets
DBLIBS += zeiterfassungcore zeiterfassunggui
TARGET = absenceplugin
HEADERS += absencedialog.h \
absencesmodel.h \
absenceplugin.h \
absencewidget.h
SOURCES += absencedialog.cpp \
absencesmodel.cpp \
absenceplugin.cpp \
absencewidget.cpp
FORMS += absencedialog.ui
RESOURCES += absenceplugin_resources.qrc
TRANSLATIONS += translations/absenceplugin_en.ts \
translations/absenceplugin_de.ts
OTHER_FILES += absenceplugin.json
include(../plugin.pri)

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/zeiterfassung/plugins/absenceplugin">
<file>images/absence.png</file>
</qresource>
</RCC>

123
absencesmodel.cpp Normal file
View File

@@ -0,0 +1,123 @@
#include "absencesmodel.h"
#include "zeiterfassungapi.h"
AbsencesModel::AbsencesModel(int userId, const QDate &date, ZeiterfassungApi &erfassung, QObject *parent) :
QAbstractListModel(parent),
m_userId(userId),
m_erfassung(erfassung)
{
connect(this, &AbsencesModel::dateChanged, this, &AbsencesModel::refresh);
setDate(date);
}
bool AbsencesModel::enabled() const
{
return m_reply == Q_NULLPTR;
}
const QDate &AbsencesModel::date() const
{
return m_date;
}
const QVector<GetAbsencesReply::Absence> &AbsencesModel::absences() const
{
return m_absences;
}
int AbsencesModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_absences.count();
}
int AbsencesModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 5;
}
QVariant AbsencesModel::data(const QModelIndex &index, int role) const
{
Q_ASSERT(index.row() < m_absences.count());
const auto &absence = m_absences.at(index.row());
switch(role)
{
case Qt::DisplayRole:
case Qt::EditRole:
switch(index.column())
{
case 0: return absence.compositeId;
case 1: return absence.start;
case 2: return absence.end;
case 3: return absence.hourCategory;
case 4: return absence.text;
}
}
return QVariant();
}
QVariant AbsencesModel::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("Start");
case 2: return tr("End");
case 3: return tr("Hour Category");
case 4: return tr("Text");
}
}
default:
qt_noop();
}
return QVariant();
}
void AbsencesModel::refresh()
{
auto oldEnabled = enabled();
m_reply = m_erfassung.doGetAbsences(m_userId, m_date, m_date);
connect(m_reply.get(), &ZeiterfassungReply::finished, this, &AbsencesModel::finished);
if(oldEnabled != enabled())
Q_EMIT enabledChanged(enabled());
}
void AbsencesModel::setDate(const QDate &date)
{
if(m_date != date)
Q_EMIT dateChanged(m_date = date);
}
void AbsencesModel::finished()
{
if(!m_reply->success())
Q_EMIT errorOccured(m_reply->message());
beginResetModel();
m_absences = m_reply->absences();
endResetModel();
auto oldEnabled = enabled();
m_reply = Q_NULLPTR;
if(oldEnabled != enabled())
Q_EMIT enabledChanged(enabled());
}

51
absencesmodel.h Normal file
View File

@@ -0,0 +1,51 @@
#pragma once
#include <memory>
#include <QAbstractListModel>
#include <QDate>
#include "replies/getabsencesreply.h"
class ZeiterfassungApi;
class AbsencesModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged)
Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged)
public:
explicit AbsencesModel(int userId, const QDate &date, ZeiterfassungApi &erfassung, QObject *parent = Q_NULLPTR);
bool enabled() const;
const QDate &date() const;
const QVector<GetAbsencesReply::Absence> &absences() const;
// 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;
Q_SIGNALS:
void enabledChanged(bool enabled);
void dateChanged(const QDate &date);
void errorOccured(const QString &message);
public Q_SLOTS:
void refresh();
void setDate(const QDate &date);
private Q_SLOTS:
void finished();
private:
int m_userId;
QDate m_date;
ZeiterfassungApi &m_erfassung;
std::unique_ptr<GetAbsencesReply> m_reply;
QVector<GetAbsencesReply::Absence> m_absences;
};

23
absencewidget.cpp Normal file
View File

@@ -0,0 +1,23 @@
#include "absencewidget.h"
#include "stripswidget.h"
#include "mainwindow.h"
#include "absencedialog.h"
AbsenceWidget::AbsenceWidget(StripsWidget &stripsWidget) :
QToolButton(&stripsWidget),
m_stripsWidget(stripsWidget)
{
setIcon(QIcon(QStringLiteral(":/zeiterfassung/plugins/absenceplugin/images/absence.png")));
setText(tr("Absence"));
connect(this, &QAbstractButton::pressed, this, &AbsenceWidget::pressedSlot);
}
void AbsenceWidget::pressedSlot()
{
AbsenceDialog dialog(m_stripsWidget.mainWindow().userInfo().userId, m_stripsWidget.date(),
m_stripsWidget.mainWindow().erfassung(), this);
dialog.exec();
}

19
absencewidget.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include <QToolButton>
class StripsWidget;
class AbsenceWidget : public QToolButton
{
Q_OBJECT
public:
explicit AbsenceWidget(StripsWidget &stripsWidget);
private Q_SLOTS:
void pressedSlot();
private:
StripsWidget &m_stripsWidget;
};

BIN
images/absence.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<context>
<name>AbsenceDialog</name>
<message>
<location filename="../absencedialog.ui" line="14"/>
<source>Absences</source>
<translation>Abwesenheiten</translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="18"/>
<source>Absences for %0</source>
<translation>Abwesenheiten für %0</translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="18"/>
<source>dd.MM.yyyy</source>
<translation>dd.MM.yyyy</translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="37"/>
<source>Could not load absences!</source>
<translation>Konnte Abwesenheiten nicht laden!</translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="47"/>
<source>Create absence</source>
<translation>Abwesenheit erstellen</translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="48"/>
<source>Refresh absences</source>
<translation>Abwesenheiten aktualisieren</translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="64"/>
<source>Edit absence</source>
<translation>Abwesenheit bearbeiten</translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="65"/>
<source>Delete absence</source>
<translation>Abwesenheit löschen</translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="74"/>
<source>Do you really want to delete the absence?</source>
<translation>Möchten Sie die Abwesenheit wirklich löschen?</translation>
</message>
</context>
<context>
<name>AbsenceWidget</name>
<message>
<location filename="../absencewidget.cpp" line="13"/>
<source>Absence</source>
<translation>Abwesenheit</translation>
</message>
</context>
<context>
<name>AbsencesModel</name>
<message>
<location filename="../absencesmodel.cpp" line="77"/>
<source>Id</source>
<translation>Id</translation>
</message>
<message>
<location filename="../absencesmodel.cpp" line="78"/>
<source>Start</source>
<translation>Start</translation>
</message>
<message>
<location filename="../absencesmodel.cpp" line="79"/>
<source>End</source>
<translation>Ende</translation>
</message>
<message>
<location filename="../absencesmodel.cpp" line="80"/>
<source>Hour Category</source>
<translation>Stunden Kategorie</translation>
</message>
<message>
<location filename="../absencesmodel.cpp" line="81"/>
<source>Text</source>
<translation>Text</translation>
</message>
</context>
</TS>

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="en_US">
<context>
<name>AbsenceDialog</name>
<message>
<location filename="../absencedialog.ui" line="14"/>
<source>Absences</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="18"/>
<source>Absences for %0</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="18"/>
<source>dd.MM.yyyy</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="37"/>
<source>Could not load absences!</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="47"/>
<source>Create absence</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="48"/>
<source>Refresh absences</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="64"/>
<source>Edit absence</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="65"/>
<source>Delete absence</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencedialog.cpp" line="74"/>
<source>Do you really want to delete the absence?</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>AbsenceWidget</name>
<message>
<location filename="../absencewidget.cpp" line="13"/>
<source>Absence</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>AbsencesModel</name>
<message>
<location filename="../absencesmodel.cpp" line="77"/>
<source>Id</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencesmodel.cpp" line="78"/>
<source>Start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencesmodel.cpp" line="79"/>
<source>End</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencesmodel.cpp" line="80"/>
<source>Hour Category</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../absencesmodel.cpp" line="81"/>
<source>Text</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>