From e0964bbc4f66e7d193abd249213c9cf762fd0294 Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 30 Dec 2020 15:37:39 +0800 Subject: import(life): ... --- works/life/cpp-practicum/Record.cpp | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 works/life/cpp-practicum/Record.cpp (limited to 'works/life/cpp-practicum/Record.cpp') diff --git a/works/life/cpp-practicum/Record.cpp b/works/life/cpp-practicum/Record.cpp new file mode 100644 index 0000000..1041b23 --- /dev/null +++ b/works/life/cpp-practicum/Record.cpp @@ -0,0 +1,38 @@ +#include "Record.hpp" + +void Record::WriteTo(QFile file) { + file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate); + QTextStream stream(&file); + stream.setCodec("UTF-8"); + + stream << books_.size() << ' ' << vendors_.size() << '\n'; + for (const auto &book : books_) { + stream << book << '\n'; + } + for (const auto &vendor : vendors_) { + stream << vendor << '\n'; + } +} + +void Record::ReadFrom(QFile file) { + file.open(QFile::ReadOnly | QFile::Text); + QTextStream stream(&file); + stream.setCodec("UTF-8"); + + books_.clear(); + vendors_.clear(); + + int book_count, vendor_count; + stream >> book_count >> vendor_count; + stream.skipWhiteSpace(); + for (int i = 0; i < book_count; i++) { + Book book; + stream >> book; + books_.push_back(std::move(book)); + } + for (int i = 0; i < vendor_count; i++) { + Vendor vendor; + stream >> vendor; + vendors_.push_back(std::move(vendor)); + } +} -- cgit v1.2.3 From d0b6d6377de44484568af2ef3a3bbd4da7cdfb4b Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 30 Dec 2020 17:23:15 +0800 Subject: import(life): ... --- works/life/cpp-practicum/Book.hpp | 2 +- works/life/cpp-practicum/Record.cpp | 147 ++++++++++++++++++++++++++++++++++++ works/life/cpp-practicum/Record.hpp | 35 ++++++--- works/life/cpp-practicum/main.cpp | 22 +++++- 4 files changed, 194 insertions(+), 12 deletions(-) (limited to 'works/life/cpp-practicum/Record.cpp') diff --git a/works/life/cpp-practicum/Book.hpp b/works/life/cpp-practicum/Book.hpp index 2fb1123..250460f 100644 --- a/works/life/cpp-practicum/Book.hpp +++ b/works/life/cpp-practicum/Book.hpp @@ -44,7 +44,7 @@ private: std::u16string type_; std::u16string author_; std::u16string press_; - int stock_count_; + int stock_count_ = 0; }; QTextStream &operator>>(QTextStream &left, Book &right); diff --git a/works/life/cpp-practicum/Record.cpp b/works/life/cpp-practicum/Record.cpp index 1041b23..ac367df 100644 --- a/works/life/cpp-practicum/Record.cpp +++ b/works/life/cpp-practicum/Record.cpp @@ -1,4 +1,7 @@ #include "Record.hpp" +#include "QAbstractitemmodel.h" +#include "qnamespace.h" +#include "qvariant.h" void Record::WriteTo(QFile file) { file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate); @@ -36,3 +39,147 @@ void Record::ReadFrom(QFile file) { vendors_.push_back(std::move(vendor)); } } + +int BookModel::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + return static_cast(record_->GetBooks().size()); +} + +int BookModel::columnCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + return 6; +} + +QVariant BookModel::headerData(int section, Qt::Orientation orientation, + int role) const { + if (role != Qt::DisplayRole) + return QVariant(); + if (orientation == Qt::Horizontal) { + switch (section) { + case 0: + return QStringLiteral("ISBN"); + case 1: + return QStringLiteral("标题"); + case 2: + return QStringLiteral("类型"); + case 3: + return QStringLiteral("作者"); + case 4: + return QStringLiteral("出版社"); + case 5: + return QStringLiteral("库存"); + default: + return QVariant(); + } + } + return QVariant(); +} + +QVariant BookModel::data(const QModelIndex &index, int role) const { + if (role != Qt::DisplayRole) + return QVariant(); + + if (!index.isValid()) + return QVariant(); + + if (index.row() >= static_cast(record_->GetBooks().size()) || + index.row() < 0) + return QVariant(); + + int row = index.row(); + const Book &book = record_->GetBooks()[row]; + + int col = index.column(); + switch (col) { + case 0: + return QString::fromStdU16String(book.GetIsbn()); + case 1: + return QString::fromStdU16String(book.GetTitle()); + case 2: + return QString::fromStdU16String(book.GetType()); + case 3: + return QString::fromStdU16String(book.GetAuthor()); + case 4: + return QString::fromStdU16String(book.GetPress()); + case 5: + return book.GetStockCount(); + default: + return QVariant(); + } +} + +bool BookModel::setData(const QModelIndex &index, const QVariant &value, + int role) { + if (index.isValid() && role == Qt::EditRole) { + int row = index.row(); + Book &book = record_->GetBooks()[row]; + + int col = index.column(); + switch (col) { + case 0: + if (!value.canConvert()) + return false; + book.SetIsbn(value.toString().toStdU16String()); + return true; + case 1: + if (!value.canConvert()) + return false; + book.SetTitle(value.toString().toStdU16String()); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + case 2: + if (!value.canConvert()) + return false; + book.SetType(value.toString().toStdU16String()); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + case 3: + if (!value.canConvert()) + return false; + book.SetAuthor(value.toString().toStdU16String()); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + case 4: + if (!value.canConvert()) + return false; + book.SetPress(value.toString().toStdU16String()); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + case 5: + if (!value.canConvert()) + return false; + book.SetStockCount(value.toInt()); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + default: + return false; + } + } + return false; +} + +Qt::ItemFlags BookModel::flags(const QModelIndex &index) const { + if (!index.isValid()) + return Qt::ItemIsEnabled; + + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; +} + +bool BookModel::insertRows(int row, int count, const QModelIndex &parent) { + beginInsertRows(parent, row, row + count - 1); + for (int i = 0; i < count; i++) { + record_->GetBooks().insert(record_->GetBooks().cbegin() + row, Book()); + } + endInsertRows(); + return true; +} + +bool BookModel::removeRows(int row, int count, const QModelIndex &parent) { + beginRemoveRows(parent, row, row + count - 1); + record_->GetBooks().erase(record_->GetBooks().cbegin() + row, + record_->GetBooks().cbegin() + row + count); + endRemoveRows(); + return true; +} diff --git a/works/life/cpp-practicum/Record.hpp b/works/life/cpp-practicum/Record.hpp index e39e626..78b70ba 100644 --- a/works/life/cpp-practicum/Record.hpp +++ b/works/life/cpp-practicum/Record.hpp @@ -4,13 +4,14 @@ #include "Book.hpp" #include "Vendor.hpp" +#include #include #include #include class Record final { public: - Record(); + Record() = default; CRU_DEFAULT_COPY(Record); CRU_DEFAULT_MOVE(Record); @@ -21,16 +22,32 @@ public: void WriteTo(QFile file); void ReadFrom(QFile file); - const std::vector &GetBooks() const { return books_; } - const std::vector &GetVendors() const { return vendors_; } - - // TODO: Implementation - std::optional FindBookByIsbn(std::u16string_view isbn); - - // TODO: Implementation - void RemoveBookByIsbn(std::u16string_view isbn); + std::vector &GetBooks() { return books_; } + std::vector &GetVendors() { return vendors_; } private: std::vector books_; std::vector vendors_; }; + +class BookModel : public QAbstractTableModel { +public: + explicit BookModel(Record *record) : record_(record) {} + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + QVariant data(const QModelIndex &index, + int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, + int role = Qt::EditRole) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool insertRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + bool removeRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + +private: + Record *record_; +}; \ No newline at end of file diff --git a/works/life/cpp-practicum/main.cpp b/works/life/cpp-practicum/main.cpp index 14847cc..b7e5db5 100644 --- a/works/life/cpp-practicum/main.cpp +++ b/works/life/cpp-practicum/main.cpp @@ -1,7 +1,9 @@ -#include "qboxlayout.h" -#include "qtableview.h" +#include "Record.hpp" +#include "qabstractitemview.h" + #include #include +#include #include #include #include @@ -20,19 +22,35 @@ int main(int argc, char *argv[]) { QPushButton import_button(QStringLiteral("导入")); QPushButton export_button(QStringLiteral("导出")); + QPushButton add_book_button(QStringLiteral("添加书")); + top_bar.addWidget(&import_button); top_bar.addWidget(&export_button); top_bar.addStretch(1); + top_bar.addWidget(&add_book_button); QHBoxLayout center_area; window_layout.addLayout(¢er_area); QTableView book_view; + book_view.verticalHeader()->hide(); + book_view.setSelectionBehavior(QAbstractItemView::SelectRows); + book_view.setEditTriggers(QAbstractItemView::DoubleClicked); + book_view.setSelectionMode(QAbstractItemView::SingleSelection); QTableView vendor_view; center_area.addWidget(&book_view); center_area.addWidget(&vendor_view); + Record record; + BookModel book_model(&record); + + book_view.setModel(&book_model); + + QObject::connect(&add_book_button, &QPushButton::clicked, [&book_model]() { + book_model.insertRow(book_model.rowCount()); + }); + window.show(); return application.exec(); -- cgit v1.2.3 From 5dc5500d0a31497f69404c463f39e44f8a70f3df Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 30 Dec 2020 17:27:48 +0800 Subject: import(life): ... --- works/life/cpp-practicum/Record.cpp | 3 --- works/life/cpp-practicum/main.cpp | 1 - 2 files changed, 4 deletions(-) (limited to 'works/life/cpp-practicum/Record.cpp') diff --git a/works/life/cpp-practicum/Record.cpp b/works/life/cpp-practicum/Record.cpp index ac367df..4d7d4a9 100644 --- a/works/life/cpp-practicum/Record.cpp +++ b/works/life/cpp-practicum/Record.cpp @@ -1,7 +1,4 @@ #include "Record.hpp" -#include "QAbstractitemmodel.h" -#include "qnamespace.h" -#include "qvariant.h" void Record::WriteTo(QFile file) { file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate); diff --git a/works/life/cpp-practicum/main.cpp b/works/life/cpp-practicum/main.cpp index b7e5db5..9ecc308 100644 --- a/works/life/cpp-practicum/main.cpp +++ b/works/life/cpp-practicum/main.cpp @@ -1,5 +1,4 @@ #include "Record.hpp" -#include "qabstractitemview.h" #include #include -- cgit v1.2.3 From 6469683b4cca6aaae9d27e34c17b8f75a988fa81 Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 30 Dec 2020 20:04:07 +0800 Subject: import(life): ... --- works/life/cpp-practicum/Record.cpp | 179 ++++++++++++++++++++++++++++++++++-- works/life/cpp-practicum/Record.hpp | 31 ++++++- works/life/cpp-practicum/main.cpp | 98 ++++++++++++++++---- 3 files changed, 279 insertions(+), 29 deletions(-) (limited to 'works/life/cpp-practicum/Record.cpp') diff --git a/works/life/cpp-practicum/Record.cpp b/works/life/cpp-practicum/Record.cpp index 4d7d4a9..bdee28b 100644 --- a/works/life/cpp-practicum/Record.cpp +++ b/works/life/cpp-practicum/Record.cpp @@ -1,10 +1,8 @@ #include "Record.hpp" -void Record::WriteTo(QFile file) { - file.open(QFile::ReadWrite | QFile::Text | QFile::Truncate); - QTextStream stream(&file); - stream.setCodec("UTF-8"); +#include +void Record::WriteTo(QTextStream &stream) { stream << books_.size() << ' ' << vendors_.size() << '\n'; for (const auto &book : books_) { stream << book << '\n'; @@ -14,11 +12,7 @@ void Record::WriteTo(QFile file) { } } -void Record::ReadFrom(QFile file) { - file.open(QFile::ReadOnly | QFile::Text); - QTextStream stream(&file); - stream.setCodec("UTF-8"); - +void Record::ReadFrom(QTextStream &stream) { books_.clear(); vendors_.clear(); @@ -180,3 +174,170 @@ bool BookModel::removeRows(int row, int count, const QModelIndex &parent) { endRemoveRows(); return true; } + +void BookModel::sort(int column, Qt::SortOrder order) { + if (column == 0) { + beginResetModel(); + if (order == Qt::AscendingOrder) { + std::sort(record_->GetBooks().begin(), record_->GetBooks().end(), + [](const Book &left, const Book &right) { + return left.GetIsbn() < right.GetIsbn(); + }); + } else { + std::sort(record_->GetBooks().begin(), record_->GetBooks().end(), + [](const Book &left, const Book &right) { + return left.GetIsbn() > right.GetIsbn(); + }); + } + endResetModel(); + } else if (column == 1) { + beginResetModel(); + if (order == Qt::AscendingOrder) { + std::sort(record_->GetBooks().begin(), record_->GetBooks().end(), + [](const Book &left, const Book &right) { + return left.GetTitle() < right.GetTitle(); + }); + } else { + std::sort(record_->GetBooks().begin(), record_->GetBooks().end(), + [](const Book &left, const Book &right) { + return left.GetTitle() > right.GetTitle(); + }); + } + endResetModel(); + } +} + +int VendorModel::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + return static_cast(record_->GetVendors().size()); +} + +int VendorModel::columnCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; + return 5; +} + +QVariant VendorModel::headerData(int section, Qt::Orientation orientation, + int role) const { + if (role != Qt::DisplayRole) + return QVariant(); + if (orientation == Qt::Horizontal) { + switch (section) { + case 0: + return QStringLiteral("编号"); + case 1: + return QStringLiteral("名称"); + case 2: + return QStringLiteral("类型"); + case 3: + return QStringLiteral("地址"); + case 4: + return QStringLiteral("电话"); + default: + return QVariant(); + } + } + return QVariant(); +} + +QVariant VendorModel::data(const QModelIndex &index, int role) const { + if (role != Qt::DisplayRole) + return QVariant(); + + if (!index.isValid()) + return QVariant(); + + if (index.row() >= static_cast(record_->GetVendors().size()) || + index.row() < 0) + return QVariant(); + + int row = index.row(); + const Vendor &vendor = record_->GetVendors()[row]; + + int col = index.column(); + switch (col) { + case 0: + return vendor.GetId(); + case 1: + return QString::fromStdU16String(vendor.GetName()); + case 2: + return QString::fromStdU16String(vendor.GetType()); + case 3: + return QString::fromStdU16String(vendor.GetAddress()); + case 4: + return QString::fromStdU16String(vendor.GetPhone()); + default: + return QVariant(); + } +} + +bool VendorModel::setData(const QModelIndex &index, const QVariant &value, + int role) { + if (index.isValid() && role == Qt::EditRole) { + int row = index.row(); + Vendor &vendor = record_->GetVendors()[row]; + + int col = index.column(); + switch (col) { + case 0: + if (!value.canConvert()) + return false; + vendor.SetId(value.toInt()); + return true; + case 1: + if (!value.canConvert()) + return false; + vendor.SetName(value.toString().toStdU16String()); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + case 2: + if (!value.canConvert()) + return false; + vendor.SetType(value.toString().toStdU16String()); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + case 3: + if (!value.canConvert()) + return false; + vendor.SetAddress(value.toString().toStdU16String()); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + case 4: + if (!value.canConvert()) + return false; + vendor.SetPhone(value.toString().toStdU16String()); + emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); + return true; + default: + return false; + } + } + return false; +} + +Qt::ItemFlags VendorModel::flags(const QModelIndex &index) const { + if (!index.isValid()) + return Qt::ItemIsEnabled; + + return QAbstractTableModel::flags(index) | Qt::ItemIsEditable; +} + +bool VendorModel::insertRows(int row, int count, const QModelIndex &parent) { + beginInsertRows(parent, row, row + count - 1); + for (int i = 0; i < count; i++) { + record_->GetVendors().insert(record_->GetVendors().cbegin() + row, + Vendor()); + } + endInsertRows(); + return true; +} + +bool VendorModel::removeRows(int row, int count, const QModelIndex &parent) { + beginRemoveRows(parent, row, row + count - 1); + record_->GetVendors().erase(record_->GetVendors().cbegin() + row, + record_->GetVendors().cbegin() + row + count); + endRemoveRows(); + return true; +} diff --git a/works/life/cpp-practicum/Record.hpp b/works/life/cpp-practicum/Record.hpp index 78b70ba..c379f04 100644 --- a/works/life/cpp-practicum/Record.hpp +++ b/works/life/cpp-practicum/Record.hpp @@ -5,7 +5,7 @@ #include "Vendor.hpp" #include -#include +#include #include #include @@ -19,8 +19,8 @@ public: ~Record() = default; public: - void WriteTo(QFile file); - void ReadFrom(QFile file); + void WriteTo(QTextStream &stream); + void ReadFrom(QTextStream &stream); std::vector &GetBooks() { return books_; } std::vector &GetVendors() { return vendors_; } @@ -47,7 +47,30 @@ public: const QModelIndex &parent = QModelIndex()) override; bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; + void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; private: Record *record_; -}; \ No newline at end of file +}; + +class VendorModel : public QAbstractTableModel { +public: + explicit VendorModel(Record *record) : record_(record) {} + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const override; + QVariant data(const QModelIndex &index, + int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, + int role = Qt::EditRole) override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + bool insertRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + bool removeRows(int row, int count, + const QModelIndex &parent = QModelIndex()) override; + +private: + Record *record_; +}; diff --git a/works/life/cpp-practicum/main.cpp b/works/life/cpp-practicum/main.cpp index 9ecc308..399c82c 100644 --- a/works/life/cpp-practicum/main.cpp +++ b/works/life/cpp-practicum/main.cpp @@ -1,6 +1,8 @@ #include "Record.hpp" #include +#include +#include #include #include #include @@ -8,49 +10,113 @@ #include #include #include +#include int main(int argc, char *argv[]) { QApplication application(argc, argv); + Record record; + + QDir app_dir(application.applicationDirPath()); + QFile data_file = app_dir.filePath("data.txt"); + std::unique_ptr stream; + if (data_file.exists()) { + data_file.open(QFile::ReadWrite); + stream.reset(new QTextStream(&data_file)); + stream->setCodec("UTF-8"); + try { + record.ReadFrom(*stream); + } catch (...) { + } + } else { + data_file.open(QFile::ReadWrite); + stream.reset(new QTextStream(&data_file)); + stream->setCodec("UTF-8"); + } + QWidget window; QVBoxLayout window_layout; window.setLayout(&window_layout); - QHBoxLayout top_bar; - window_layout.addLayout(&top_bar); + QHBoxLayout center_area; + window_layout.addLayout(¢er_area); - QPushButton import_button(QStringLiteral("导入")); - QPushButton export_button(QStringLiteral("导出")); - QPushButton add_book_button(QStringLiteral("添加书")); + QVBoxLayout book_area; + QVBoxLayout vendor_area; + center_area.addLayout(&book_area); + center_area.addLayout(&vendor_area); - top_bar.addWidget(&import_button); - top_bar.addWidget(&export_button); - top_bar.addStretch(1); - top_bar.addWidget(&add_book_button); + QHBoxLayout book_top_area; + QHBoxLayout vendor_top_area; + book_area.addLayout(&book_top_area); + vendor_area.addLayout(&vendor_top_area); - QHBoxLayout center_area; - window_layout.addLayout(¢er_area); + QPushButton book_add_button(QStringLiteral("添加")); + QPushButton book_remove_button(QStringLiteral("删除")); + + book_top_area.addStretch(1); + book_top_area.addWidget(&book_add_button); + book_top_area.addWidget(&book_remove_button); + + QPushButton vendor_add_button(QStringLiteral("添加")); + QPushButton vendor_remove_button(QStringLiteral("删除")); + + vendor_top_area.addStretch(1); + vendor_top_area.addWidget(&vendor_add_button); + vendor_top_area.addWidget(&vendor_remove_button); QTableView book_view; book_view.verticalHeader()->hide(); book_view.setSelectionBehavior(QAbstractItemView::SelectRows); book_view.setEditTriggers(QAbstractItemView::DoubleClicked); book_view.setSelectionMode(QAbstractItemView::SingleSelection); + book_view.setSortingEnabled(true); + QTableView vendor_view; + vendor_view.verticalHeader()->hide(); + vendor_view.setSelectionBehavior(QAbstractItemView::SelectRows); + vendor_view.setEditTriggers(QAbstractItemView::DoubleClicked); + vendor_view.setSelectionMode(QAbstractItemView::SingleSelection); - center_area.addWidget(&book_view); - center_area.addWidget(&vendor_view); + book_area.addWidget(&book_view, 1); + vendor_area.addWidget(&vendor_view, 1); - Record record; BookModel book_model(&record); + VendorModel vendor_model(&record); book_view.setModel(&book_model); + vendor_view.setModel(&vendor_model); - QObject::connect(&add_book_button, &QPushButton::clicked, [&book_model]() { + QObject::connect(&book_add_button, &QPushButton::clicked, [&book_model]() { book_model.insertRow(book_model.rowCount()); }); + QObject::connect( + &book_remove_button, &QPushButton::clicked, [&book_view, &book_model]() { + auto selected_rows = book_view.selectionModel()->selectedRows(); + for (const auto &row : selected_rows) { + book_model.removeRow(row.row()); + } + }); + + QObject::connect( + &vendor_add_button, &QPushButton::clicked, + [&vendor_model]() { vendor_model.insertRow(vendor_model.rowCount()); }); + + QObject::connect(&vendor_remove_button, &QPushButton::clicked, + [&vendor_view, &vendor_model]() { + auto selected_rows = + vendor_view.selectionModel()->selectedRows(); + for (const auto &row : selected_rows) { + vendor_model.removeRow(row.row()); + } + }); + window.show(); - return application.exec(); + int result = application.exec(); + + record.WriteTo(*stream); + + return result; } -- cgit v1.2.3