#include "quam/archive.h" #include "quam/pack.h" #include "quam/wad2.h" #include namespace Arc { Option getArchiveType(std::istream &st) noexcept { try { auto pos = st.tellg(); auto magic = readBytes<4>(st); st.seekg(pos); if(magic == std::array{'P', 'A', 'C', 'K'}) {return ArcType::Pack;} if(magic == std::array{'W', 'A', 'D', '2'}) {return ArcType::Wad2;} } catch(...) { } return None; } 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; }); return it != end() ? &*it : nullptr; } Node::Node(Dir &&f, std::string &&n, FileType t) : superType(std::move(f)), name(std::move(n)), type(t) { } Node::Node(File &&f, std::string &&n, FileType t) : superType(std::move(f)), name(std::move(n)), type(t) { } Model::Model(QObject *parent) : QAbstractItemModel{parent}, m_dir{nullptr} { } Model::~Model() { } QVariant Model::data(QModelIndex const &index, int role) const { if(!index.isValid()) { return QVariant{}; } auto node = static_cast(index.internalPointer()); auto col = Column(index.column()); switch(role) { case Qt::DecorationRole: if(col == Column::Name) { auto icon = std::holds_alternative(*node) ? "folder" : "text-x-generic"; return QVariant{QIcon::fromTheme(icon)}; } break; case Qt::DisplayRole: switch(col) { case Column::Size: if(auto file = std::get_if(node)) { return QVariant{QString::number(file->size())}; } break; case Column::Type: return QVariant{tr(enumToString(node->type))}; case Column::Name: return QVariant{tr(node->name.data())}; } case Qt::UserRole: return QVariant::fromValue(static_cast(node)); default: break; } return QVariant{}; } Qt::ItemFlags Model::flags(QModelIndex const &index) const { if(!index.isValid()) { return Qt::NoItemFlags; } else { return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren; } } QVariant Model::headerData(int section, Qt::Orientation ori, int role) const { if(ori == Qt::Horizontal && role == Qt::DisplayRole) { switch(Column(section)) { case Column::Size: return QVariant{tr("Size")}; case Column::Type: return QVariant{tr("Type")}; case Column::Name: return QVariant{tr("Name")}; } } return QVariant{}; } QModelIndex Model::index(int row, int col, QModelIndex const &parent) const { if(!m_dir || !hasIndex(row, col, parent) || row > m_dir->size()) { return QModelIndex{}; } else { return createIndex(row, col, &m_dir->at(row)); } } QModelIndex Model::parent(QModelIndex const &) const { return QModelIndex{}; } int Model::rowCount(QModelIndex const &) const { return m_dir ? m_dir->size() : 0; } int Model::columnCount(QModelIndex const &) const { return enumMax(); } Dir *Model::dir() const { return 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 = to; emit layoutChanged(); 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); } } } // EOF