Skip to content

Commit

Permalink
GUI: Add files from archive to tree
Browse files Browse the repository at this point in the history
  • Loading branch information
fdde authored and DrMcCoy committed Dec 27, 2017
1 parent 835b2a0 commit 39ab949
Show file tree
Hide file tree
Showing 4 changed files with 463 additions and 106 deletions.
265 changes: 215 additions & 50 deletions src/gui/resourcetree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,35 @@
*/

#include <QDir>
#include <QDirIterator>
#include <QFileInfoList>
#include <QTreeView>

#include "verdigris/wobjectimpl.h"

#include "src/aurora/biffile.h"
#include "src/aurora/bzffile.h"
#include "src/aurora/erffile.h"
#include "src/aurora/rimfile.h"
#include "src/aurora/zipfile.h"
#include "src/common/filepath.h"
#include "src/common/readfile.h"
#include "src/gui/resourcetree.h"
#include "src/gui/resourcetreeitem.h"

namespace GUI {

W_OBJECT_IMPL(ResourceTree)

ResourceTree::ResourceTree(const QString &rootPath, QObject *parent) : QAbstractItemModel(parent) {
_root = new ResourceTreeItem("Filename", "", nullptr);
_iconProvider = new QFileIconProvider();

if (!rootPath.isEmpty())
ResourceTree::setRootPath(rootPath);
setRootPath(rootPath);
}

ResourceTree::~ResourceTree() {
_archives.clear();
_keyDataFiles.clear();
delete _iconProvider;
delete _root;
}

Expand All @@ -51,16 +60,14 @@ void ResourceTree::populate(const QString& path, ResourceTreeItem *parentNode) {

QDir dir(path);
dir.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
dir.setSorting(QDir::DirsFirst);
dir.setSorting(QDir::DirsFirst | QDir::Name);

QFileInfoList list = dir.entryInfoList();

for (auto &e : list) {
curNode = new ResourceTreeItem(e.fileName(), parentNode);
curNode->setFileInfo(e);
curNode = new ResourceTreeItem(e.canonicalFilePath(), parentNode);
parentNode->addChild(curNode);
if (e.isDir()) {
curNode->setIsDir(true);
populate(e.canonicalFilePath(), curNode);
}
}
Expand All @@ -69,75 +76,107 @@ void ResourceTree::populate(const QString& path, ResourceTreeItem *parentNode) {
void ResourceTree::setRootPath(const QString& path) {
if (_root)
delete _root;

populate(path, new ResourceTreeItem("", "", nullptr));
_root = new ResourceTreeItem(path, nullptr);
populate(path, _root);
}

ResourceTreeItem *ResourceTree::getNode(const QModelIndex &index) const {
if (index.isValid())
return static_cast<ResourceTreeItem*>(index.internalPointer());
else
return _root;
}

bool ResourceTree::canFetchMore(const QModelIndex &index) {
ResourceTreeItem *item = getNode(index);
return _root;
}

if (item->getIsDir() && !item->getIsTraversed())
bool ResourceTree::canFetchMore(const QModelIndex &index) const {
auto type = getNode(index)->getFileType();
if (type == Aurora::kFileTypeZIP ||
type == Aurora::kFileTypeERF ||
type == Aurora::kFileTypeMOD ||
type == Aurora::kFileTypeNWM ||
type == Aurora::kFileTypeSAV ||
type == Aurora::kFileTypeHAK ||
type == Aurora::kFileTypeRIM ||
type == Aurora::kFileTypeKEY)
return true;

return false;
}

// TODO
void ResourceTree::fetchMore(const QModelIndex &index) {
// TreeNode *parent = getNode(index);
if (!index.isValid())
return;

// We only need special treatment for these archives
auto type = getNode(index)->getFileType();
if (type != Aurora::kFileTypeZIP &&
type != Aurora::kFileTypeERF &&
type != Aurora::kFileTypeMOD &&
type != Aurora::kFileTypeNWM &&
type != Aurora::kFileTypeSAV &&
type != Aurora::kFileTypeHAK &&
type != Aurora::kFileTypeRIM &&
type != Aurora::kFileTypeKEY)
return;

// We already added the archive members. Nothing to do
ResourceTreeItem::Data &data = getNode(index)->getData();
if (data.addedArchiveMembers)
return;

// Load the archive, if necessary
if (!data.archive) {
try {
data.archive = getArchive(getNode(index)->getPath());
} catch (Common::Exception &e) {
// If that fails, print the error and treat this archive as empty

e.add("Failed to load archive \"%s\"", getNode(index)->getName().toStdString().c_str());
Common::printException(e, "WARNING: ");

return;
}
}

// QList<TreeNode*> nodes;
// QDirIterator it(parent->get_path(), QDirIterator::Subdirectories);
// while (it.hasNext()) {
// TreeNode *TreeNode = new TreeNode("", it.path(), parent);
// if (TreeNode->is_dir())
// TreeNode->set_is_dir();
insertNodes(data, index);

// nodes.append(TreeNode);
// }
// insertNodes(0, nodes, index);
// parent->set_is_traversed();
data.addedArchiveMembers = true;
}

bool ResourceTree::hasChildren(const QModelIndex &index) const {
ResourceTreeItem *item = getNode(index);
if (!index.isValid())
return true;

if (item->getIsDir())
auto type = getNode(index)->getFileType();
if (type == Aurora::kFileTypeZIP ||
type == Aurora::kFileTypeERF ||
type == Aurora::kFileTypeMOD ||
type == Aurora::kFileTypeNWM ||
type == Aurora::kFileTypeSAV ||
type == Aurora::kFileTypeHAK ||
type == Aurora::kFileTypeRIM ||
type == Aurora::kFileTypeKEY)
return true;

return QAbstractItemModel::hasChildren(index);
return getNode(index)->hasChildren();
}

int ResourceTree::rowCount(const QModelIndex &parent) const {
ResourceTreeItem* item = getNode(parent);
return item->childCount();
return getNode(parent)->childCount();
}

int ResourceTree::columnCount(const QModelIndex &parent) const {
return 1;
}

QModelIndex ResourceTree::parent(const QModelIndex &index) const {
ResourceTreeItem *node = getNode(index);

ResourceTreeItem *parent = node->getParent();
ResourceTreeItem *parent = getNode(index)->getParent();
if (parent == _root)
return QModelIndex();

return createIndex(parent->row(), 0, parent);
}

QModelIndex ResourceTree::index(int row, int column, const QModelIndex &parent) const {
ResourceTreeItem *node = getNode(parent);

ResourceTreeItem *child = node->child(row);
ResourceTreeItem *child = getNode(parent)->child(row);

if (!child)
return QModelIndex();
Expand All @@ -153,13 +192,35 @@ QVariant ResourceTree::data(const QModelIndex &index, int role) const {
if (!index.isValid())
return QVariant();

if (role != Qt::DisplayRole)
return QVariant();

ResourceTreeItem *node = static_cast<ResourceTreeItem*>(index.internalPointer());
ResourceTreeItem *cur = getNode(index);

if (role == Qt::DecorationRole)
{
switch (cur->getSource()) {
case Source::kSourceFile:
switch (cur->getFileType()) {
case Aurora::kFileTypeZIP:
case Aurora::kFileTypeERF:
case Aurora::kFileTypeMOD:
case Aurora::kFileTypeNWM:
case Aurora::kFileTypeSAV:
case Aurora::kFileTypeHAK:
case Aurora::kFileTypeRIM:
case Aurora::kFileTypeKEY:
// TODO: special icon for archives?
//return _iconProvider->icon(QFileIconProvider::File);
default:
return _iconProvider->icon(QFileIconProvider::File);
}
case Source::kSourceDirectory:
return _iconProvider->icon(QFileIconProvider::Folder);
default:
return _iconProvider->icon(QFileIconProvider::File);
}
}

if (role == Qt::DisplayRole)
return node->getName();
return cur->getName();

return QVariant();
}
Expand All @@ -171,18 +232,122 @@ Qt::ItemFlags ResourceTree::flags(const QModelIndex &index) const {
return QAbstractItemModel::flags(index);
}

bool ResourceTree::insertNodes(int position, QList<ResourceTreeItem*> &nodes, QModelIndex parent) {
ResourceTreeItem *item = getNode(parent);
bool ResourceTree::insertNodes(ResourceTreeItem::Data &data, const QModelIndex &parent) {
QList<ResourceTreeItem*> nodes;
auto resources = data.archive->getResources();
for (auto r = resources.begin(); r != resources.end(); ++r) {
nodes << new ResourceTreeItem(getNode(parent)->getPath() + "/" + (*r).name.toQString(), data.archive, *r,
getNode(parent));
// fixme...
}

insertNodes(0, nodes, parent);
}

bool ResourceTree::insertNodes(int position, QList<ResourceTreeItem*> &nodes, const QModelIndex &parent) {
ResourceTreeItem *node = getNode(parent);

beginInsertRows(parent, position, position + nodes.count() - 1);

bool success = false;
for (auto &child : nodes)
success = item->insertChild(position, child);
node->addChild(child);

endInsertRows();

return success;
return true;
}

#define USTR(x) (Common::UString((x).toStdString()))

Aurora::Archive *ResourceTree::getArchive(const QString &path) {
ArchiveMap::iterator a = _archives.find(path.toStdString().c_str());
if (a != _archives.end())
return a->second;

Aurora::Archive *arch = 0;
switch (TypeMan.getFileType(USTR(path))) {
case Aurora::kFileTypeZIP:
arch = new Aurora::ZIPFile(new Common::ReadFile(path.toStdString().c_str()));
break;

case Aurora::kFileTypeERF:
case Aurora::kFileTypeMOD:
case Aurora::kFileTypeNWM:
case Aurora::kFileTypeSAV:
case Aurora::kFileTypeHAK:
arch = new Aurora::ERFFile(new Common::ReadFile(path.toStdString().c_str()));
break;

case Aurora::kFileTypeRIM:
arch = new Aurora::RIMFile(new Common::ReadFile(path.toStdString().c_str()));
break;

case Aurora::kFileTypeKEY: {
Aurora::KEYFile *key = new Aurora::KEYFile(new Common::ReadFile(path.toStdString().c_str()));
loadKEYDataFiles(*key);

arch = key;
break;
}

default:
throw Common::Exception("Invalid archive file \"%s\"", path.toStdString().c_str());
}

_archives.insert(std::make_pair(path.toStdString().c_str(), arch));
return arch;
}

#define USTR(x) (Common::UString((x).toStdString()))

Aurora::KEYDataFile *ResourceTree::getKEYDataFile(const Common::UString &file) {
KEYDataFileMap::iterator d = _keyDataFiles.find(file);
if (d != _keyDataFiles.end())
return d->second;

Common::UString path = Common::FilePath::normalize(USTR(_root->getPath() + "/" + file.toQString()));
if (path.empty())
throw Common::Exception("No such file or directory \"%s\"", USTR(_root->getPath() + "/" + file.toQString()).c_str());

Aurora::FileType type = TypeMan.getFileType(file);

Aurora::KEYDataFile *dataFile = 0;
switch (type) {
case Aurora::kFileTypeBIF:
dataFile = new Aurora::BIFFile(new Common::ReadFile(path));
break;

case Aurora::kFileTypeBZF:
dataFile = new Aurora::BZFFile(new Common::ReadFile(path));
break;

default:
throw Common::Exception("Unknown KEY data file type %d\n", type);
}

_keyDataFiles.insert(std::make_pair(file, dataFile));
return dataFile;
}

void ResourceTree::loadKEYDataFiles(Aurora::KEYFile &key) {
const std::vector<Common::UString> dataFiles = key.getDataFileList();
for (uint i = 0; i < dataFiles.size(); i++) {
try {

//GetStatusBar()->PushStatusText(Common::UString("Loading data file") + dataFiles[i] + "..."); // fixme

Aurora::KEYDataFile *dataFile = getKEYDataFile(dataFiles[i]);
key.addDataFile(i, dataFile);

//GetStatusBar()->PopStatusText(); // fixme

} catch (Common::Exception &e) {
e.add("Failed to load KEY data file \"%s\"", dataFiles[i].c_str());

// GetStatusBar()->PopStatusText(); // fixme
Common::printException(e, "WARNING: ");
}
}
}

} // End of namespace GUI

0 comments on commit 39ab949

Please sign in to comment.