# HG changeset patch # User Teemu Piippo # Date 1632765885 -10800 # Node ID 2f383e88acf462b1499b62710f6b7fe7c2bf1d95 # Parent 72098474d362fad9c760abe1c97e85c3eed46eeb work on saving diff -r 72098474d362 -r 2f383e88acf4 CMakeLists.txt --- a/CMakeLists.txt Wed Sep 22 14:03:43 2021 +0300 +++ b/CMakeLists.txt Mon Sep 27 21:04:45 2021 +0300 @@ -34,6 +34,7 @@ src/documentmanager.cpp src/edithistory.cpp src/geometry.cpp + src/header.cpp src/libraries.cpp src/invert.cpp src/main.cpp diff -r 72098474d362 -r 2f383e88acf4 src/documentmanager.cpp --- a/src/documentmanager.cpp Wed Sep 22 14:03:43 2021 +0300 +++ b/src/documentmanager.cpp Mon Sep 27 21:04:45 2021 +0300 @@ -89,7 +89,7 @@ QFile file{path}; const QString name = pathToName(path); file.open(QFile::ReadOnly | QFile::Text); - std::unique_ptr newModel = std::make_unique(); + std::unique_ptr newModel = std::make_unique(path); QTextStream textStream{&file}; Model::EditContext editor = newModel->edit(); Parser parser{file}; diff -r 72098474d362 -r 2f383e88acf4 src/header.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/header.cpp Mon Sep 27 21:04:45 2021 +0300 @@ -0,0 +1,85 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2020 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "header.h" + +const QString LDHeader::caLicenseString = "0 !LICENSE Redistributable under CCAL version 2.0"; +const QString LDHeader::nonCaLicenseString = "0 !LICENSE Not redistributable"; + +static const QMap typeStrings = { + {"Part", LDHeader::Part}, + {"Subpart", LDHeader::Subpart}, + {"Shortcut", LDHeader::Shortcut}, + {"Primitive", LDHeader::Primitive}, + {"8_Primitive", LDHeader::Primitive_8}, + {"48_Primitive", LDHeader::Primitive_48}, + {"Configuration", LDHeader::Configuration}, +}; + +QString headerTypeToString(const LDHeader::FileType fileType) +{ + QMapIterator it{::typeStrings}; + while (it.hasNext()) + { + it.next(); + if (it.value() == fileType) + { + return it.key(); + } + } + return "Part"; +} + +LDHeader::FileType headerTypeFromString(const QString& string) +{ + return ::typeStrings.value(string, LDHeader::Part); +} + +QString headerToString(const LDHeader& header) +{ + QString result; + result += "0 " + header.description + "\r\n"; + result += "Name: " + header.name + "\r\n"; + result += "Author: " + header.author + "\r\n"; + if (header.type != LDHeader::NoHeader) + { + result += "0 !LDRAW Unofficial_" + headerTypeToString(header.type) + "\r\n"; + } + switch (header.license) + { + case LDHeader::UnspecifiedLicense: + break; + case LDHeader::CaLicense: + result += LDHeader::caLicenseString + "\r\n"; + break; + case LDHeader::NonCaLicense: + result += LDHeader::nonCaLicenseString + "\r\n"; + break; + } + if (not header.help.isEmpty()) + { + result += "\r\n"; + for (const QString& helpLine : header.help.split("\n")) + { + result += "0 !HELP " + helpLine + "\r\n"; + } + } + result += "\r\n"; + // FIXME: continue + return result; +} diff -r 72098474d362 -r 2f383e88acf4 src/header.h --- a/src/header.h Wed Sep 22 14:03:43 2021 +0300 +++ b/src/header.h Mon Sep 27 21:04:45 2021 +0300 @@ -22,6 +22,8 @@ struct LDHeader { + static const QString caLicenseString; + static const QString nonCaLicenseString; struct HistoryEntry { QDate date; @@ -63,4 +65,8 @@ static decltype(license) defaultLicense(); }; +LDHeader::FileType headerTypeFromString(const QString& string); +QString headerTypeToString(const LDHeader::FileType fileType); +QString headerToString(const LDHeader& header); + Q_DECLARE_OPERATORS_FOR_FLAGS(QFlags) diff -r 72098474d362 -r 2f383e88acf4 src/linetypes/subfilereference.cpp --- a/src/linetypes/subfilereference.cpp Wed Sep 22 14:03:43 2021 +0300 +++ b/src/linetypes/subfilereference.cpp Mon Sep 27 21:04:45 2021 +0300 @@ -36,7 +36,13 @@ QString ldraw::SubfileReference::textRepresentation() const { - return referenceName + " " + utility::vertexToStringParens(this->position()); + QString out; + if (this->isInverted) + { + out += "0 BFC INVERTNEXT\r\n"; + } + out += referenceName + " " + utility::vertexToStringParens(this->position()); + return out; } void ldraw::SubfileReference::getPolygons diff -r 72098474d362 -r 2f383e88acf4 src/model.cpp --- a/src/model.cpp Wed Sep 22 14:03:43 2021 +0300 +++ b/src/model.cpp Mon Sep 27 21:04:45 2021 +0300 @@ -17,6 +17,7 @@ */ #include +#include #include #include "model.h" #include "modeleditcontext.h" @@ -25,8 +26,17 @@ * @brief Constructs a model * @param parent QObject parent to pass forward */ -Model::Model(QObject* parent) : - QAbstractListModel{parent} +Model::Model(QObject* parent) : + Model{"", parent} {} + +/** + * @brief Constructs a model + * @param path Path that was used to open the model + * @param parent QObject parent to pass forward + */ +Model::Model(const QString& path, QObject *parent) : + QAbstractListModel{parent}, + path{path} { connect(this, &Model::dataChanged, [&](){ this->needRecache = true; }); } @@ -256,3 +266,20 @@ { return this->body[unsigned_cast(index.row())].get(); } + +/** + * @brief Write out the model as text + */ +void Model::save() const +{ + QFile file{this->path}; + if (file.open(QIODevice::WriteOnly)) + { + QTextStream out{&file}; + for (const ModelObjectPointer& object : this->body) + { + out << object.get()->textRepresentation() << "\r\n"; + } + file.close(); + } +} \ No newline at end of file diff -r 72098474d362 -r 2f383e88acf4 src/model.h --- a/src/model.h Wed Sep 22 14:03:43 2021 +0300 +++ b/src/model.h Mon Sep 27 21:04:45 2021 +0300 @@ -34,6 +34,7 @@ Q_OBJECT public: class EditContext; + Model(const QString& path, QObject* parent = nullptr); Model(QObject* parent = nullptr); Model(const Model&) = delete; int size() const; @@ -61,6 +62,7 @@ Get2Result get2(ldraw::Id id) const; template void apply(Fn f) const; + void save() const; Q_SIGNALS: void objectAdded(ldraw::id_t id, int position); void objectModified(ldraw::id_t id, int position); diff -r 72098474d362 -r 2f383e88acf4 src/parser.cpp --- a/src/parser.cpp Wed Sep 22 14:03:43 2021 +0300 +++ b/src/parser.cpp Mon Sep 27 21:04:45 2021 +0300 @@ -48,16 +48,6 @@ return QString::fromUtf8(this->device.readLine()).trimmed(); } -static const QMap typeStrings { - {"Part", LDHeader::Part}, - {"Subpart", LDHeader::Subpart}, - {"Shortcut", LDHeader::Shortcut}, - {"Primitive", LDHeader::Primitive}, - {"8_Primitive", LDHeader::Primitive_8}, - {"48_Primitive", LDHeader::Primitive_48}, - {"Configuration", LDHeader::Configuration}, -}; - /* * Parses a single line of the header. * Possible parse results: @@ -91,7 +81,7 @@ // consideration. if (partTypeString.startsWith("Unofficial_")) partTypeString = partTypeString.mid(strlen("Unofficial_")); - header.type = typeStrings.value(partTypeString, LDHeader::Part); + header.type = headerTypeFromString(partTypeString); header.qualfiers = {}; if (tokens.contains("Alias")) header.qualfiers |= LDHeader::Alias; @@ -183,12 +173,12 @@ header.cmdline = line.mid(strlen("0 !CMDLINE ")); return ParseSuccess; } - else if (line.startsWith("0 !LICENSE Redistributable under CCAL version 2.0")) + else if (line.startsWith(LDHeader::caLicenseString)) { header.license = LDHeader::CaLicense; return ParseSuccess; } - else if (line.startsWith("0 !LICENSE Not redistributable")) + else if (line.startsWith(LDHeader::nonCaLicenseString)) { header.license = LDHeader::NonCaLicense; return ParseSuccess;