2022-11-17 08:26:05 +00:00
|
|
|
#include "xmlprojectmanager.h"
|
|
|
|
|
|
|
|
#include <xmlconfig.h>
|
|
|
|
#include <QDir>
|
|
|
|
#include <QRandomGenerator>
|
|
|
|
#include <QDateTime>
|
|
|
|
#include <QTextStream>
|
|
|
|
#include <QCoreApplication>
|
|
|
|
#include <QIcon>
|
|
|
|
|
|
|
|
using namespace Project;
|
|
|
|
using namespace Config;
|
|
|
|
|
|
|
|
XMLProjectManager::XMLProjectManager(QObject *parent)
|
|
|
|
: Project::ProjectManager(parent),
|
|
|
|
project_config(new XMLConfig(this)),
|
|
|
|
mode_holder(new QStandardItemModel(this)),
|
|
|
|
open_status(false){ }
|
|
|
|
|
|
|
|
XMLProjectManager::~XMLProjectManager(){
|
|
|
|
delete project_config;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool XMLProjectManager::isOpen() const
|
|
|
|
{
|
|
|
|
return open_status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* <?xml version='1.0'?>
|
|
|
|
* <project name="project-name" config="xml-path">
|
|
|
|
* <package name="name" path="filepath">
|
|
|
|
* <file name="name" path="filepath"/>
|
|
|
|
* <package name="name2" path="filepath" />
|
|
|
|
* </package>
|
|
|
|
* </project>
|
|
|
|
*/
|
|
|
|
int XMLProjectManager::openProject(const QString &project_file)
|
|
|
|
{
|
|
|
|
file_path = project_file;
|
|
|
|
QFileInfo info(project_file);
|
|
|
|
if(!info.exists())
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
// 获取项目文件内容
|
|
|
|
QFile project_in(project_file);
|
|
|
|
if(!project_in.open(QIODevice::ReadOnly|QIODevice::Text))
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
// 载入文件内容
|
|
|
|
QDomDocument doc;
|
|
|
|
QString err; int row, col;
|
|
|
|
if(!doc.setContent(&project_in, false, &err, &row, &col))
|
|
|
|
return -3;
|
|
|
|
|
|
|
|
// 构建项目组织树
|
|
|
|
auto root_elm = doc.documentElement();
|
|
|
|
auto name = root_elm.attribute("name");
|
|
|
|
auto pnode = new ProjectNode(NodeType::GROUP, name);
|
|
|
|
pnode->setFile(root_elm.attribute("config"));
|
|
|
|
mode_holder->appendRow(pnode);
|
|
|
|
|
|
|
|
// 载入项目配置
|
|
|
|
auto config = root_elm.attribute("config");
|
|
|
|
auto config_path = info.dir().filePath(config);
|
|
|
|
project_config->loadFile(config_path);
|
|
|
|
|
|
|
|
structure_parser(root_elm, pnode);
|
|
|
|
|
|
|
|
open_status = true;
|
|
|
|
pnode->setIcon(QIcon(":/icons/toplevel.png"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int XMLProjectManager::newProject(const QString &project_dir, const QString &name)
|
|
|
|
{
|
|
|
|
// 确定目标项目文件
|
|
|
|
QDir root(project_dir);
|
|
|
|
QDir::setCurrent(root.path());
|
|
|
|
auto project_file = root.filePath(name+".nsf");
|
|
|
|
file_path = project_file;
|
|
|
|
|
|
|
|
QFileInfo info(project_file);
|
|
|
|
if(info.exists())
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
// 构建项目表示树
|
|
|
|
auto project_node = new ProjectNode(NodeType::GROUP, name);
|
|
|
|
project_node->setFile(".project_config.xml");
|
|
|
|
mode_holder->appendRow(project_node);
|
|
|
|
project_config->loadFile(root.filePath(project_node->file()));
|
|
|
|
|
|
|
|
// 写出到磁盘
|
|
|
|
save();
|
|
|
|
open_status = true;
|
|
|
|
project_node->setIcon(QIcon(":/icons/toplevel.png"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void XMLProjectManager::closeProject()
|
|
|
|
{
|
|
|
|
open_status = false;
|
|
|
|
mode_holder->clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void XMLProjectManager::save()
|
|
|
|
{
|
|
|
|
project_config->save();
|
|
|
|
|
|
|
|
QDomDocument doc;
|
|
|
|
auto pnode = static_cast<ProjectNode*>(mode_holder->item(0));
|
|
|
|
doc.appendChild(doc.createProcessingInstruction("xml", "version='1.0'"));
|
|
|
|
auto project_elm = doc.createElement("project");
|
|
|
|
project_elm.setAttribute("name", pnode->text());
|
|
|
|
project_elm.setAttribute("config", pnode->file());
|
|
|
|
doc.appendChild(project_elm);
|
|
|
|
|
|
|
|
structure_severlize(pnode, project_elm);
|
|
|
|
|
|
|
|
QFile records(file_path);
|
|
|
|
if(!records.open(QIODevice::WriteOnly|QIODevice::Text))
|
|
|
|
return;
|
|
|
|
|
|
|
|
QTextStream txout(&records);
|
|
|
|
doc.save(txout, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString XMLProjectManager::projectName() const
|
|
|
|
{
|
|
|
|
return mode_holder->item(0)->text();
|
|
|
|
}
|
|
|
|
|
|
|
|
Configration *XMLProjectManager::configraions() const
|
|
|
|
{
|
|
|
|
return this->project_config;
|
|
|
|
}
|
|
|
|
|
|
|
|
QStandardItemModel *XMLProjectManager::model() const
|
|
|
|
{
|
|
|
|
return mode_holder;
|
|
|
|
}
|
|
|
|
|
|
|
|
void XMLProjectManager::structure_parser(QDomElement struct_elm, ProjectNode *pnode)
|
|
|
|
{
|
|
|
|
auto children = struct_elm.childNodes();
|
|
|
|
|
|
|
|
for(auto idx=0; idx<children.count(); ++idx) {
|
|
|
|
auto node = children.at(idx);
|
|
|
|
if(node.isElement()){
|
|
|
|
auto xnode = node.toElement();
|
|
|
|
|
|
|
|
|
|
|
|
ProjectNode *node = nullptr;
|
|
|
|
if(xnode.tagName()=="package"){
|
|
|
|
node = new ProjectNode(NodeType::GROUP, xnode.attribute("name"));
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
node = new ProjectNode(NodeType::FILE, xnode.attribute("name"));
|
|
|
|
node->setFile(xnode.attribute("path"));
|
|
|
|
}
|
|
|
|
|
|
|
|
pnode->appendRow(node);
|
|
|
|
|
|
|
|
structure_parser(xnode, node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void XMLProjectManager::structure_severlize(ProjectNode *pnode, QDomElement &elm)
|
|
|
|
{
|
|
|
|
auto doc = elm.ownerDocument();
|
|
|
|
for(auto idx=0; idx<pnode->rowCount(); ++idx){
|
|
|
|
auto item = static_cast<ProjectNode*>(pnode->child(idx));
|
|
|
|
QDomElement e = doc.createElement("file");
|
|
|
|
if(item->nodeType() == NodeType::GROUP)
|
|
|
|
e.setTagName("package");
|
|
|
|
|
|
|
|
e.setAttribute("name", item->text());
|
|
|
|
e.setAttribute("path", item->file());
|
|
|
|
elm.appendChild(e);
|
|
|
|
|
|
|
|
structure_severlize(item, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int XMLProjectManager::createFile(const QList<QString> &path, const QString &name, const QString &suffix)
|
|
|
|
{
|
|
|
|
auto root = QFileInfo(file_path).dir();
|
|
|
|
QRandomGenerator xgen(QDateTime::currentDateTime().offsetFromUtc());
|
|
|
|
|
|
|
|
QString filename = "";
|
|
|
|
do{
|
|
|
|
QString number = QString("%1").arg(xgen.generate());
|
|
|
|
filename = QString("contentfile_%1.%2").arg(number, suffix);
|
|
|
|
}while(QFileInfo::exists(root.absoluteFilePath(filename)));
|
|
|
|
QFile tfile(root.absoluteFilePath(filename));
|
|
|
|
if(!tfile.open(QIODevice::Text|QIODevice::WriteOnly))
|
|
|
|
return -3;
|
|
|
|
tfile.close();
|
|
|
|
|
|
|
|
auto pnode = static_cast<ProjectNode*>(mode_holder->item(0));
|
|
|
|
auto group = node_follows(pnode, path);
|
|
|
|
if(group == nullptr)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if(group->nodeType() == NodeType::FILE)
|
|
|
|
return -2;
|
|
|
|
|
|
|
|
auto filenode = new ProjectNode(NodeType::FILE, name);
|
|
|
|
filenode->setFile(filename);
|
|
|
|
group->appendRow(filenode);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool XMLProjectManager::deletePath(const QList<QString> &path)
|
|
|
|
{
|
|
|
|
auto root_node = static_cast<ProjectNode*>(mode_holder->item(0));
|
|
|
|
auto xnode = node_follows(root_node, path);
|
|
|
|
if(xnode == nullptr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
xnode->parent()->removeRow(xnode->row());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-11-22 06:15:36 +00:00
|
|
|
QList<std::tuple<QFileInfo, QString> > XMLProjectManager::filesWithEnds(const QString &suffix) const
|
2022-11-17 08:26:05 +00:00
|
|
|
{
|
|
|
|
auto root_project = mode_holder->item(0);
|
|
|
|
return nodes_search(static_cast<ProjectNode*>(root_project), suffix);
|
|
|
|
}
|
|
|
|
|
|
|
|
QStandardItem *XMLProjectManager::newPath(const QList<QString> &path)
|
|
|
|
{
|
|
|
|
auto pnode = mode_holder->item(0);
|
|
|
|
return groups_rebuild(static_cast<ProjectNode*>(pnode), path);
|
|
|
|
}
|
|
|
|
|
|
|
|
QFileInfo XMLProjectManager::queryWith(const QList<QString> &path)
|
|
|
|
{
|
|
|
|
auto root = mode_holder->item(0);
|
|
|
|
|
|
|
|
auto item = node_follows(static_cast<ProjectNode*>(root), path);
|
|
|
|
if(item == nullptr || item->nodeType() == NodeType::GROUP)
|
|
|
|
return QFileInfo();
|
|
|
|
|
|
|
|
return QFileInfo(QFileInfo(file_path).dir().filePath(item->file()));
|
|
|
|
}
|
|
|
|
|
|
|
|
ProjectNode *XMLProjectManager::node_follows(ProjectNode *pnode, const QList<QString> &path_remains)
|
|
|
|
{
|
|
|
|
if(path_remains.size()==0)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
for(auto idx=0; idx<pnode->rowCount(); ++idx){
|
|
|
|
auto node = static_cast<ProjectNode*>(pnode->child(idx));
|
|
|
|
if(node->text() == path_remains[0]){
|
|
|
|
if(path_remains.size() == 1)
|
|
|
|
return node;
|
|
|
|
else
|
|
|
|
return node_follows(node, path_remains.mid(1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2022-11-22 06:15:36 +00:00
|
|
|
QList<std::tuple<QFileInfo, QString> > XMLProjectManager::nodes_search(ProjectNode *pnode, const QString &suffix) const
|
2022-11-17 08:26:05 +00:00
|
|
|
{
|
|
|
|
auto root_dir = QFileInfo(file_path).dir();
|
2022-11-22 06:15:36 +00:00
|
|
|
QList<std::tuple<QFileInfo, QString>> infos_return;
|
2022-11-17 08:26:05 +00:00
|
|
|
|
|
|
|
for(auto idx=0; idx<pnode->rowCount(); ++idx){
|
|
|
|
auto item = static_cast<ProjectNode*>(pnode->child(idx));
|
|
|
|
|
|
|
|
if(item->nodeType() == NodeType::FILE){
|
|
|
|
auto file_path = root_dir.filePath(item->file());
|
|
|
|
QFileInfo xinfo(file_path);
|
|
|
|
if(xinfo.suffix() == suffix)
|
2022-11-22 06:15:36 +00:00
|
|
|
infos_return << std::make_tuple(xinfo, item->text());
|
2022-11-17 08:26:05 +00:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
auto elist = nodes_search(item, suffix);
|
|
|
|
infos_return.append(elist);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return infos_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ProjectNode* XMLProjectManager::groups_rebuild(ProjectNode *pnode, const QList<QString> &path_remains)
|
|
|
|
{
|
|
|
|
// 查找对匹配结果
|
|
|
|
for(auto idx=0; idx<pnode->rowCount(); ++idx){
|
|
|
|
auto item = static_cast<ProjectNode*>(pnode->child(idx));
|
|
|
|
if(item->text() == path_remains[0] && item->nodeType() == NodeType::GROUP){
|
|
|
|
if(path_remains.size() > 1)
|
|
|
|
return groups_rebuild(item, path_remains.mid(1));
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto item = new ProjectNode(NodeType::GROUP, path_remains[0]);
|
|
|
|
pnode->appendRow(item);
|
|
|
|
|
|
|
|
if(path_remains.size() > 1)
|
|
|
|
return groups_rebuild(item, path_remains.mid(1));
|
|
|
|
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 完成线 =======================================================================================================
|
|
|
|
|
|
|
|
|
|
|
|
bool XMLProjectManager::moveTo(const QList<QString> &item_path, const QList<QString> &target_group, int index)
|
|
|
|
{
|
|
|
|
auto root = mode_holder->item(0);
|
|
|
|
auto file = node_follows(static_cast<ProjectNode*>(root), item_path);
|
|
|
|
|
|
|
|
if(file == nullptr || file->nodeType() == NodeType::GROUP)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
auto group = node_follows(static_cast<ProjectNode*>(root), target_group);
|
|
|
|
if(group->rowCount() <= index)
|
|
|
|
group->insertRow(index, file);
|
|
|
|
else
|
|
|
|
group->appendRow(file);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ProjectNode::ProjectNode(NodeType t, const QString &name)
|
|
|
|
: QStandardItem(name),type_indi(t)
|
|
|
|
{
|
|
|
|
if(t == NodeType::FILE)
|
|
|
|
{
|
|
|
|
setIcon(QIcon(":/icons/文件.png"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setIcon(QIcon(":/icons/集合.png"));
|
|
|
|
}
|
|
|
|
|
|
|
|
setEditable(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
NodeType ProjectNode::nodeType() const
|
|
|
|
{return type_indi;}
|
|
|
|
|
|
|
|
void ProjectNode::setFile(const QString &name)
|
|
|
|
{
|
|
|
|
this->filename = name;
|
|
|
|
|
|
|
|
if(name.endsWith("storychain"))
|
|
|
|
setIcon(QIcon(":/icons/脉络.png"));
|
|
|
|
if(name.endsWith("storyunit"))
|
|
|
|
setIcon(QIcon(":/icons/单元.png"));
|
|
|
|
if(name.endsWith("storyboard"))
|
|
|
|
setIcon(QIcon(":/icons/故事.png"));
|
|
|
|
if(name.endsWith("storyvolume"))
|
|
|
|
setIcon(QIcon(":/icons/叙述.png"));
|
|
|
|
if(name.endsWith("txt"))
|
|
|
|
setIcon(QIcon(":/icons/文件.png"));
|
2022-11-25 07:30:33 +00:00
|
|
|
if(name.endsWith("storyconcept"))
|
|
|
|
setIcon(QIcon(":/icons/概念.png"));
|
2022-11-17 08:26:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
QString ProjectNode::file() const
|
|
|
|
{return filename;}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|