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>
|
||||
using Option = std::optional<T>;
|
||||
|
||||
template<typename... Ts>
|
||||
using Variant = std::variant<Ts...>;
|
||||
|
||||
struct Error : public std::runtime_error {
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
@ -122,17 +125,20 @@ static inline QDebug operator<<(QDebug debug, std::string const &t) {
|
|||
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>
|
||||
static inline QDebug operator<<(QDebug debug,
|
||||
std::variant<T0, Ts...> const &t) {
|
||||
static inline QDebug operator<<(QDebug debug, Variant<T0, Ts...> const &t) {
|
||||
std::visit([&](auto &&arg) {debug << arg;}, t);
|
||||
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
|
||||
|
|
|
@ -6,148 +6,150 @@
|
|||
#include <QIcon>
|
||||
|
||||
namespace Arc {
|
||||
|
||||
Option<ArchiveType> 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 ArcPack;}
|
||||
if(magic == std::array{'W', 'A', 'D', '2'}) {return ArcWad2;}
|
||||
} catch(...) {
|
||||
Option<ArcType> 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;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
Dir readArchive(std::istream &st) {
|
||||
switch(auto v = getArchiveType(st);
|
||||
v.has_value() ? *v : throw FileFormatError("not an archive")) {
|
||||
case ArcPack: return readPack(st);
|
||||
case ArcWad2: return readWad2(st);
|
||||
Dir readArchive(std::istream &st) {
|
||||
switch(auto v = getArchiveType(st);
|
||||
v.has_value() ? *v : throw FileFormatError("not an archive")) {
|
||||
case ArcType::Pack: return readPack(st);
|
||||
case ArcType::Wad2: return readWad2(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dir::iterator Dir::findNode(std::string const &name) {
|
||||
return std::find_if(begin(), end(), [&name](Node const &node) {
|
||||
return node.name == name;
|
||||
});
|
||||
}
|
||||
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) :
|
||||
super_type(std::move(f)),
|
||||
name(std::move(n)),
|
||||
type(t)
|
||||
{
|
||||
}
|
||||
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) :
|
||||
super_type(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(QObject *parent) :
|
||||
QAbstractItemModel{parent},
|
||||
m_dir{nullptr}
|
||||
{
|
||||
}
|
||||
|
||||
Model::~Model() {
|
||||
}
|
||||
Model::~Model() {
|
||||
}
|
||||
|
||||
QVariant Model::data(QModelIndex const &index, int role) const {
|
||||
if(!index.isValid()) {
|
||||
QVariant Model::data(QModelIndex const &index, int role) const {
|
||||
if(!index.isValid()) {
|
||||
return QVariant{};
|
||||
}
|
||||
|
||||
auto node = static_cast<Node *>(index.internalPointer());
|
||||
auto col = Column(index.column());
|
||||
|
||||
switch(role) {
|
||||
case Qt::DecorationRole:
|
||||
if(col == Column::Name) {
|
||||
auto icon =
|
||||
std::holds_alternative<Dir>(*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<File>(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<void *>(node));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant{};
|
||||
}
|
||||
|
||||
auto node = static_cast<Node const *>(index.internalPointer());
|
||||
|
||||
switch(role) {
|
||||
case Qt::DecorationRole:
|
||||
if(index.column() == ColumnName) {
|
||||
auto icon =
|
||||
std::holds_alternative<Dir>(*node) ? "folder"
|
||||
: "text-x-generic";
|
||||
return QVariant{QIcon::fromTheme(icon)};
|
||||
}
|
||||
break;
|
||||
case Qt::DisplayRole:
|
||||
switch(index.column()) {
|
||||
case ColumnSize:
|
||||
if(auto file = std::get_if<File>(node)) {
|
||||
return QVariant{QString::number(file->size())};
|
||||
}
|
||||
break;
|
||||
case ColumnType:
|
||||
return QVariant{tr(enumToString(node->type))};
|
||||
case ColumnName:
|
||||
return QVariant{tr(node->name.data())};
|
||||
}
|
||||
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 orientation,
|
||||
int role) const {
|
||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
switch(section) {
|
||||
case ColumnSize: return QVariant{tr("Size")};
|
||||
case ColumnType: return QVariant{tr("Type")};
|
||||
case ColumnName: return QVariant{tr("Name")};
|
||||
Qt::ItemFlags Model::flags(QModelIndex const &index) const {
|
||||
if(!index.isValid()) {
|
||||
return Qt::NoItemFlags;
|
||||
} else {
|
||||
return Qt::ItemIsSelectable |
|
||||
Qt::ItemIsDragEnabled |
|
||||
Qt::ItemIsEnabled |
|
||||
Qt::ItemNeverHasChildren;
|
||||
}
|
||||
}
|
||||
return QVariant{};
|
||||
}
|
||||
|
||||
QModelIndex Model::index(int row, int col, QModelIndex const &parent) const {
|
||||
if(!m_dir || !hasIndex(row, col, parent) || row > m_dir->size()) {
|
||||
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{};
|
||||
} else {
|
||||
// despite index data being const, this function does not take a const
|
||||
// pointer, which is very annoying!
|
||||
return createIndex(row, col, const_cast<Node *>(&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<Column>();
|
||||
}
|
||||
|
||||
Dir *Model::dir() const {
|
||||
return m_dir;
|
||||
}
|
||||
|
||||
void Model::setDir(Dir *dir) {
|
||||
if(dir != m_dir) {
|
||||
m_dir = dir;
|
||||
emit layoutChanged();
|
||||
emit dirChanged(dir);
|
||||
int Model::rowCount(QModelIndex const &) const {
|
||||
return m_dir ? m_dir->size() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Model::columnCount(QModelIndex const &) const {
|
||||
return enumMax<Column>();
|
||||
}
|
||||
|
||||
Dir *Model::dir() const {
|
||||
return m_dir;
|
||||
}
|
||||
|
||||
void Model::setDir(Dir *dir) {
|
||||
if(dir != m_dir) {
|
||||
m_dir = dir;
|
||||
emit layoutChanged();
|
||||
emit dirChanged(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
|
|
@ -12,10 +12,10 @@ namespace Arc {
|
|||
struct Node;
|
||||
struct Dir;
|
||||
|
||||
enum Column {
|
||||
ColumnSize,
|
||||
ColumnType,
|
||||
ColumnName,
|
||||
enum class Column {
|
||||
Size,
|
||||
Type,
|
||||
Name,
|
||||
};
|
||||
Q_ENUM_NS(Column)
|
||||
|
||||
|
@ -30,28 +30,28 @@ namespace Arc {
|
|||
};
|
||||
Q_ENUM_NS(FileType)
|
||||
|
||||
enum ArchiveType {
|
||||
ArcPack,
|
||||
ArcWad2,
|
||||
enum class ArcType {
|
||||
Pack,
|
||||
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);
|
||||
|
||||
struct Dir : public std::vector<Node> {
|
||||
using std::vector<Node>::vector;
|
||||
|
||||
Dir::iterator findNode(std::string const &name);
|
||||
Node *findNode(std::string const &name);
|
||||
};
|
||||
|
||||
struct File : public QByteArray {
|
||||
using QByteArray::QByteArray;
|
||||
};
|
||||
|
||||
struct Node : public std::variant<Dir, File> {
|
||||
using super_type = std::variant<Dir, File>;
|
||||
struct Node : public Variant<Dir, File> {
|
||||
using superType = Variant<Dir, File>;
|
||||
|
||||
Node() = default;
|
||||
|
||||
|
@ -74,13 +74,14 @@ namespace Arc {
|
|||
|
||||
QVariant data(QModelIndex const &index, int role) 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;
|
||||
QModelIndex index(int row,
|
||||
int col,
|
||||
QModelIndex const &parent = QModelIndex())
|
||||
int col,
|
||||
QModelIndex const &parent = QModelIndex())
|
||||
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 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::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
|
||||
|
|
|
@ -59,7 +59,7 @@ static PackEntry readPackEntry(std::istream &st) {
|
|||
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;
|
||||
|
||||
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);
|
||||
|
||||
if(next) {
|
||||
auto ref =
|
||||
existing != dir.end()
|
||||
? *existing
|
||||
: dir.emplace_back(Arc::Dir{}, std::move(name));
|
||||
insertFile(std::get<Arc::Dir>(ref), *std::move(next), std::move(file));
|
||||
} else {
|
||||
if(existing != dir.end()) {
|
||||
throw FileFormatError("duplicate file");
|
||||
}
|
||||
auto &ref = existing ? *existing
|
||||
: dir.emplace_back(Arc::Dir{}, std::move(name));
|
||||
insertFile(std::get<Arc::Dir>(ref), *next, file);
|
||||
} else if(!existing) {
|
||||
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++) {
|
||||
auto ent = readPackEntry(st);
|
||||
insertFile(root, std::move(ent.name), std::move(ent.file));
|
||||
insertFile(root, ent.name, ent.file);
|
||||
}
|
||||
|
||||
return root;
|
||||
|
|
|
@ -19,7 +19,10 @@ Project::Project(Arc::Dir &&arc, QErrorMessage *errors, QMdiArea *parent) :
|
|||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
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);
|
||||
tableView->setModel(m_sorter);
|
||||
|
@ -33,4 +36,12 @@ void Project::dirChanged(Arc::Dir *) {
|
|||
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
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
|
||||
private slots:
|
||||
void dirChanged(Arc::Dir *dir);
|
||||
void viewDoubleClicked(QModelIndex const &index);
|
||||
|
||||
private:
|
||||
Arc::Dir m_arc;
|
||||
|
|
|
@ -82,11 +82,6 @@ Arc::Dir readWad2(std::istream &st) {
|
|||
|
||||
for(quint32 i = 0; i < hdr.dirNum; i++) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user