aboutsummaryrefslogtreecommitdiff
path: root/core/src/UI/UI_DatabaseView.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/UI/UI_DatabaseView.cpp')
-rw-r--r--core/src/UI/UI_DatabaseView.cpp314
1 files changed, 233 insertions, 81 deletions
diff --git a/core/src/UI/UI_DatabaseView.cpp b/core/src/UI/UI_DatabaseView.cpp
index 96009fb..bc458da 100644
--- a/core/src/UI/UI_DatabaseView.cpp
+++ b/core/src/UI/UI_DatabaseView.cpp
@@ -10,7 +10,9 @@
#include <IconsFontAwesome.h>
#include <SQLiteCpp/Statement.h>
#include <imgui.h>
+#include <tsl/robin_map.h>
#include <cstdint>
+#include <iostream>
#include <memory>
#include <vector>
@@ -19,27 +21,36 @@ namespace {
// TODO move to Settings
constexpr int kMaxEntriesPerPage = 20;
-class SaleEntry {
-public:
- std::string Customer;
- std::string Deadline;
- std::string DeliveryTime;
+enum class DeliveryDirection
+{
+ FactoryToWarehouse,
+ WarehouseToCustomer,
};
-class PurchaseEntry {
-public:
- std::string Factory;
- std::string OrderTime;
- std::string DeliveryTime;
+struct DeliveryEntry
+{
+ std::string ShipmentTime;
+ std::string ArriveTime;
+ DeliveryDirection Direction;
+
+ const char* StringifyDirection() const
+ {
+ switch (Direction) {
+ case DeliveryDirection::FactoryToWarehouse: return "Factory to warehouse";
+ case DeliveryDirection::WarehouseToCustomer: return "Warehouse to customer";
+ }
+ }
};
-class GenericTableView {
+class GenericTableView
+{
protected:
// Translation entries for implementer to fill out
const char* mEditDialogTitle;
SQLite::Statement* mGetRowCountStatement;
SQLite::Statement* mGetRowsStatement;
+ SQLite::Statement* mFilterRowsStatement;
Project* mProject;
@@ -69,28 +80,33 @@ protected:
int mSelectedEntryRowId;
public:
- static int CalcPageForRowId(int64_t rowId) {
+ static int CalcPageForRowId(int64_t rowId)
+ {
return rowId / kMaxEntriesPerPage;
}
/// Calculate range [begin, end) of index for the list of entries that are currently visible that the path-th page would show.
/// i.e. when there is a filter, look into \c mActiveEntryIndices; when there is no filter, use directly.
- static std::pair<int64_t, int64_t> CalcRangeForPage(int page) {
+ static std::pair<int64_t, int64_t> CalcRangeForPage(int page)
+ {
int begin = page * kMaxEntriesPerPage;
return { begin, begin + kMaxEntriesPerPage };
}
- Project* GetProject() const {
+ Project* GetProject() const
+ {
return mProject;
}
- virtual void OnProjectChanged(Project* newProject) {
+ virtual void OnProjectChanged(Project* newProject)
+ {
mProject = newProject;
if (mGetRowCountStatement->executeStep()) {
mRowCount = mGetRowCountStatement->getColumn(0).getInt();
} else {
- // TODO report error
+ std::cerr << "Failed to fetch row count from SQLite.\n";
+ mRowCount = 0;
}
mFirstCachedRowId = 0;
@@ -105,13 +121,16 @@ public:
mSelectedEntryRowId = -1;
}
- TableRowsFilter* GetFilter() const {
+ TableRowsFilter* GetFilter() const
+ {
return mActiveFilter.get();
}
- virtual void OnFilterChanged() {
- auto& stmt = mProject->GetTransactionsModel().GetSales().FilterRowsStatement;
- DEFER {
+ virtual void OnFilterChanged()
+ {
+ auto& stmt = *mFilterRowsStatement;
+ DEFER
+ {
stmt.reset();
};
@@ -128,12 +147,14 @@ public:
mSelectedEntryRowId = -1;
}
- void OnFilterChanged(std::unique_ptr<TableRowsFilter> filter) {
+ void OnFilterChanged(std::unique_ptr<TableRowsFilter> filter)
+ {
mActiveFilter = std::move(filter);
OnFilterChanged();
}
- void Draw() {
+ void Draw()
+ {
bool dummy = true;
auto ls = LocaleStrings::Instance.get();
@@ -161,8 +182,24 @@ public:
ImGui::EndPopup();
}
- if (ImGui::BeginTable("", GetTableColumnCount())) {
+ ImGui::SameLine();
+ if (ImGui::Button(ls->Add.Get())) {
+ // TODO
+ }
+
+ if (mSelectedEntryRowId == -1) {
+ DrawMainTable();
+ } else {
+ // TODO better layout
+ DrawMainTable();
+ ImGui::SameLine();
+ DrawDeliveriesTable();
+ }
+ }
+ void DrawMainTable()
+ {
+ if (ImGui::BeginTable("DataTable", GetTableColumnCount(), ImGuiTableFlags_ScrollX)) {
SetupTableColumns();
ImGui::TableHeadersRow();
@@ -184,34 +221,94 @@ public:
}
}
- void SetPage(int page) {
+ void DrawDeliveriesTable()
+ {
+ if (ImGui::BeginTable("DeliveriesTable", 2)) {
+
+ ImGui::TableSetupColumn("Shipment time");
+ ImGui::TableSetupColumn("Arrival time");
+ ImGui::TableHeadersRow();
+
+ auto& deliveries = GetEntryAssociatedDeliveries(mSelectedEntryRowId);
+ for (auto& delivery : deliveries) {
+ ImGui::TableNextRow();
+
+ ImGui::TableNextColumn();
+ ImGui::TextUnformatted(delivery.ShipmentTime.c_str());
+
+ ImGui::TableNextColumn();
+ ImGui::TextUnformatted(delivery.ArriveTime.c_str());
+ }
+
+ ImGui::EndTable();
+ }
+ }
+
+ void SetPage(int page)
+ {
mCurrentPage = page;
EnsureCacheCoversPage(page);
}
- int RowIdToIndex(int64_t rowId) const {
+ int RowIdToIndex(int64_t rowId) const
+ {
return rowId - mFirstCachedRowId;
}
- int64_t IndexToRowId(int index) const {
+ int64_t IndexToRowId(int index) const
+ {
return index + mFirstCachedRowId;
}
+ std::vector<DeliveryEntry> LoadDeliveriesEntries(int64_t orderRowId, DeliveryDirection type)
+ {
+ bool outgoingFlag;
+ switch (type) {
+ case DeliveryDirection::FactoryToWarehouse: outgoingFlag = false; break;
+ case DeliveryDirection::WarehouseToCustomer: outgoingFlag = true; break;
+ }
+
+ auto& stmt = mProject->GetTransactionsModel().GetDeliveries().FilterByTypeAndId;
+ DEFER
+ {
+ stmt.reset();
+ };
+
+ stmt.bind(1, orderRowId);
+ stmt.bind(2, static_cast<int>(type));
+
+ std::vector<DeliveryEntry> entries;
+ int sendTimeCol = stmt.getColumnIndex("ShipmentTime");
+ int arrivalTimeCol = stmt.getColumnIndex("ArrivalTime");
+ while (stmt.executeStep()) {
+ entries.push_back(DeliveryEntry{
+ .ShipmentTime = StringifyTimeStamp(stmt.getColumn(arrivalTimeCol).getInt64()),
+ .ArriveTime = StringifyTimeStamp(stmt.getColumn(sendTimeCol).getInt64()),
+ .Direction = type,
+ });
+ }
+
+ return entries;
+ }
+
protected:
virtual int GetTableColumnCount() const = 0;
virtual void SetupTableColumns() = 0;
+ virtual const std::vector<DeliveryEntry>& GetEntryAssociatedDeliveries(int rowId) = 0;
virtual void DisplayEntry(int rowId) = 0;
virtual void EditEntry(int rowId) = 0;
virtual void ClearEntries() = 0;
- void EnsureCacheCoversPage(int page) {
+ void EnsureCacheCoversPage(int page)
+ {
auto [begin, end] = CalcRangeForPage(page);
EnsureCacheCovers(begin, end - 1);
}
- void EnsureCacheCovers(int64_t firstRow, int64_t lastRow) {
+ void EnsureCacheCovers(int64_t firstRow, int64_t lastRow)
+ {
if (firstRow > lastRow) {
std::swap(firstRow, lastRow);
}
@@ -239,7 +336,21 @@ protected:
virtual void EnsureCacheCoversImpl(int newFirst, int newLast) = 0;
template <class TEntry, class TCollector>
- std::vector<TEntry> LoadRange(int64_t begin, int64_t end, TCollector&& collector) {
+ void LoadExtraEntries(std::vector<TEntry>& entries, int newFirst, int newLast, TCollector&& collector)
+ {
+ auto front = LoadRange<TEntry>(newFirst, mFirstCachedRowId, collector);
+ auto back = LoadRange<TEntry>(mLastCachedRowId + 1, newLast + 1, collector);
+
+ mFirstCachedRowId -= front.size();
+ mLastCachedRowId += back.size();
+
+ entries.insert(entries.begin(), std::make_move_iterator(front.begin()), std::make_move_iterator(front.end()));
+ entries.insert(entries.end(), std::make_move_iterator(back.begin()), std::make_move_iterator(back.end()));
+ }
+
+ template <class TEntry, class TCollector>
+ std::vector<TEntry> LoadRange(int64_t begin, int64_t end, TCollector&& collector)
+ {
std::vector<TEntry> result;
size_t size = end - begin;
@@ -249,10 +360,10 @@ protected:
result.reserve(size);
- DEFER {
+ DEFER
+ {
mGetRowsStatement->reset();
};
-
mGetRowsStatement->bind(1, begin);
mGetRowsStatement->bind(2, end);
@@ -260,46 +371,75 @@ protected:
return result;
}
- void UpdateLastPage() {
+private:
+ void UpdateLastPage()
+ {
mLastPage = mActiveEntries.empty()
? CalcPageForRowId(mRowCount)
: CalcPageForRowId(mActiveEntries.back());
}
};
-class SalesTableView : public GenericTableView {
+class SaleEntry
+{
+public:
+ std::vector<DeliveryEntry> AssociatedDeliveries;
+ std::string Customer;
+ std::string Deadline;
+ std::string DeliveryTime;
+ bool DeliveriesCached = false;
+};
+
+class SalesTableView : public GenericTableView
+{
private:
/// A cached, contiguous (row id of each entry is monotonically increasing, but not necessarily starts at 0) list ready-to-be-presented entries. May be incomplete.
std::vector<SaleEntry> mEntries;
public:
- SalesTableView() {
+ SalesTableView()
+ {
auto ls = LocaleStrings::Instance.get();
mEditDialogTitle = ls->EditSaleEntryDialogTitle.Get();
}
- virtual void OnProjectChanged(Project* newProject) override {
+ virtual void OnProjectChanged(Project* newProject) override
+ {
auto& sales = newProject->GetTransactionsModel().GetSales();
- mGetRowCountStatement = &sales.GetRowCountStatement;
- mGetRowsStatement = &sales.GetRowsStatement;
+ mGetRowCountStatement = &sales.GetRowCount;
+ mGetRowsStatement = &sales.GetRows;
+ // mFilterRowsStatement = &sales.FilterRows;
GenericTableView::OnProjectChanged(newProject);
}
protected:
- virtual int GetTableColumnCount() const override {
+ virtual int GetTableColumnCount() const override
+ {
return 3;
}
- virtual void SetupTableColumns() override {
+ virtual void SetupTableColumns() override
+ {
auto ls = LocaleStrings::Instance.get();
ImGui::TableSetupColumn(ls->DatabaseCustomerColumn.Get());
ImGui::TableSetupColumn(ls->DatabaseDeadlineColumn.Get());
ImGui::TableSetupColumn(ls->DatabaseDeliveryTimeColumn.Get());
}
- virtual void DisplayEntry(int rowId) override {
- auto& entry = GetEntry(rowId);
+ virtual const std::vector<DeliveryEntry>& GetEntryAssociatedDeliveries(int rowId) override
+ {
+ auto& entry = mEntries[RowIdToIndex(rowId)];
+ if (!entry.DeliveriesCached) {
+ entry.AssociatedDeliveries = LoadDeliveriesEntries(rowId, DeliveryDirection::FactoryToWarehouse);
+ entry.DeliveriesCached = true;
+ }
+ return entry.AssociatedDeliveries;
+ }
+
+ virtual void DisplayEntry(int rowId) override
+ {
+ auto& entry = mEntries[RowIdToIndex(rowId)];
auto ls = LocaleStrings::Instance.get();
ImGui::PushID(rowId);
@@ -323,15 +463,18 @@ protected:
ImGui::PopID();
}
- virtual void EditEntry(int rowId) override {
- // TODO
+ virtual void EditEntry(int rowId) override
+ {
+ // `TODO`
}
- virtual void ClearEntries() override {
+ virtual void ClearEntries() override
+ {
mEntries.clear();
}
- virtual void EnsureCacheCoversImpl(int newFirst, int newLast) override {
+ virtual void EnsureCacheCoversImpl(int newFirst, int newLast) override
+ {
auto CollectRows = [&](std::vector<SaleEntry>& result) {
auto& stmt = *mGetRowsStatement;
int customerCol = stmt.getColumnIndex("Customer");
@@ -350,53 +493,69 @@ protected:
}
};
- auto front = LoadRange<SaleEntry>(newFirst, mFirstCachedRowId, CollectRows);
- auto back = LoadRange<SaleEntry>(mLastCachedRowId + 1, newLast + 1, CollectRows);
-
- mFirstCachedRowId -= front.size();
- mLastCachedRowId += back.size();
-
- mEntries.insert(mEntries.begin(), std::make_move_iterator(front.begin()), std::make_move_iterator(front.end()));
- mEntries.insert(mEntries.end(), std::make_move_iterator(back.begin()), std::make_move_iterator(back.end()));
+ LoadExtraEntries<SaleEntry>(mEntries, newFirst, newLast, CollectRows);
}
+};
- SaleEntry& GetEntry(int rowId) {
- return mEntries[RowIdToIndex(rowId)];
- }
+class PurchaseEntry
+{
+public:
+ std::vector<DeliveryEntry> AssociatedDeliveries;
+ std::string Factory;
+ std::string OrderTime;
+ std::string DeliveryTime;
+ bool DeliveriesCached;
};
-class PurchasesTableView : public GenericTableView {
+class PurchasesTableView : public GenericTableView
+{
private:
std::vector<PurchaseEntry> mEntries;
public:
- PurchasesTableView() {
+ PurchasesTableView()
+ {
auto ls = LocaleStrings::Instance.get();
mEditDialogTitle = ls->EditPurchaseEntryDialogTitle.Get();
}
- virtual void OnProjectChanged(Project* newProject) override {
+ virtual void OnProjectChanged(Project* newProject) override
+ {
auto& purchases = newProject->GetTransactionsModel().GetPurchases();
- mGetRowCountStatement = &purchases.GetRowCountStatement;
- mGetRowsStatement = &purchases.GetRowsStatement;
+ mGetRowCountStatement = &purchases.GetRowCount;
+ mGetRowsStatement = &purchases.GetRows;
+ // mFilterRowsStatement = &purchases.FilterRowsStatement;
GenericTableView::OnProjectChanged(newProject);
}
protected:
- virtual int GetTableColumnCount() const override {
+ virtual int GetTableColumnCount() const override
+ {
return 3;
}
- virtual void SetupTableColumns() override {
+ virtual void SetupTableColumns() override
+ {
auto ls = LocaleStrings::Instance.get();
ImGui::TableSetupColumn(ls->DatabaseFactoryColumn.Get());
ImGui::TableSetupColumn(ls->DatabaseOrderTimeColumn.Get());
ImGui::TableSetupColumn(ls->DatabaseDeliveryTimeColumn.Get());
}
- virtual void DisplayEntry(int rowId) override {
- auto& entry = GetEntry(rowId);
+ virtual const std::vector<DeliveryEntry>& GetEntryAssociatedDeliveries(int rowId) override
+ {
+ auto& entry = mEntries[RowIdToIndex(rowId)];
+ if (!entry.DeliveriesCached) {
+ entry.AssociatedDeliveries = LoadDeliveriesEntries(rowId, DeliveryDirection::FactoryToWarehouse);
+ entry.DeliveriesCached = true;
+ }
+ return entry.AssociatedDeliveries;
+ }
+
+ virtual void DisplayEntry(int rowId) override
+ {
+ auto& entry = mEntries[RowIdToIndex(rowId)];
auto ls = LocaleStrings::Instance.get();
ImGui::PushID(rowId);
@@ -424,15 +583,18 @@ protected:
ImGui::PopID();
}
- virtual void EditEntry(int rowId) override {
+ virtual void EditEntry(int rowId) override
+ {
// TODO
}
- virtual void ClearEntries() override {
+ virtual void ClearEntries() override
+ {
mEntries.clear();
}
- virtual void EnsureCacheCoversImpl(int newFirst, int newLast) override {
+ virtual void EnsureCacheCoversImpl(int newFirst, int newLast) override
+ {
auto CollectRows = [&](std::vector<PurchaseEntry>& result) {
auto& stmt = *mGetRowsStatement;
int factoryCol = stmt.getColumnIndex("Factory");
@@ -451,23 +613,13 @@ protected:
}
};
- auto front = LoadRange<PurchaseEntry>(newFirst, mFirstCachedRowId, CollectRows);
- auto back = LoadRange<PurchaseEntry>(mLastCachedRowId + 1, newLast + 1, CollectRows);
-
- mFirstCachedRowId -= front.size();
- mLastCachedRowId += back.size();
-
- mEntries.insert(mEntries.begin(), std::make_move_iterator(front.begin()), std::make_move_iterator(front.end()));
- mEntries.insert(mEntries.end(), std::make_move_iterator(back.begin()), std::make_move_iterator(back.end()));
- }
-
- PurchaseEntry& GetEntry(int rowId) {
- return mEntries[RowIdToIndex(rowId)];
+ LoadExtraEntries<PurchaseEntry>(mEntries, newFirst, newLast, CollectRows);
}
};
} // namespace
-void UI::DatabaseViewTab() {
+void UI::DatabaseViewTab()
+{
auto ls = LocaleStrings::Instance.get();
auto& uis = UIState::GetInstance();