diff --git a/source/common.h b/source/common.h index 6f40f7d..5aba29a 100644 --- a/source/common.h +++ b/source/common.h @@ -120,6 +120,15 @@ static inline int enumMax() { return QMetaEnum::fromType().keyCount(); } +template +static inline T orThrow(Option opt, Error err) { + if(opt) { + return *opt; + } else { + throw err; + } +} + static inline QDebug operator<<(QDebug debug, std::string const &t) { debug << QString::fromStdString(t); return debug; diff --git a/source/quam/archive.cc b/source/quam/archive.cc index 000c4b9..6a5b3e9 100644 --- a/source/quam/archive.cc +++ b/source/quam/archive.cc @@ -18,14 +18,42 @@ namespace Arc { return None; } - Dir readArchive(std::istream &st) { - switch(auto v = getArchiveType(st); - v.has_value() ? *v : throw FileFormatError("not an archive")) { + Dir Dir::readArchive(std::istream &st, ArcType type) { + switch(type) { case ArcType::Pack: return readPack(st); case ArcType::Wad2: return readWad2(st); } } + ArcInfo::ArcInfo(ArcType arcType) noexcept : + type{arcType} + { + switch(type) { + case ArcType::Pack: + pathMaxChars = 56; + validatorType = PackValidator::staticMetaObject; + break; + case ArcType::Wad2: + pathMaxChars = 16; + validatorType = Wad2Validator::staticMetaObject; + break; + } + } + + Arc::Arc(std::istream &st, QObject *parent) : + QObject{parent}, + info{ArcInfo(orThrow(getArchiveType(st), + FileFormatError("not an archive")))}, + root{Dir::readArchive(st, info.type)}, + validator{qobject_cast(info.validatorType + .newInstance(Q_ARG(QObject *, + this)))} + { + } + + Arc::~Arc() { + } + Node *Dir::findNode(std::string const &name) { auto it = std::find_if(begin(), end(), [&name](Node &node) { return node.name == name; @@ -143,17 +171,25 @@ namespace Arc { return m_dir; } - void Model::setDir(Dir *dir) { - if(dir != m_dir) { + void Model::setDir(Dir *to) { + auto from = m_dir; + if(to != from) { emit layoutAboutToBeChanged(); for(int row = 0, rows = rowCount(); row < rows; row++) { for(int col = 0, cols = columnCount(); col < cols; col++) { changePersistentIndex(index(row, col), QModelIndex{}); } } - m_dir = dir; + m_dir = to; emit layoutChanged(); - emit dirChanged(dir); + emit dirChanged(from, to); + } + } + + void Model::setDirToIndex(QModelIndex const &ind) { + auto node = static_cast(ind.data(Qt::UserRole).value()); + if(auto dir = std::get_if(node)) { + setDir(dir); } } } diff --git a/source/quam/archive.h b/source/quam/archive.h index 2ad12b6..de67f4c 100644 --- a/source/quam/archive.h +++ b/source/quam/archive.h @@ -4,14 +4,13 @@ #include #include +#include #include +#include namespace Arc { Q_NAMESPACE - struct Node; - struct Dir; - enum class Column { Size, Type, @@ -36,14 +35,14 @@ namespace Arc { }; Q_ENUM_NS(ArcType) - Option getArchiveType(std::istream &st) noexcept; - - Dir readArchive(std::istream &st); + struct Node; struct Dir : public std::vector { using std::vector::vector; Node *findNode(std::string const &name); + + static Dir readArchive(std::istream &st, ArcType type); }; struct File : public QByteArray { @@ -89,13 +88,36 @@ namespace Arc { public slots: void setDir(Dir *dir); + void setDirToIndex(QModelIndex const &ind); signals: - void dirChanged(Dir *dir); + void dirChanged(Dir *from, Dir *to); private: Dir *m_dir; }; + + struct ArcInfo { + ArcInfo(ArcType arcType) noexcept; + + ArcType type; + std::size_t pathMaxChars; + QMetaObject validatorType; + }; + + class Arc : QObject { + Q_OBJECT + + public: + explicit Arc(std::istream &st, QObject *parent = nullptr); + ~Arc(); + + ArcInfo info; + Dir root; + QValidator *validator; + }; + + Option getArchiveType(std::istream &st) noexcept; } Q_DECLARE_METATYPE(Arc::Dir) Q_DECLARE_METATYPE(Arc::File) diff --git a/source/quam/main.cc b/source/quam/main.cc index aabad62..dca3194 100644 --- a/source/quam/main.cc +++ b/source/quam/main.cc @@ -43,9 +43,7 @@ static int modeText(int argc, char *argv[]) { auto fileName = par.value(fileNameOpt).toStdString(); auto st = openReadBin(fileName); - auto arc = Arc::readArchive(st); - - qDebug() << arc; + qDebug() << Arc::Arc(st).root; return 0; } diff --git a/source/quam/main_window.cc b/source/quam/main_window.cc index f5831d9..78076be 100644 --- a/source/quam/main_window.cc +++ b/source/quam/main_window.cc @@ -34,9 +34,8 @@ void MainWindow::fileOpen() { if(!fileName.isEmpty()) { try { - auto st = openReadBin(fileName.toStdString()); - auto arc = Arc::readArchive(st); - new Project{std::move(arc), m_errors, mdiArea}; + auto st = openReadBin(fileName.toStdString()); + new Project{st, m_errors, mdiArea}; } catch(std::exception const &exc) { m_errors->showMessage(tr(exc.what())); } diff --git a/source/quam/pack.cc b/source/quam/pack.cc index 6ccff84..1cbc08c 100644 --- a/source/quam/pack.cc +++ b/source/quam/pack.cc @@ -93,4 +93,13 @@ Arc::Dir readPack(std::istream &st) { return root; } +PackValidator::PackValidator(QObject *parent) : + QValidator{parent} +{ +} + +QValidator::State PackValidator::validate(QString &input, int &pos) const { + return QValidator::Acceptable; +} + // EOF diff --git a/source/quam/pack.h b/source/quam/pack.h index 63b26e6..bd0b402 100644 --- a/source/quam/pack.h +++ b/source/quam/pack.h @@ -4,6 +4,17 @@ #include "quam/archive.h" +#include + +class PackValidator : public QValidator { + Q_OBJECT + +public: + Q_INVOKABLE explicit PackValidator(QObject *parent); + + QValidator::State validate(QString &input, int &pos) const override; +}; + Arc::Dir readPack(std::istream &st); // EOF diff --git a/source/quam/project.cc b/source/quam/project.cc index c13805c..01d7131 100644 --- a/source/quam/project.cc +++ b/source/quam/project.cc @@ -5,15 +5,17 @@ #include #include -Project::Project(Arc::Dir &&arc, QErrorMessage *errors, QMdiArea *parent) : +Project::Project(std::istream &st, QErrorMessage *errors, QMdiArea *parent) : QMdiSubWindow{parent}, Ui::Project{}, - m_arc{std::move(arc)}, + m_arc{new Arc::Arc{st, this}}, + m_root{&m_arc->root}, + m_lastDir{nullptr}, m_errors{errors}, m_model{new Arc::Model{this}}, m_sorter{new QSortFilterProxyModel{this}} { - auto widget = new QWidget(this); + auto widget = new QWidget{this}; setupUi(widget); setWidget(widget); setAttribute(Qt::WA_DeleteOnClose); @@ -22,26 +24,19 @@ Project::Project(Arc::Dir &&arc, QErrorMessage *errors, QMdiArea *parent) : connect(m_model, &Arc::Model::dirChanged, this, &Project::dirChanged); connect(tableView, &QAbstractItemView::doubleClicked, - this, &Project::viewDoubleClicked); + m_model, &Arc::Model::setDirToIndex); m_sorter->setSourceModel(m_model); tableView->setModel(m_sorter); - m_model->setDir(&m_arc); + m_model->setDir(m_root); } Project::~Project() { } -void Project::dirChanged(Arc::Dir *) { +void Project::dirChanged(Arc::Dir *from, Arc::Dir *to) { + m_lastDir = from; tableView->resizeColumnsToContents(); } -void Project::viewDoubleClicked(QModelIndex const &index) { - auto node = static_cast(index.data(Qt::UserRole) - .value()); - if(auto dir = std::get_if(node)) { - m_model->setDir(dir); - } -} - // EOF diff --git a/source/quam/project.h b/source/quam/project.h index 73a1826..ece5a7a 100644 --- a/source/quam/project.h +++ b/source/quam/project.h @@ -17,15 +17,15 @@ class Project : public QMdiSubWindow, private Ui::Project { Q_OBJECT public: - explicit Project(Arc::Dir &&arc, QErrorMessage *errors, QMdiArea *parent); + explicit Project(std::istream &st, QErrorMessage *errors, QMdiArea *parent); virtual ~Project(); private slots: - void dirChanged(Arc::Dir *dir); - void viewDoubleClicked(QModelIndex const &index); + void dirChanged(Arc::Dir *from, Arc::Dir *to); private: - Arc::Dir m_arc; + Arc::Arc *m_arc; + Arc::Dir *m_root, *m_lastDir; QErrorMessage *m_errors; Arc::Model *m_model; QSortFilterProxyModel *m_sorter; diff --git a/source/quam/project.ui b/source/quam/project.ui index c7b429d..e646aff 100644 --- a/source/quam/project.ui +++ b/source/quam/project.ui @@ -19,43 +19,66 @@ Qt::Horizontal - - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAlwaysOff - - - false - - - true - - - true - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - false - - - true - - - true - - - true - - - false - + + + + + + + + + + + + + + true + + + + + + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + + false + + + true + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + true + + + true + + + true + + + false + + + + diff --git a/source/quam/wad2.cc b/source/quam/wad2.cc index 996bb2b..e2dec57 100644 --- a/source/quam/wad2.cc +++ b/source/quam/wad2.cc @@ -88,4 +88,13 @@ Arc::Dir readWad2(std::istream &st) { return root; } +Wad2Validator::Wad2Validator(QObject *parent) : + QValidator{parent} +{ +} + +QValidator::State Wad2Validator::validate(QString &input, int &pos) const { + return QValidator::Acceptable; +} + // EOF diff --git a/source/quam/wad2.h b/source/quam/wad2.h index 01d0acd..6a35f7b 100644 --- a/source/quam/wad2.h +++ b/source/quam/wad2.h @@ -4,6 +4,17 @@ #include "quam/archive.h" +#include + +class Wad2Validator : public QValidator { + Q_OBJECT + +public: + Q_INVOKABLE explicit Wad2Validator(QObject *parent); + + QValidator::State validate(QString &input, int &pos) const override; +}; + Arc::Dir readWad2(std::istream &st); // EOF