TGAHNK YOU C++ VERY COOL
This commit is contained in:
parent
dab41d87ef
commit
881fa8c9bd
|
@ -25,6 +25,9 @@ inline constexpr std::nullopt_t None{std::nullopt};
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using Option = std::optional<T>;
|
using Option = std::optional<T>;
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
using Variant = std::variant<Ts...>;
|
||||||
|
|
||||||
struct Error : public std::runtime_error {
|
struct Error : public std::runtime_error {
|
||||||
using std::runtime_error::runtime_error;
|
using std::runtime_error::runtime_error;
|
||||||
};
|
};
|
||||||
|
@ -122,17 +125,20 @@ static inline QDebug operator<<(QDebug debug, std::string const &t) {
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static inline QDebug operator<<(QDebug debug, std::unique_ptr<T> const &t) {
|
|
||||||
debug << *t;
|
|
||||||
return debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T0, typename... Ts>
|
template<typename T0, typename... Ts>
|
||||||
static inline QDebug operator<<(QDebug debug,
|
static inline QDebug operator<<(QDebug debug, Variant<T0, Ts...> const &t) {
|
||||||
std::variant<T0, Ts...> const &t) {
|
|
||||||
std::visit([&](auto &&arg) {debug << arg;}, t);
|
std::visit([&](auto &&arg) {debug << arg;}, t);
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline QDebug operator<<(QDebug debug, Option<T> const &t) {
|
||||||
|
if(t) {
|
||||||
|
debug << *t;
|
||||||
|
} else {
|
||||||
|
debug << "None";
|
||||||
|
}
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
@ -6,66 +6,67 @@
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
|
||||||
namespace Arc {
|
namespace Arc {
|
||||||
|
Option<ArcType> getArchiveType(std::istream &st) noexcept {
|
||||||
Option<ArchiveType> getArchiveType(std::istream &st) noexcept {
|
|
||||||
try {
|
try {
|
||||||
auto pos = st.tellg();
|
auto pos = st.tellg();
|
||||||
auto magic = readBytes<4>(st);
|
auto magic = readBytes<4>(st);
|
||||||
st.seekg(pos);
|
st.seekg(pos);
|
||||||
if(magic == std::array{'P', 'A', 'C', 'K'}) {return ArcPack;}
|
if(magic == std::array{'P', 'A', 'C', 'K'}) {return ArcType::Pack;}
|
||||||
if(magic == std::array{'W', 'A', 'D', '2'}) {return ArcWad2;}
|
if(magic == std::array{'W', 'A', 'D', '2'}) {return ArcType::Wad2;}
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dir readArchive(std::istream &st) {
|
Dir readArchive(std::istream &st) {
|
||||||
switch(auto v = getArchiveType(st);
|
switch(auto v = getArchiveType(st);
|
||||||
v.has_value() ? *v : throw FileFormatError("not an archive")) {
|
v.has_value() ? *v : throw FileFormatError("not an archive")) {
|
||||||
case ArcPack: return readPack(st);
|
case ArcType::Pack: return readPack(st);
|
||||||
case ArcWad2: return readWad2(st);
|
case ArcType::Wad2: return readWad2(st);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Dir::iterator Dir::findNode(std::string const &name) {
|
Node *Dir::findNode(std::string const &name) {
|
||||||
return std::find_if(begin(), end(), [&name](Node const &node) {
|
auto it = std::find_if(begin(), end(), [&name](Node &node) {
|
||||||
return node.name == name;
|
return node.name == name;
|
||||||
});
|
});
|
||||||
}
|
return it != end() ? &*it : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
Node::Node(Dir &&f, std::string &&n, FileType t) :
|
Node::Node(Dir &&f, std::string &&n, FileType t) :
|
||||||
super_type(std::move(f)),
|
superType(std::move(f)),
|
||||||
name(std::move(n)),
|
name(std::move(n)),
|
||||||
type(t)
|
type(t)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Node::Node(File &&f, std::string &&n, FileType t) :
|
Node::Node(File &&f, std::string &&n, FileType t) :
|
||||||
super_type(std::move(f)),
|
superType(std::move(f)),
|
||||||
name(std::move(n)),
|
name(std::move(n)),
|
||||||
type(t)
|
type(t)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::Model(QObject *parent) :
|
Model::Model(QObject *parent) :
|
||||||
QAbstractItemModel{parent},
|
QAbstractItemModel{parent},
|
||||||
m_dir{nullptr}
|
m_dir{nullptr}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::~Model() {
|
Model::~Model() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant Model::data(QModelIndex const &index, int role) const {
|
QVariant Model::data(QModelIndex const &index, int role) const {
|
||||||
if(!index.isValid()) {
|
if(!index.isValid()) {
|
||||||
return QVariant{};
|
return QVariant{};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto node = static_cast<Node const *>(index.internalPointer());
|
auto node = static_cast<Node *>(index.internalPointer());
|
||||||
|
auto col = Column(index.column());
|
||||||
|
|
||||||
switch(role) {
|
switch(role) {
|
||||||
case Qt::DecorationRole:
|
case Qt::DecorationRole:
|
||||||
if(index.column() == ColumnName) {
|
if(col == Column::Name) {
|
||||||
auto icon =
|
auto icon =
|
||||||
std::holds_alternative<Dir>(*node) ? "folder"
|
std::holds_alternative<Dir>(*node) ? "folder"
|
||||||
: "text-x-generic";
|
: "text-x-generic";
|
||||||
|
@ -73,24 +74,26 @@ QVariant Model::data(QModelIndex const &index, int role) const {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
switch(index.column()) {
|
switch(col) {
|
||||||
case ColumnSize:
|
case Column::Size:
|
||||||
if(auto file = std::get_if<File>(node)) {
|
if(auto file = std::get_if<File>(node)) {
|
||||||
return QVariant{QString::number(file->size())};
|
return QVariant{QString::number(file->size())};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ColumnType:
|
case Column::Type:
|
||||||
return QVariant{tr(enumToString(node->type))};
|
return QVariant{tr(enumToString(node->type))};
|
||||||
case ColumnName:
|
case Column::Name:
|
||||||
return QVariant{tr(node->name.data())};
|
return QVariant{tr(node->name.data())};
|
||||||
}
|
}
|
||||||
|
case Qt::UserRole:
|
||||||
|
return QVariant::fromValue(static_cast<void *>(node));
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return QVariant{};
|
return QVariant{};
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::ItemFlags Model::flags(QModelIndex const &index) const {
|
Qt::ItemFlags Model::flags(QModelIndex const &index) const {
|
||||||
if(!index.isValid()) {
|
if(!index.isValid()) {
|
||||||
return Qt::NoItemFlags;
|
return Qt::NoItemFlags;
|
||||||
} else {
|
} else {
|
||||||
|
@ -99,55 +102,54 @@ Qt::ItemFlags Model::flags(QModelIndex const &index) const {
|
||||||
Qt::ItemIsEnabled |
|
Qt::ItemIsEnabled |
|
||||||
Qt::ItemNeverHasChildren;
|
Qt::ItemNeverHasChildren;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant Model::headerData(int section,
|
QVariant Model::headerData(int section,
|
||||||
Qt::Orientation orientation,
|
Qt::Orientation ori,
|
||||||
int role) const {
|
int role) const {
|
||||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
if(ori == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||||
switch(section) {
|
switch(Column(section)) {
|
||||||
case ColumnSize: return QVariant{tr("Size")};
|
case Column::Size: return QVariant{tr("Size")};
|
||||||
case ColumnType: return QVariant{tr("Type")};
|
case Column::Type: return QVariant{tr("Type")};
|
||||||
case ColumnName: return QVariant{tr("Name")};
|
case Column::Name: return QVariant{tr("Name")};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QVariant{};
|
return QVariant{};
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex Model::index(int row, int col, QModelIndex const &parent) const {
|
QModelIndex Model::index(int row,
|
||||||
|
int col,
|
||||||
|
QModelIndex const &parent) const {
|
||||||
if(!m_dir || !hasIndex(row, col, parent) || row > m_dir->size()) {
|
if(!m_dir || !hasIndex(row, col, parent) || row > m_dir->size()) {
|
||||||
return QModelIndex{};
|
return QModelIndex{};
|
||||||
} else {
|
} else {
|
||||||
// despite index data being const, this function does not take a const
|
return createIndex(row, col, &m_dir->at(row));
|
||||||
// pointer, which is very annoying!
|
}
|
||||||
return createIndex(row, col, const_cast<Node *>(&m_dir->at(row)));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QModelIndex Model::parent(QModelIndex const &) const {
|
QModelIndex Model::parent(QModelIndex const &) const {
|
||||||
return QModelIndex{};
|
return QModelIndex{};
|
||||||
}
|
}
|
||||||
|
|
||||||
int Model::rowCount(QModelIndex const &) const {
|
int Model::rowCount(QModelIndex const &) const {
|
||||||
return m_dir ? m_dir->size() : 0;
|
return m_dir ? m_dir->size() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Model::columnCount(QModelIndex const &) const {
|
int Model::columnCount(QModelIndex const &) const {
|
||||||
return enumMax<Column>();
|
return enumMax<Column>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dir *Model::dir() const {
|
Dir *Model::dir() const {
|
||||||
return m_dir;
|
return m_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setDir(Dir *dir) {
|
void Model::setDir(Dir *dir) {
|
||||||
if(dir != m_dir) {
|
if(dir != m_dir) {
|
||||||
m_dir = dir;
|
m_dir = dir;
|
||||||
emit layoutChanged();
|
emit layoutChanged();
|
||||||
emit dirChanged(dir);
|
emit dirChanged(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
@ -12,10 +12,10 @@ namespace Arc {
|
||||||
struct Node;
|
struct Node;
|
||||||
struct Dir;
|
struct Dir;
|
||||||
|
|
||||||
enum Column {
|
enum class Column {
|
||||||
ColumnSize,
|
Size,
|
||||||
ColumnType,
|
Type,
|
||||||
ColumnName,
|
Name,
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(Column)
|
Q_ENUM_NS(Column)
|
||||||
|
|
||||||
|
@ -30,28 +30,28 @@ namespace Arc {
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(FileType)
|
Q_ENUM_NS(FileType)
|
||||||
|
|
||||||
enum ArchiveType {
|
enum class ArcType {
|
||||||
ArcPack,
|
Pack,
|
||||||
ArcWad2,
|
Wad2,
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(ArchiveType)
|
Q_ENUM_NS(ArcType)
|
||||||
|
|
||||||
Option<ArchiveType> getArchiveType(std::istream &st) noexcept;
|
Option<ArcType> getArchiveType(std::istream &st) noexcept;
|
||||||
|
|
||||||
Dir readArchive(std::istream &st);
|
Dir readArchive(std::istream &st);
|
||||||
|
|
||||||
struct Dir : public std::vector<Node> {
|
struct Dir : public std::vector<Node> {
|
||||||
using std::vector<Node>::vector;
|
using std::vector<Node>::vector;
|
||||||
|
|
||||||
Dir::iterator findNode(std::string const &name);
|
Node *findNode(std::string const &name);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct File : public QByteArray {
|
struct File : public QByteArray {
|
||||||
using QByteArray::QByteArray;
|
using QByteArray::QByteArray;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Node : public std::variant<Dir, File> {
|
struct Node : public Variant<Dir, File> {
|
||||||
using super_type = std::variant<Dir, File>;
|
using superType = Variant<Dir, File>;
|
||||||
|
|
||||||
Node() = default;
|
Node() = default;
|
||||||
|
|
||||||
|
@ -74,13 +74,14 @@ namespace Arc {
|
||||||
|
|
||||||
QVariant data(QModelIndex const &index, int role) const override;
|
QVariant data(QModelIndex const &index, int role) const override;
|
||||||
Qt::ItemFlags flags(QModelIndex const &index) const override;
|
Qt::ItemFlags flags(QModelIndex const &index) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role)
|
QVariant headerData(int section, Qt::Orientation ori, int role)
|
||||||
const override;
|
const override;
|
||||||
QModelIndex index(int row,
|
QModelIndex index(int row,
|
||||||
int col,
|
int col,
|
||||||
QModelIndex const &parent = QModelIndex())
|
QModelIndex const &parent = QModelIndex())
|
||||||
const override;
|
const override;
|
||||||
QModelIndex parent(QModelIndex const &index = QModelIndex()) const override;
|
QModelIndex parent(QModelIndex const &index = QModelIndex())
|
||||||
|
const override;
|
||||||
int rowCount(QModelIndex const &index = QModelIndex()) const override;
|
int rowCount(QModelIndex const &index = QModelIndex()) const override;
|
||||||
int columnCount(QModelIndex const &index = QModelIndex()) const override;
|
int columnCount(QModelIndex const &index = QModelIndex()) const override;
|
||||||
|
|
||||||
|
@ -100,4 +101,12 @@ Q_DECLARE_METATYPE(Arc::Dir)
|
||||||
Q_DECLARE_METATYPE(Arc::File)
|
Q_DECLARE_METATYPE(Arc::File)
|
||||||
Q_DECLARE_METATYPE(Arc::Node)
|
Q_DECLARE_METATYPE(Arc::Node)
|
||||||
|
|
||||||
|
static inline QDebug operator<<(QDebug debug, Arc::Node const &t) {
|
||||||
|
debug << "Arc::Node(" << t.name << ", ";
|
||||||
|
std::visit([&](auto &&arg) {debug << arg;},
|
||||||
|
static_cast<Variant<Arc::Dir, Arc::File>>(t));
|
||||||
|
debug << ")";
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
@ -59,7 +59,7 @@ static PackEntry readPackEntry(std::istream &st) {
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void insertFile(Arc::Dir &dir, std::string name, Arc::File file) {
|
static void insertFile(Arc::Dir &dir, std::string &name, Arc::File &file) {
|
||||||
Option<std::string> next;
|
Option<std::string> next;
|
||||||
|
|
||||||
if(auto slash = name.find('/'); slash != std::string::npos) {
|
if(auto slash = name.find('/'); slash != std::string::npos) {
|
||||||
|
@ -68,18 +68,14 @@ static void insertFile(Arc::Dir &dir, std::string name, Arc::File file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto existing = dir.findNode(name);
|
auto existing = dir.findNode(name);
|
||||||
|
|
||||||
if(next) {
|
if(next) {
|
||||||
auto ref =
|
auto &ref = existing ? *existing
|
||||||
existing != dir.end()
|
|
||||||
? *existing
|
|
||||||
: dir.emplace_back(Arc::Dir{}, std::move(name));
|
: dir.emplace_back(Arc::Dir{}, std::move(name));
|
||||||
insertFile(std::get<Arc::Dir>(ref), *std::move(next), std::move(file));
|
insertFile(std::get<Arc::Dir>(ref), *next, file);
|
||||||
} else {
|
} else if(!existing) {
|
||||||
if(existing != dir.end()) {
|
|
||||||
throw FileFormatError("duplicate file");
|
|
||||||
}
|
|
||||||
dir.emplace_back(std::move(file), std::move(name));
|
dir.emplace_back(std::move(file), std::move(name));
|
||||||
|
} else {
|
||||||
|
throw FileFormatError("duplicate file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +87,7 @@ Arc::Dir readPack(std::istream &st) {
|
||||||
|
|
||||||
for(quint32 i = 0; i < hdr.dirNum; i++) {
|
for(quint32 i = 0; i < hdr.dirNum; i++) {
|
||||||
auto ent = readPackEntry(st);
|
auto ent = readPackEntry(st);
|
||||||
insertFile(root, std::move(ent.name), std::move(ent.file));
|
insertFile(root, ent.name, ent.file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
|
|
|
@ -19,7 +19,10 @@ Project::Project(Arc::Dir &&arc, QErrorMessage *errors, QMdiArea *parent) :
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
showMaximized();
|
showMaximized();
|
||||||
|
|
||||||
connect(m_model, &Arc::Model::dirChanged, this, &Project::dirChanged);
|
connect(m_model, &Arc::Model::dirChanged,
|
||||||
|
this, &Project::dirChanged);
|
||||||
|
connect(tableView, &QAbstractItemView::doubleClicked,
|
||||||
|
this, &Project::viewDoubleClicked);
|
||||||
|
|
||||||
m_sorter->setSourceModel(m_model);
|
m_sorter->setSourceModel(m_model);
|
||||||
tableView->setModel(m_sorter);
|
tableView->setModel(m_sorter);
|
||||||
|
@ -33,4 +36,12 @@ void Project::dirChanged(Arc::Dir *) {
|
||||||
tableView->resizeColumnsToContents();
|
tableView->resizeColumnsToContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Project::viewDoubleClicked(QModelIndex const &index) {
|
||||||
|
auto node = static_cast<Arc::Node *>(index.data(Qt::UserRole)
|
||||||
|
.value<void *>());
|
||||||
|
if(auto dir = std::get_if<Arc::Dir>(node)) {
|
||||||
|
m_model->setDir(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void dirChanged(Arc::Dir *dir);
|
void dirChanged(Arc::Dir *dir);
|
||||||
|
void viewDoubleClicked(QModelIndex const &index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Arc::Dir m_arc;
|
Arc::Dir m_arc;
|
||||||
|
|
|
@ -82,11 +82,6 @@ Arc::Dir readWad2(std::istream &st) {
|
||||||
|
|
||||||
for(quint32 i = 0; i < hdr.dirNum; i++) {
|
for(quint32 i = 0; i < hdr.dirNum; i++) {
|
||||||
auto ent = readWad2Entry(st);
|
auto ent = readWad2Entry(st);
|
||||||
/*
|
|
||||||
if(root.findNode(ent.name) != root.end()) {
|
|
||||||
throw FileFormatError("duplicate file");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
root.emplace_back(std::move(ent.file), std::move(ent.name), ent.type);
|
root.emplace_back(std::move(ent.file), std::move(ent.name), ent.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user