diff --git a/UIs/BeetRoundWidgets/CMakeLists.txt b/UIs/BeetRoundWidgets/CMakeLists.txt index 49eaae5..7cbf417 100644 --- a/UIs/BeetRoundWidgets/CMakeLists.txt +++ b/UIs/BeetRoundWidgets/CMakeLists.txt @@ -11,7 +11,7 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets LinguistTools) -find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets LinguistTools Charts) set(TS_FILES ${TARGET_APP}_en_US.ts) @@ -38,6 +38,8 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) widgets/spinboxdelegate.h widgets/spinboxdelegate.cpp widgets/biddingroundcontrol.h widgets/biddingroundcontrol.cpp widgets/summarywidget.h widgets/summarywidget.cpp + widgets/biddingroundstatuswidget.h widgets/biddingroundstatuswidget.cpp + widgets/biddingroundprogresslayout.h widgets/biddingroundprogresslayout.cpp ) # Define target properties for Android with Qt 6 as: # set_property(TARGET ${TARGET_APP} APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR @@ -64,7 +66,7 @@ endif() include_directories(${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(${TARGET_APP} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) +target_link_libraries(${TARGET_APP} PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Charts) target_include_directories(${TARGET_APP} PRIVATE ${CORE_LIB_DIR}/) target_link_libraries(${TARGET_APP} PRIVATE BeetRoundCore) diff --git a/UIs/BeetRoundWidgets/widgets/biddingroundprogresslayout.cpp b/UIs/BeetRoundWidgets/widgets/biddingroundprogresslayout.cpp new file mode 100644 index 0000000..7dd7c84 --- /dev/null +++ b/UIs/BeetRoundWidgets/widgets/biddingroundprogresslayout.cpp @@ -0,0 +1,44 @@ +#include "biddingroundprogresslayout.h" + +#include +#include + +BiddingRoundProgressLayout::BiddingRoundProgressLayout(const int nCurrentBiddings, + const int nExpectedBiddings, + QWidget* parent) + : QHBoxLayout(parent) + , m_nCurrentBiddings(nCurrentBiddings) + , m_nExpectedBiddings(nExpectedBiddings) { + QLabel* nBidsText = new QLabel("Abgegeben:"); + addWidget(nBidsText); + + m_nBiddings1Label = new QLabel(QString::number(m_nCurrentBiddings)); + addWidget(m_nBiddings1Label); + + QLabel* nExpectedText = new QLabel("Erwartet:"); + addWidget(nExpectedText); + + m_nExpectedBidding1Label = new QLabel(QString::number(m_nExpectedBiddings)); + addWidget(m_nExpectedBidding1Label); + + m_biddingRound1ProgressBar = new QProgressBar(parent); + m_biddingRound1ProgressBar->setMinimum(0); + m_biddingRound1ProgressBar->setMaximum(m_nExpectedBiddings); + m_biddingRound1ProgressBar->setValue(m_nCurrentBiddings); + + addWidget(m_biddingRound1ProgressBar); +} + +void BiddingRoundProgressLayout::setCurrentBiddings(const int value) { + m_nCurrentBiddings = value; + const QString bidCountString = QString::number(value); + m_nBiddings1Label->setText(bidCountString); + m_biddingRound1ProgressBar->setValue(value); +} + +void BiddingRoundProgressLayout::setExpectedBiddings(const int value) { + m_nExpectedBiddings = value; + const QString expectedBiddingsString = QString::number(value); + m_nExpectedBidding1Label->setText(expectedBiddingsString); + m_biddingRound1ProgressBar->setMaximum(value); +} diff --git a/UIs/BeetRoundWidgets/widgets/biddingroundprogresslayout.h b/UIs/BeetRoundWidgets/widgets/biddingroundprogresslayout.h new file mode 100644 index 0000000..a25e18d --- /dev/null +++ b/UIs/BeetRoundWidgets/widgets/biddingroundprogresslayout.h @@ -0,0 +1,28 @@ +#ifndef BIDDINGROUNDPROGRESSLAYOUT_H +#define BIDDINGROUNDPROGRESSLAYOUT_H + +#include + +class QLabel; +class QProgressBar; + +class BiddingRoundProgressLayout : public QHBoxLayout { + Q_OBJECT + public: + BiddingRoundProgressLayout(const int nCurrentBiddings, + const int nExpectedBiddings, + QWidget* parent = nullptr); + + void setCurrentBiddings(const int value); + void setExpectedBiddings(const int value); + + private: + int m_nCurrentBiddings; + int m_nExpectedBiddings; + + QLabel* m_nBiddings1Label = nullptr; + QLabel* m_nExpectedBidding1Label = nullptr; + QProgressBar* m_biddingRound1ProgressBar = nullptr; +}; + +#endif // BIDDINGROUNDPROGRESSLAYOUT_H diff --git a/UIs/BeetRoundWidgets/widgets/biddingroundstatuswidget.cpp b/UIs/BeetRoundWidgets/widgets/biddingroundstatuswidget.cpp new file mode 100644 index 0000000..31a1538 --- /dev/null +++ b/UIs/BeetRoundWidgets/widgets/biddingroundstatuswidget.cpp @@ -0,0 +1,110 @@ +#include "biddingroundstatuswidget.h" + +#include +#include +#include +#include + +BiddingRoundStatusWidget::BiddingRoundStatusWidget(const QString& title, + const int placedBiddings, + const int expectedBiddings, + const int financialNeed, + const int currentSum, + const qreal currentAverage, + QWidget* parent) + : QWidget{parent} + , m_title(title) + , m_financialNeed(financialNeed) + , m_currentSum(currentSum) { + m_moneyDonutSeries = new QPieSeries(); + m_moneyDonutSeries->setHoleSize(0.35); + const QString sumText = QString("Summe: %1 €").arg(currentSum); + m_sumSlice = m_moneyDonutSeries->append(sumText, currentSum); + m_sumSlice->setLabelVisible(); + + const int currentGap = m_financialNeed - currentSum; + const QString gapText = QString("offen: %1 €").arg(currentGap); + m_gapSlice = m_moneyDonutSeries->append(gapText, currentGap); + m_gapSlice->setLabelVisible(); + + m_chartView = new QChartView(); + m_chartView->setMinimumWidth(100); + // m_chartView->setMaximumWidth(500); + m_chartView->setRenderHint(QPainter::Antialiasing); + m_chartView->chart()->setTitle(m_title); + m_chartView->chart()->addSeries(m_moneyDonutSeries); + m_chartView->chart()->legend()->setAlignment(Qt::AlignBottom); + m_chartView->chart()->setTheme(QChart::ChartThemeBlueCerulean); + m_chartView->chart()->legend()->setFont(QFont("Arial", 8)); + + QVBoxLayout* layout = new QVBoxLayout(); + layout->addWidget(m_chartView, 5); + QBoxLayout* progressLayout = createProgressLayout(placedBiddings, expectedBiddings); + layout->addLayout(progressLayout); + + /// bidding average + QHBoxLayout* averageLayout = new QHBoxLayout(); + m_biddingAverageDescription = new QLabel("Durchschnittsgebot: "); + const QString currencyString = createCurrencyString(currentAverage); + m_biddingAverageValue = new QLabel(currencyString); + averageLayout->addWidget(m_biddingAverageDescription); + averageLayout->addWidget(m_biddingAverageValue); + layout->addLayout(averageLayout); + + setLayout(layout); +} + +void BiddingRoundStatusWidget::onExpectedBiddingsChanged(const int nExpected) { + m_biddingRoundProgress->setExpectedBiddings(nExpected); +} + +void BiddingRoundStatusWidget::onNPlacedBiddingsChanged(const int nPlaced) { + m_biddingRoundProgress->setCurrentBiddings(nPlaced); +} + +void BiddingRoundStatusWidget::onBiddingSumChanged(const int sum) { + m_currentSum = sum; + updateDonutChart(); +} + +void BiddingRoundStatusWidget::onBiddingAverageChanged(const qreal average) { + if (m_biddingAverageValue) { + m_biddingAverageValue->setText(createCurrencyString(average)); + } +} + +void BiddingRoundStatusWidget::onFinancialNeedChanged(const int financialNeed) { + m_financialNeed = financialNeed; + updateDonutChart(); +} + +QBoxLayout* BiddingRoundStatusWidget::createProgressLayout(const int nPlaced, const int nExpected) { + QVBoxLayout* progressLayout = new QVBoxLayout(); + + m_biddingRoundProgress = new BiddingRoundProgressLayout(nPlaced, nExpected); + progressLayout->addLayout(m_biddingRoundProgress); + + return progressLayout; +} + +void BiddingRoundStatusWidget::updateDonutChart() { + int currentGap; + if (m_currentSum < m_financialNeed) { + currentGap = m_financialNeed - m_currentSum; + } else { + currentGap = 0; + } + const QString sumText = QString("Summe: %1 €").arg(m_currentSum); + m_sumSlice->setValue(m_currentSum); + m_sumSlice->setLabel(sumText); + + const QString gapText = QString("offen: %1 €").arg(currentGap); + m_gapSlice->setValue(currentGap); + m_gapSlice->setLabel(gapText); + const bool gapLabelVisible = currentGap != 0; + m_gapSlice->setLabelVisible(gapLabelVisible); +} + +QString BiddingRoundStatusWidget::createCurrencyString(const qreal value) const { + return QString::number(value) + " €"; +} diff --git a/UIs/BeetRoundWidgets/widgets/biddingroundstatuswidget.h b/UIs/BeetRoundWidgets/widgets/biddingroundstatuswidget.h new file mode 100644 index 0000000..f1fb835 --- /dev/null +++ b/UIs/BeetRoundWidgets/widgets/biddingroundstatuswidget.h @@ -0,0 +1,53 @@ +#ifndef BIDDINGROUNDSTATUSWIDGET_H +#define BIDDINGROUNDSTATUSWIDGET_H + +#include "biddingroundprogresslayout.h" + +#include + +class QBoxLayout; +class QChartView; +class QPieSeries; +class QPieSlice; + +class BiddingRoundStatusWidget : public QWidget { + Q_OBJECT + public: + explicit BiddingRoundStatusWidget(const QString& title, + const int placedBiddings, + const int expectedBiddings, + const int financialNeed, + const int currentSum, + const qreal currentAverage, + QWidget* parent = nullptr); + + public slots: + void onExpectedBiddingsChanged(const int nExpected); + void onNPlacedBiddingsChanged(const int nPlaced); + void onBiddingSumChanged(const int sum); + void onBiddingAverageChanged(const qreal average); + void onFinancialNeedChanged(const int financialNeed); + + signals: + + private: + QString m_title; + int m_financialNeed; + int m_currentSum; + + QChartView* m_chartView = nullptr; + QPieSeries* m_moneyDonutSeries = nullptr; + QPieSlice* m_sumSlice = nullptr; + QPieSlice* m_gapSlice = nullptr; + QLabel* m_biddingAverageDescription = nullptr; + QLabel* m_biddingAverageValue = nullptr; + + BiddingRoundProgressLayout* m_biddingRoundProgress = nullptr; + + QBoxLayout* createProgressLayout(const int nPlaced, const int nExpected); + void updateDonutChart(); + + QString createCurrencyString(const qreal value) const; +}; + +#endif // BIDDINGROUNDSTATUSWIDGET_H diff --git a/UIs/BeetRoundWidgets/widgets/summarywidget.cpp b/UIs/BeetRoundWidgets/widgets/summarywidget.cpp index 0214c9e..129b5be 100644 --- a/UIs/BeetRoundWidgets/widgets/summarywidget.cpp +++ b/UIs/BeetRoundWidgets/widgets/summarywidget.cpp @@ -1,5 +1,7 @@ #include "summarywidget.h" +#include "biddingroundstatuswidget.h" + #include #include #include @@ -11,20 +13,7 @@ SummaryWidget::SummaryWidget(std::shared_ptr modelSummary, QWidget : QWidget{parent} , m_modelSummary(modelSummary) { /// Layouting - QVBoxLayout* mainLayout = new QVBoxLayout(this); - QHBoxLayout* headerLayout = new QHBoxLayout(); - - /// bindable (proof of concept) properties - QLabel* rowCountLabel = new QLabel("Row count:"); - m_rowCountValueLabel = new QLabel(""); - headerLayout->addWidget(rowCountLabel); - headerLayout->addWidget(m_rowCountValueLabel); - - QHBoxLayout* nExpectedBiddingsLayout = new QHBoxLayout(); - QLabel* nExpectedBiddingsLabel = new QLabel("Expected biddings:"); - m_nExpectedBiddingsValueLabel = new QLabel(""); - nExpectedBiddingsLayout->addWidget(nExpectedBiddingsLabel); - nExpectedBiddingsLayout->addWidget(m_nExpectedBiddingsValueLabel); + QVBoxLayout* mainLayout = new QVBoxLayout(this); /// monthly need QHBoxLayout* footerLayout = new QHBoxLayout(); @@ -39,35 +28,122 @@ SummaryWidget::SummaryWidget(std::shared_ptr modelSummary, QWidget footerLayout->addWidget(m_financialNeedBox); footerLayout->addStretch(1); - mainLayout->addLayout(headerLayout); - mainLayout->addLayout(nExpectedBiddingsLayout); + QBoxLayout* roundsLayout = createBiddingOverviewLayout(); + mainLayout->addLayout(roundsLayout); mainLayout->addLayout(footerLayout); + mainLayout->setSpacing(50); setLayout(mainLayout); - setupBindableProperties(); + setupConnections(); } void SummaryWidget::onFinancialNeedChanged(int newFinancialNeed) { - // NEXT implement reaction on financial need changes - qCritical() << "Apply financial need changes!!!"; + m_biddingStatus1->onFinancialNeedChanged(newFinancialNeed); + m_biddingStatus2->onFinancialNeedChanged(newFinancialNeed); + m_biddingStatus3->onFinancialNeedChanged(newFinancialNeed); } -void SummaryWidget::setupBindableProperties() { +void SummaryWidget::onNExpectedBiddingChanged(int newNExpected) { + m_biddingStatus1->onExpectedBiddingsChanged(newNExpected); + m_biddingStatus2->onExpectedBiddingsChanged(newNExpected); + m_biddingStatus3->onExpectedBiddingsChanged(newNExpected); +} + +void SummaryWidget::onNPlacedBiddingsChanged(const int roundNumber) { + switch (roundNumber) { + case 1: + m_biddingStatus1->onNPlacedBiddingsChanged(m_modelSummary->nPlacedBiddings1()); + break; + case 2: + m_biddingStatus2->onNPlacedBiddingsChanged(m_modelSummary->nPlacedBiddings2()); + break; + case 3: + m_biddingStatus3->onNPlacedBiddingsChanged(m_modelSummary->nPlacedBiddings3()); + break; + default: + qWarning() << "Unknown round number:" << roundNumber; + break; + } +} + +void SummaryWidget::onBiddingSumChanged(const int roundNumber) { + switch (roundNumber) { + case 1: + m_biddingStatus1->onBiddingSumChanged(m_modelSummary->biddingSum1()); + break; + case 2: + m_biddingStatus2->onBiddingSumChanged(m_modelSummary->biddingSum2()); + break; + case 3: + m_biddingStatus3->onBiddingSumChanged(m_modelSummary->biddingSum3()); + break; + default: + qWarning() << "Unknown round number:" << roundNumber; + break; + } +} + +void SummaryWidget::onBiddingAverageChanged(const int roundNumber) { + switch (roundNumber) { + case 1: + m_biddingStatus1->onBiddingAverageChanged(m_modelSummary->biddingAverage1()); + break; + case 2: + m_biddingStatus2->onBiddingAverageChanged(m_modelSummary->biddingAverage2()); + break; + case 3: + m_biddingStatus3->onBiddingAverageChanged(m_modelSummary->biddingAverage3()); + break; + default: + qWarning() << "Unknown round number:" << roundNumber; + break; + } +} + +QBoxLayout* SummaryWidget::createBiddingOverviewLayout() { + QHBoxLayout* layout = new QHBoxLayout(); + + const int expectedBiddings = m_modelSummary->nExpectedBiddings(); + + /// bidding round 1 + const int placedBiddings1 = m_modelSummary->nPlacedBiddings1(); + const int biddingSum1 = m_modelSummary->biddingSum1(); + const qreal biddingAverage1 = m_modelSummary->biddingAverage1(); + m_biddingStatus1 = + make_unique("Bietrunde 1", placedBiddings1, expectedBiddings, + m_financialNeed, biddingSum1, biddingAverage1); + /// bidding round 2 + const int placedBiddings2 = m_modelSummary->nPlacedBiddings2(); + const int biddingSum2 = m_modelSummary->biddingSum2(); + const qreal biddingAverage2 = m_modelSummary->biddingAverage2(); + m_biddingStatus2 = + make_unique("Bietrunde 2", placedBiddings2, expectedBiddings, + m_financialNeed, biddingSum2, biddingAverage2); + /// bidding round 3 + const int placedBiddings3 = m_modelSummary->nPlacedBiddings3(); + const int biddingSum3 = m_modelSummary->biddingSum3(); + const qreal biddingAverage3 = m_modelSummary->biddingAverage3(); + m_biddingStatus3 = + make_unique("Bietrunde 3", placedBiddings3, expectedBiddings, + m_financialNeed, biddingSum3, biddingAverage3); + + layout->addWidget(m_biddingStatus1.get()); + layout->addWidget(m_biddingStatus2.get()); + layout->addWidget(m_biddingStatus3.get()); + + return layout; +} + +void SummaryWidget::setupConnections() { // TODO figure out how to encapsulate each property binding into a dedicated function: // "bindProperty(&bindable, &signal, &getter, widget)" - /// nRows - QProperty nRows(-1); - QObject::connect(m_modelSummary.get(), &ModelSummary::rowCountChanged, [&]() { - m_rowCountValueLabel->setText(QString::number(m_modelSummary->rowCount())); - }); - m_modelSummary->bindableRowCount().setBinding([&]() { return nRows.value(); }); - - /// nExpectedBiddings - QProperty nExpectedBiddings(-1); - QObject::connect(m_modelSummary.get(), &ModelSummary::nExpectedBiddingsChanged, [&]() { - m_nExpectedBiddingsValueLabel->setText(QString::number(m_modelSummary->nExpectedBiddings())); - }); - m_modelSummary->bindableNExpectedBiddings().setBinding( - [&]() { return nExpectedBiddings.value(); }); + QObject::connect(m_modelSummary.get(), &ModelSummary::nExpectedBiddingsChanged, + [&]() { onNExpectedBiddingChanged(m_modelSummary->nExpectedBiddings()); }); + QObject::connect(m_modelSummary.get(), &ModelSummary::nPlacedBiddingsChanged, this, + &SummaryWidget::onNPlacedBiddingsChanged); + QObject::connect(m_modelSummary.get(), &ModelSummary::biddingSumChanged, this, + &SummaryWidget::onBiddingSumChanged); + QObject::connect(m_modelSummary.get(), &ModelSummary::biddingAverageChanged, this, + &SummaryWidget::onBiddingAverageChanged); } diff --git a/UIs/BeetRoundWidgets/widgets/summarywidget.h b/UIs/BeetRoundWidgets/widgets/summarywidget.h index 553efdd..10f7252 100644 --- a/UIs/BeetRoundWidgets/widgets/summarywidget.h +++ b/UIs/BeetRoundWidgets/widgets/summarywidget.h @@ -3,9 +3,11 @@ #include +class BiddingRoundStatusWidget; class ModelSummary; class QLabel; class QSpinBox; +class QBoxLayout; class SummaryWidget : public QWidget { Q_OBJECT @@ -15,10 +17,19 @@ class SummaryWidget : public QWidget { private slots: void onFinancialNeedChanged(int newFinancialNeed); + void onNExpectedBiddingChanged(int newNExpected); + + void onNPlacedBiddingsChanged(const int roundNumber); + void onBiddingSumChanged(const int roundNumber); + void onBiddingAverageChanged(const int roundNumber); private: std::shared_ptr m_modelSummary; + std::unique_ptr m_biddingStatus1; + std::unique_ptr m_biddingStatus2; + std::unique_ptr m_biddingStatus3; + // TODO read from settings (maybe via model/core; maybe set in constructor) const int m_financialNeed = 13942; QSpinBox* m_financialNeedBox = nullptr; @@ -26,7 +37,9 @@ class SummaryWidget : public QWidget { QLabel* m_rowCountValueLabel; QLabel* m_nExpectedBiddingsValueLabel; - void setupBindableProperties(); + /// functions + QBoxLayout* createBiddingOverviewLayout(); + void setupConnections(); }; #endif // SUMMARYWIDGET_H diff --git a/libs/BeetRoundCore/model/modelsummary.cpp b/libs/BeetRoundCore/model/modelsummary.cpp index 33566ea..17b471e 100644 --- a/libs/BeetRoundCore/model/modelsummary.cpp +++ b/libs/BeetRoundCore/model/modelsummary.cpp @@ -10,6 +10,11 @@ ModelSummary::ModelSummary(std::shared_ptr model, QObject* parent) // TODO ? use existing model signals (dataChanged(role),...) instead of special signals connect(m_model.get(), &TableModel::nExpectedBiddingsChanged, this, &ModelSummary::nExpectedBiddingsChanged); + connect(m_model.get(), &TableModel::nPlacedBiddingsChanged, this, + &ModelSummary::nPlacedBiddingsChanged); + connect(m_model.get(), &TableModel::biddingSumChanged, this, &ModelSummary::biddingSumChanged); + connect(m_model.get(), &TableModel::biddingAverageChanged, this, + &ModelSummary::biddingAverageChanged); } ModelSummary::~ModelSummary() {} @@ -26,7 +31,14 @@ QBindable ModelSummary::bindableRowCount() { int ModelSummary::nExpectedBiddings() const { return m_model->nExpectedBiddings(); } -QBindable ModelSummary::bindableNExpectedBiddings() { - m_nExpectedBiddings = m_model->nExpectedBiddings(); - return &m_nExpectedBiddings; -} +int ModelSummary::nPlacedBiddings1() const { return m_model->nPlacedBiddings1(); } +int ModelSummary::nPlacedBiddings2() const { return m_model->nPlacedBiddings2(); } +int ModelSummary::nPlacedBiddings3() const { return m_model->nPlacedBiddings3(); } + +int ModelSummary::biddingSum1() const { return m_model->biddingSum1(); } +int ModelSummary::biddingSum2() const { return m_model->biddingSum2(); } +int ModelSummary::biddingSum3() const { return m_model->biddingSum3(); } + +qreal ModelSummary::biddingAverage1() const { return m_model->biddingAverage1(); } +qreal ModelSummary::biddingAverage2() const { return m_model->biddingAverage2(); } +qreal ModelSummary::biddingAverage3() const { return m_model->biddingAverage3(); } diff --git a/libs/BeetRoundCore/model/modelsummary.h b/libs/BeetRoundCore/model/modelsummary.h index 075b572..cc98771 100644 --- a/libs/BeetRoundCore/model/modelsummary.h +++ b/libs/BeetRoundCore/model/modelsummary.h @@ -12,8 +12,6 @@ class ModelSummary : public QObject { Q_OBJECT Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged BINDABLE bindableRowCount) - Q_PROPERTY(int nExpectedBiddings READ nExpectedBiddings NOTIFY nExpectedBiddingsChanged BINDABLE - bindableNExpectedBiddings) public: ModelSummary(shared_ptr model, QObject* parent = nullptr); @@ -22,20 +20,30 @@ class ModelSummary : public QObject { int rowCount() const; QBindable bindableRowCount(); int nExpectedBiddings() const; - QBindable bindableNExpectedBiddings(); + int nPlacedBiddings1() const; + int nPlacedBiddings2() const; + int nPlacedBiddings3() const; + + int biddingSum1() const; + int biddingSum2() const; + int biddingSum3() const; + + qreal biddingAverage1() const; + qreal biddingAverage2() const; + qreal biddingAverage3() const; signals: void rowCountChanged(); void nExpectedBiddingsChanged(); + void nPlacedBiddingsChanged(const int roundNumber); + void biddingSumChanged(const int roundNumber); + void biddingAverageChanged(const int roundNumber); + private: shared_ptr m_model; Q_OBJECT_BINDABLE_PROPERTY(ModelSummary, int, m_rowCount, &ModelSummary::rowCountChanged); - Q_OBJECT_BINDABLE_PROPERTY(ModelSummary, - int, - m_nExpectedBiddings, - &ModelSummary::nExpectedBiddingsChanged); }; #endif // MODELSUMMARY_H diff --git a/libs/BeetRoundCore/model/tablemodel.cpp b/libs/BeetRoundCore/model/tablemodel.cpp index 18855a1..8fac24f 100644 --- a/libs/BeetRoundCore/model/tablemodel.cpp +++ b/libs/BeetRoundCore/model/tablemodel.cpp @@ -291,6 +291,18 @@ void TableModel::onRowCountChanged(const QModelIndex& parent, int first, int las } emit rowCountChanged(); emit nExpectedBiddingsChanged(); + + emit nPlacedBiddingsChanged(1); + emit nPlacedBiddingsChanged(2); + emit nPlacedBiddingsChanged(3); + + emit biddingSumChanged(1); + emit biddingSumChanged(2); + emit biddingSumChanged(3); + + emit biddingAverageChanged(1); + emit biddingAverageChanged(2); + emit biddingAverageChanged(3); } int TableModel::nExpectedBiddings() const { @@ -303,6 +315,35 @@ int TableModel::nExpectedBiddings() const { } return result; } + +int TableModel::nPlacedBiddings1() const { return nPlacedBiddings(Bidding1Role); } +int TableModel::nPlacedBiddings2() const { return nPlacedBiddings(Bidding2Role); } +int TableModel::nPlacedBiddings3() const { return nPlacedBiddings(Bidding3Role); } + +int TableModel::biddingSum1() const { return biddingSum(Bidding1Role); } +int TableModel::biddingSum2() const { return biddingSum(Bidding2Role); } +int TableModel::biddingSum3() const { return biddingSum(Bidding3Role); } + +qreal TableModel::biddingAverage1() const { + const UserRoles biddingRole = Bidding1Role; + const qreal averageBidding = averageBiddingAmount(biddingRole); + qInfo() << "average calculation (1):" << averageBidding; + return averageBidding; +} + +qreal TableModel::biddingAverage2() const { + const UserRoles biddingRole = Bidding2Role; + const qreal averageBidding = averageBiddingAmount(biddingRole); + qInfo() << "average calculation (2):" << averageBidding; + return averageBidding; +} +qreal TableModel::biddingAverage3() const { + const UserRoles biddingRole = Bidding3Role; + const qreal averageBidding = averageBiddingAmount(biddingRole); + qInfo() << "average calculation (3):" << averageBidding; + return averageBidding; +} + void TableModel::execInsertItems(const int firstRow, const QList valueList) { const int nRows = valueList.size(); qDebug() << "Inserting" << nRows << "items..."; @@ -339,7 +380,37 @@ void TableModel::execEditItemData(const int row, const QMap& chan emit dataChanged(firstIndex, lastIndex, roles.toVector()); // NEXT check which roles are changed & trigger only changed properties - emit nExpectedBiddingsChanged(); + if (roles.contains(BiddingTypeRole) || roles.contains(ShareAmountRole)) { + emit nExpectedBiddingsChanged(); + } + if (roles.contains(ShareAmountRole) || roles.contains(ShareTypeRole)) { + emit nPlacedBiddingsChanged(1); + emit nPlacedBiddingsChanged(2); + emit nPlacedBiddingsChanged(3); + emit biddingSumChanged(1); + emit biddingSumChanged(2); + emit biddingSumChanged(3); + emit biddingAverageChanged(1); + emit biddingAverageChanged(2); + emit biddingAverageChanged(3); + } else { + /// no changes to share amount or type, but maybe to the biddings: + if (roles.contains(Bidding1Role)) { + emit nPlacedBiddingsChanged(1); + emit biddingSumChanged(1); + emit biddingAverageChanged(1); + } + if (roles.contains(Bidding2Role)) { + emit nPlacedBiddingsChanged(2); + emit biddingSumChanged(2); + emit biddingAverageChanged(2); + } + if (roles.contains(Bidding3Role)) { + emit nPlacedBiddingsChanged(3); + emit biddingSumChanged(3); + emit biddingAverageChanged(3); + } + } } } @@ -435,3 +506,64 @@ bool TableModel::isItemEqualToItemValues(const QModelIndex& itemIndex, return true; } } + +int TableModel::nPlacedBiddings(const UserRoles biddingRole) const { + int result = 0; + for (auto i = m_items.begin(), end = m_items.end(); i != end; ++i) { + int localBidding = (*i)->data(biddingRole).toInt(); + if (localBidding > 0) { + result++; + } + } + return result; +} + +int TableModel::biddingSum(const UserRoles biddingRole) const { + int result = 0; + for (auto i = m_items.begin(), end = m_items.end(); i != end; ++i) { + result += (*i)->data(biddingRole).toInt(); + } + return result; +} + +qreal TableModel::averageBiddingAmount(const UserRoles biddingRole) const { + qInfo() << "Calculating average bidding for role:" << ROLE_NAMES.value(biddingRole); + const qreal localTotalSharesWithBiddings = totalSharesWithBiddings(biddingRole); + + if (localTotalSharesWithBiddings <= 0) { + qInfo() << "No biddings found. Aborting calculation..."; + return 0; + } + + const qreal localTotalBiddingAmount = biddingSum(biddingRole); + const qreal alternateBiddingAverage = localTotalBiddingAmount / localTotalSharesWithBiddings; + qDebug() << "Total bidding amount:" << localTotalBiddingAmount; + qDebug() << "Total bidding shares:" << localTotalSharesWithBiddings; + return alternateBiddingAverage; +} + +qreal TableModel::totalSharesWithBiddings(const UserRoles biddingRole) const { + qreal result = 0; + for (auto i = m_items.begin(), end = m_items.end(); i != end; ++i) { + const qreal bidding = (*i)->data(biddingRole).toReal(); + const qreal shareAmount = (*i)->data(ShareAmountRole).toReal(); + const QString shareType = (*i)->data(ShareTypeRole).toString(); + const bool isValid = bidding != 0 && shareAmount != 0; + if (isValid) { + // qInfo() << "Including entry in bidding average calculation. MailRole:" + // << (*i)->data(MailRole); + // qreal bidForWholeShare = 0; + if (shareType == "bezahlt") { + result += shareAmount; + } else if (shareType == "teils/teils") { + result += shareAmount / 2; + } else { + qInfo() << "Share type not 'bezahlt' nor 'teils/teils'. Will be ignored.."; + qDebug() << "Share type:" << shareType; + continue; + } + } + } + qInfo() << "Biddings exist for " << result << "shares!"; + return result; +} diff --git a/libs/BeetRoundCore/model/tablemodel.h b/libs/BeetRoundCore/model/tablemodel.h index 5a11602..9d7d03d 100644 --- a/libs/BeetRoundCore/model/tablemodel.h +++ b/libs/BeetRoundCore/model/tablemodel.h @@ -56,9 +56,28 @@ class TableModel : public QAbstractTableModel { const QList& itemValuesList, const QModelIndex& parentIndex = QModelIndex()); + /// property functions + int nExpectedBiddings() const; + int nPlacedBiddings1() const; + int nPlacedBiddings2() const; + int nPlacedBiddings3() const; + + int biddingSum1() const; + int biddingSum2() const; + int biddingSum3() const; + + qreal biddingAverage1() const; + qreal biddingAverage2() const; + qreal biddingAverage3() const; + signals: void rowCountChanged(); + void nExpectedBiddingsChanged(); + void nPlacedBiddingsChanged(const int roundNumber); + void biddingSumChanged(const int roundNumber); + void biddingAverageChanged(const int roundNumber); + private slots: void onRowCountChanged(const QModelIndex& parent, int first, int last); @@ -81,6 +100,11 @@ class TableModel : public QAbstractTableModel { QModelIndex searchItemIndex(const ModelItemValues givenItemValues) const; bool isItemEqualToItemValues(const QModelIndex& itemIndex, const ModelItemValues givenItemValues) const; + + int nPlacedBiddings(const UserRoles biddingRole) const; + int biddingSum(const UserRoles biddingRole) const; + qreal averageBiddingAmount(const UserRoles biddingRole) const; + qreal totalSharesWithBiddings(const UserRoles biddingRole) const; }; #endif // TABLEMODEL_H