#include "xmlprojectmanager.h" #include #include #include #include #include #include #include using namespace Project; using namespace Config; class Impl_ProjectException : public ProjectException { public: Impl_ProjectException(const QString& title, const QString& reason) : reason_store(reason), title_store(title) {} private: QString reason_store; QString title_store; // exception interface public: virtual const char *what() const override{return reason_store.toLocal8Bit();} // ParseException interface public: virtual QString reason() const override{ return reason_store;} virtual QString title() const override{return title_store;} }; XMLProjectManager::XMLProjectManager(QObject *parent) : QObject(parent), project_config(new XMLConfig(this)), project_structure(new QStandardItemModel(this)), open_status(false){ } XMLProjectManager::~XMLProjectManager(){ delete project_config; } bool XMLProjectManager::isOpen() const { return open_status; } /* * * * * * * * */ void XMLProjectManager::openProject(const QString &project_file) { filepath_store = project_file; QFileInfo info(project_file); if(!info.exists()) throw new Impl_ProjectException("打开失败", "指定的项目文件不存在:"+project_file); // 获取项目文件内容 QFile project_in(project_file); if(!project_in.open(QIODevice::ReadOnly|QIODevice::Text)) throw new Impl_ProjectException("打开失败", "指定的项目文件无法打开:" + project_file); // 载入文件内容 QDomDocument doc; QString err; int row, col; if(!doc.setContent(&project_in, false, &err, &row, &col)) throw new Impl_ProjectException("打开失败", QString("项目文件格式错误:%1,row:%2,col:%3").arg(err).arg(row).arg(col)); // 构建项目组织树 auto root_elm = doc.documentElement(); auto name = root_elm.attribute("name"); auto pnode = new ProjectNode(NodeType::GROUP, name); pnode->setFile(root_elm.attribute("config")); project_structure->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")); } void XMLProjectManager::newProject(const QString &project_dir, const QString &name) { // 确定目标项目文件 QDir root(project_dir); QDir::setCurrent(root.path()); auto project_file = root.filePath(name + ".nsf"); filepath_store = project_file; QFileInfo info(project_file); if(info.exists()) throw new Impl_ProjectException("新建错误", "指定路径的项目文件已经存在,无法构建新项目"); // 构建项目表示树 auto project_node = new ProjectNode(NodeType::GROUP, name); project_node->setFile(".project_config.xml"); project_structure->appendRow(project_node); project_config->loadFile(root.filePath(project_node->file())); // 写出到磁盘 save(); open_status = true; project_node->setIcon(QIcon(":/icons/toplevel.png")); } void XMLProjectManager::closeProject() { open_status = false; project_structure->clear(); } void XMLProjectManager::save() { project_config->save(); QDomDocument doc; auto pnode = static_cast(project_structure->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(filepath_store); if(!records.open(QIODevice::WriteOnly|QIODevice::Text)) throw new Impl_ProjectException("保存错误", "保存过程中,指定项目文件无法打开保存:" + filepath_store); QTextStream txout(&records); doc.save(txout, 4); txout.flush(); } QString XMLProjectManager::projectName() const { return project_structure->item(0)->text(); } Configration *XMLProjectManager::configraions() const { return this->project_config; } QStandardItemModel *XMLProjectManager::model() const { return project_structure; } void XMLProjectManager::structure_parser(QDomElement struct_elm, ProjectNode *pnode) { auto children = struct_elm.childNodes(); for(auto idx=0; idxsetFile(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; idxrowCount(); ++idx){ auto item = static_cast(pnode->child(idx)); QDomElement e = doc.createElement("package"); e.setAttribute("name", item->text()); if(item->nodeType() == NodeType::FILE){ e.setTagName("file"); e.setAttribute("path", item->file()); } elm.appendChild(e); structure_severlize(item, e); } } int XMLProjectManager::createFile(const QList &path, const QString &name, const QString &suffix) { auto pnode = static_cast(project_structure->item(0)); auto group = node_follows(pnode, path); if(group == nullptr) return -1; if(group->nodeType() == NodeType::FILE) return -2; for(auto idx=0; idxrowCount(); ++idx) if(group->child(idx)->text() == name) return -3; auto root = QFileInfo(filepath_store).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 filenode = new ProjectNode(NodeType::FILE, name); filenode->setFile(filename); group->appendRow(filenode); return 0; } bool XMLProjectManager::deletePath(const QList &path) { auto root_node = static_cast(project_structure->item(0)); auto xnode = node_follows(root_node, path); if(xnode == nullptr) return false; xnode->parent()->removeRow(xnode->row()); return true; } QList > XMLProjectManager::filesWithEnds(const QString &suffix) const { auto root_project = project_structure->item(0); return nodes_search(static_cast(root_project), suffix); } QStandardItem *XMLProjectManager::newPath(const QList &path) { auto pnode = project_structure->item(0); return groups_rebuild(static_cast(pnode), path); } QFileInfo XMLProjectManager::queryWith(const QList &path) { auto root = project_structure->item(0); auto item = node_follows(static_cast(root), path); if(item == nullptr || item->nodeType() == NodeType::GROUP) return QFileInfo(); return QFileInfo(QFileInfo(filepath_store).dir().filePath(item->file())); } ProjectNode *XMLProjectManager::node_follows(ProjectNode *pnode, const QList &path_remains) { if(path_remains.size()==0) return nullptr; for(auto idx=0; idxrowCount(); ++idx){ auto node = static_cast(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; } QList > XMLProjectManager::nodes_search(ProjectNode *pnode, const QString &suffix) const { auto root_dir = QFileInfo(filepath_store).dir(); QList> infos_return; for(auto idx=0; idxrowCount(); ++idx){ auto item = static_cast(pnode->child(idx)); if(item->nodeType() == NodeType::FILE){ auto file_path = root_dir.filePath(item->file()); QFileInfo xinfo(file_path); if(xinfo.suffix() == suffix) infos_return << std::make_tuple(xinfo, item->text()); } else{ auto elist = nodes_search(item, suffix); infos_return.append(elist); } } return infos_return; } ProjectNode* XMLProjectManager::groups_rebuild(ProjectNode *pnode, const QList &path_remains) { // 查找对匹配结果 for(auto idx=0; idxrowCount(); ++idx){ auto item = static_cast(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 &item_path, const QList &target_group, int index) { auto root = project_structure->item(0); auto file = node_follows(static_cast(root), item_path); if(file == nullptr || file->nodeType() == NodeType::GROUP) return false; auto group = node_follows(static_cast(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")); if(name.endsWith("storyconcept")) setIcon(QIcon(":/icons/概念.png")); } QString ProjectNode::file() const {return filename;}