correct metainformation export + test

This commit is contained in:
Alexey Fedoseev
2024-04-14 18:57:00 +03:00
parent 99bf4912cd
commit c02e24d16a
5 changed files with 300 additions and 67 deletions

View File

@@ -34,6 +34,8 @@ namespace Cyberiada {
static const String STANDARD_VERSION = "1.0"; static const String STANDARD_VERSION = "1.0";
static const String DEFAULT_GRAPHML_FORMAT = "Cyberiada-GraphML-1.0"; static const String DEFAULT_GRAPHML_FORMAT = "Cyberiada-GraphML-1.0";
static const String META_NODE_NAME = "CGML_META";
static const String META_NODE_ID = "nMeta";
const String VERTEX_ID_PREFIX = "n"; const String VERTEX_ID_PREFIX = "n";
const String SM_ID_PREFIX = "G"; const String SM_ID_PREFIX = "G";
const String TRANTISION_ID_SEP = "-"; const String TRANTISION_ID_SEP = "-";
@@ -372,8 +374,8 @@ Comment::Comment(Element* _parent, const ID& _id, const String& _body, bool _hum
update_comment_type(); update_comment_type();
} }
Comment::Comment(Element* _parent, const ID& _id, const String& _body, bool _human_readable, Comment::Comment(Element* _parent, const ID& _id, const String& _body, const Name& _name, bool _human_readable,
const Name& _name, const String& _markup, const Rect& rect, const Color& _color): const String& _markup, const Rect& rect, const Color& _color):
Element(_parent, elementComment, _id, _name), body(_body), markup(_markup), Element(_parent, elementComment, _id, _name), body(_body), markup(_markup),
human_readable(_human_readable), geometry_rect(rect), color(_color) human_readable(_human_readable), geometry_rect(rect), color(_color)
{ {
@@ -674,6 +676,13 @@ void ElementCollection::add_element(Element* e)
children.push_back(e); children.push_back(e);
} }
void ElementCollection::add_first_element(Element* e)
{
CYB_ASSERT(e);
CYB_ASSERT(e->get_parent() == this);
children.push_front(e);
}
void ElementCollection::remove_element(const ID& _id) void ElementCollection::remove_element(const ID& _id)
{ {
for (ElementList::iterator i = children.begin(); i != children.end(); i++) { for (ElementList::iterator i = children.begin(); i != children.end(); i++) {
@@ -725,6 +734,26 @@ std::list<Vertex*> ElementCollection::get_vertexes()
return result; return result;
} }
const Element* ElementCollection::first_element() const
{
if (has_children()) {
const Element* element = *(children.begin());
return element;
} else {
return NULL;
}
}
Element* ElementCollection::first_element()
{
if (has_children()) {
Element* element = *(children.begin());
return element;
} else {
return NULL;
}
}
CyberiadaNode* ElementCollection::to_node() const CyberiadaNode* ElementCollection::to_node() const
{ {
CyberiadaNode* node = Element::to_node(); CyberiadaNode* node = Element::to_node();
@@ -1137,7 +1166,8 @@ std::ostream& StateMachine::dump(std::ostream& os) const
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
Document::Document(): Document::Document():
ElementCollection(NULL, elementRoot, "", ""), ElementCollection(NULL, elementRoot, "", ""),
format(DEFAULT_GRAPHML_FORMAT) format(DEFAULT_GRAPHML_FORMAT),
metainfo_element(NULL)
{ {
reset(); reset();
} }
@@ -1149,6 +1179,7 @@ void Document::reset()
metainfo.transition_order_flag = false; metainfo.transition_order_flag = false;
metainfo.event_propagation_flag = false; metainfo.event_propagation_flag = false;
format = DEFAULT_GRAPHML_FORMAT; format = DEFAULT_GRAPHML_FORMAT;
metainfo_element = NULL;
clear(); clear();
} }
@@ -1156,6 +1187,7 @@ StateMachine* Document::new_state_machine(const String& sm_name, const Rect& r)
{ {
StateMachine* sm = new StateMachine(this, generate_sm_id(), sm_name, r); StateMachine* sm = new StateMachine(this, generate_sm_id(), sm_name, r);
add_element(sm); add_element(sm);
update_metainfo_element();
return sm; return sm;
} }
@@ -1163,6 +1195,7 @@ StateMachine* Document::new_state_machine(const ID& _id, const String& sm_name,
{ {
StateMachine* sm = new StateMachine(this, _id, sm_name, r); StateMachine* sm = new StateMachine(this, _id, sm_name, r);
add_element(sm); add_element(sm);
update_metainfo_element();
return sm; return sm;
} }
@@ -1249,8 +1282,13 @@ void Document::import_nodes_recursively(ElementCollection* collection, Cyberiada
} }
if (n->title) { if (n->title) {
element = new Comment(collection, n->id, comment_body, n->type == cybNodeComment, Comment* comment = new Comment(collection, n->id, comment_body, n->title,
n->title, comment_markup, rect, _color); n->type == cybNodeComment, comment_markup, rect, _color);
element = comment;
if (n->type == cybNodeFormalComment && String(n->title) == META_NODE_NAME) {
CYB_ASSERT(!metainfo_element);
metainfo_element = comment;
}
} else { } else {
element = new Comment(collection, n->id, comment_body, n->type == cybNodeComment, element = new Comment(collection, n->id, comment_body, n->type == cybNodeComment,
comment_markup, rect, _color); comment_markup, rect, _color);
@@ -1386,6 +1424,7 @@ void Document::set_name(const Name& _name)
{ {
Element::set_name(_name); Element::set_name(_name);
metainfo.name = _name; metainfo.name = _name;
update_metainfo_element();
} }
void Document::load(const String& path, DocumentFormat f) void Document::load(const String& path, DocumentFormat f)
@@ -1476,6 +1515,44 @@ void Document::load(const String& path, DocumentFormat f)
cyberiada_cleanup_sm_document(&doc); cyberiada_cleanup_sm_document(&doc);
} }
void Document::update_metainfo_element()
{
std::list<StateMachine*> sms = get_state_machines();
if (sms.size() == 0) {
return ;
}
String new_meta_comment;
CyberiadaMetainformation* meta = export_meta();
char* buffer = NULL;
cyberiada_encode_meta(meta, &buffer, NULL);
if (buffer) {
new_meta_comment = buffer;
free(buffer);
}
cyberiada_destroy_meta(meta);
if (metainfo_element) {
metainfo_element->set_body(new_meta_comment);
} else {
StateMachine* sm = *(sms.begin()); // first SM
if (sm->has_children()) {
Element* first = sm->first_element();
if (first->get_type() == elementFormalComment &&
first->has_name() &&
first->get_name() == META_NODE_NAME) {
metainfo_element = static_cast<Comment*>(first);
CYB_ASSERT(metainfo_element);
metainfo_element->set_body(new_meta_comment);
return ;
}
}
// Comment* comment = new Comment(sm, META_NODE_ID, new_meta_comment, META_NODE_NAME, false);
// sm->add_first_element(comment);
// metainfo_element = comment;
}
}
void Document::export_edges(CyberiadaEdge** edges, const StateMachine* sm) const void Document::export_edges(CyberiadaEdge** edges, const StateMachine* sm) const
{ {
CyberiadaEdge* edge; CyberiadaEdge* edge;
@@ -1505,6 +1582,72 @@ void Document::export_edges(CyberiadaEdge** edges, const StateMachine* sm) const
} }
} }
CyberiadaMetainformation* Document::export_meta() const
{
CyberiadaMetainformation* meta_info = cyberiada_new_meta();
CYB_ASSERT(metainfo.standard_version == String(meta_info->standard_version));
if (!metainfo.platform_name.empty()) {
cyberiada_copy_string(&(meta_info->platform_name),
&(meta_info->platform_name_len),
metainfo.platform_name.c_str());
}
if (!metainfo.platform_version.empty()) {
cyberiada_copy_string(&(meta_info->platform_version),
&(meta_info->platform_version_len),
metainfo.platform_version.c_str());
}
if (!metainfo.platform_language.empty()) {
cyberiada_copy_string(&(meta_info->platform_language),
&(meta_info->platform_language_len),
metainfo.platform_language.c_str());
}
if (!metainfo.target_system.empty()) {
cyberiada_copy_string(&(meta_info->target_system),
&(meta_info->target_system_len),
metainfo.target_system.c_str());
}
if (!metainfo.name.empty()) {
cyberiada_copy_string(&(meta_info->name),
&(meta_info->name_len),
metainfo.name.c_str());
}
if (!metainfo.author.empty()) {
cyberiada_copy_string(&(meta_info->author),
&(meta_info->author_len),
metainfo.author.c_str());
}
if (!metainfo.contact.empty()) {
cyberiada_copy_string(&(meta_info->contact),
&(meta_info->contact_len),
metainfo.contact.c_str());
}
if (!metainfo.description.empty()) {
cyberiada_copy_string(&(meta_info->description),
&(meta_info->description_len),
metainfo.description.c_str());
}
if (!metainfo.version.empty()) {
cyberiada_copy_string(&(meta_info->version),
&(meta_info->version_len),
metainfo.version.c_str());
}
if (!metainfo.date.empty()) {
cyberiada_copy_string(&(meta_info->date),
&(meta_info->date_len),
metainfo.date.c_str());
}
if (!metainfo.markup_language.empty()) {
cyberiada_copy_string(&(meta_info->markup_language),
&(meta_info->markup_language_len),
metainfo.markup_language.c_str());
}
meta_info->transition_order_flag = metainfo.transition_order_flag ? 2: 1;
meta_info->event_propagation_flag = metainfo.event_propagation_flag ? 2: 1;
return meta_info;
}
void Document::save(const String& path, DocumentFormat f) const void Document::save(const String& path, DocumentFormat f) const
{ {
CyberiadaDocument doc; CyberiadaDocument doc;
@@ -1532,67 +1675,7 @@ void Document::save(const String& path, DocumentFormat f) const
DEFAULT_GRAPHML_FORMAT.c_str()); DEFAULT_GRAPHML_FORMAT.c_str());
} }
doc.meta_info = cyberiada_new_meta(); doc.meta_info = export_meta();
CYB_ASSERT(metainfo.standard_version == String(doc.meta_info->standard_version));
if (!metainfo.platform_name.empty()) {
cyberiada_copy_string(&(doc.meta_info->platform_name),
&(doc.meta_info->platform_name_len),
metainfo.platform_name.c_str());
}
if (!metainfo.platform_version.empty()) {
cyberiada_copy_string(&(doc.meta_info->platform_version),
&(doc.meta_info->platform_version_len),
metainfo.platform_version.c_str());
}
if (!metainfo.platform_language.empty()) {
cyberiada_copy_string(&(doc.meta_info->platform_language),
&(doc.meta_info->platform_language_len),
metainfo.platform_language.c_str());
}
if (!metainfo.target_system.empty()) {
cyberiada_copy_string(&(doc.meta_info->target_system),
&(doc.meta_info->target_system_len),
metainfo.target_system.c_str());
}
if (!metainfo.name.empty()) {
cyberiada_copy_string(&(doc.meta_info->name),
&(doc.meta_info->name_len),
metainfo.name.c_str());
}
if (!metainfo.author.empty()) {
cyberiada_copy_string(&(doc.meta_info->author),
&(doc.meta_info->author_len),
metainfo.author.c_str());
}
if (!metainfo.contact.empty()) {
cyberiada_copy_string(&(doc.meta_info->contact),
&(doc.meta_info->contact_len),
metainfo.contact.c_str());
}
if (!metainfo.description.empty()) {
cyberiada_copy_string(&(doc.meta_info->description),
&(doc.meta_info->description_len),
metainfo.description.c_str());
}
if (!metainfo.version.empty()) {
cyberiada_copy_string(&(doc.meta_info->version),
&(doc.meta_info->version_len),
metainfo.version.c_str());
}
if (!metainfo.date.empty()) {
cyberiada_copy_string(&(doc.meta_info->date),
&(doc.meta_info->date_len),
metainfo.date.c_str());
}
if (!metainfo.markup_language.empty()) {
cyberiada_copy_string(&(doc.meta_info->markup_language),
&(doc.meta_info->markup_language_len),
metainfo.markup_language.c_str());
}
doc.meta_info->transition_order_flag = metainfo.transition_order_flag ? 2: 1;
doc.meta_info->event_propagation_flag = metainfo.event_propagation_flag ? 2: 1;
for (std::list<const StateMachine*>::const_iterator i = state_machines.begin(); i != state_machines.end(); i++) { for (std::list<const StateMachine*>::const_iterator i = state_machines.begin(); i != state_machines.end(); i++) {
const StateMachine* orig_sm = *i; const StateMachine* orig_sm = *i;

View File

@@ -193,12 +193,15 @@ namespace Cyberiada {
public: public:
Comment(Element* parent, const ID& id, const String& body, bool human_readable = true, Comment(Element* parent, const ID& id, const String& body, bool human_readable = true,
const String& markup = String(), const Rect& rect = Rect(), const Color& color = Color()); const String& markup = String(), const Rect& rect = Rect(), const Color& color = Color());
Comment(Element* parent, const ID& id, const String& body, bool human_readable, const Name& name, Comment(Element* parent, const ID& id, const String& body, const Name& name, bool human_readable,
const String& markup = String(), const Rect& rect = Rect(), const Color& color = Color()); const String& markup = String(), const Rect& rect = Rect(), const Color& color = Color());
bool is_human_readable() const { return human_readable; } bool is_human_readable() const { return human_readable; }
bool is_machine_readable() const { return !human_readable; } bool is_machine_readable() const { return !human_readable; }
bool has_body() const { return !body.empty(); }
void set_body(const String& b) { body = b; }
bool has_subjects() const { return !subjects.empty(); } bool has_subjects() const { return !subjects.empty(); }
const std::list<CommentSubject>& get_subjects() const { return subjects; } const std::list<CommentSubject>& get_subjects() const { return subjects; }
void add_subject(const CommentSubject& s); void add_subject(const CommentSubject& s);
@@ -274,6 +277,8 @@ namespace Cyberiada {
virtual bool has_children() const { return !children.empty(); } virtual bool has_children() const { return !children.empty(); }
virtual size_t children_count() const { return children.size(); } virtual size_t children_count() const { return children.size(); }
virtual size_t elements_count() const; virtual size_t elements_count() const;
const Element* first_element() const;
Element* first_element();
const Element* find_element_by_id(const ID& id) const; const Element* find_element_by_id(const ID& id) const;
Element* find_element_by_id(const ID& id); Element* find_element_by_id(const ID& id);
ConstElementList find_elements_by_type(ElementType type) const; ConstElementList find_elements_by_type(ElementType type) const;
@@ -282,6 +287,7 @@ namespace Cyberiada {
ElementList find_elements_by_types(const ElementTypes& types); ElementList find_elements_by_types(const ElementTypes& types);
virtual void add_element(Element* e); virtual void add_element(Element* e);
virtual void add_first_element(Element* e);
virtual void remove_element(const ID& id); virtual void remove_element(const ID& id);
void clear(); void clear();
@@ -549,15 +555,18 @@ namespace Cyberiada {
private: private:
void check_cyberiada_error(int res, const String& msg = "") const; void check_cyberiada_error(int res, const String& msg = "") const;
void update_metainfo_element();
ID generate_sm_id() const; ID generate_sm_id() const;
ID generate_vertex_id(const Element* element) const; ID generate_vertex_id(const Element* element) const;
ID generate_transition_id(const String& source_id, const String& target_id) const; ID generate_transition_id(const String& source_id, const String& target_id) const;
void import_nodes_recursively(ElementCollection* collection, CyberiadaNode* nodes); void import_nodes_recursively(ElementCollection* collection, CyberiadaNode* nodes);
void import_edges(ElementCollection* collection, CyberiadaEdge* edges); void import_edges(ElementCollection* collection, CyberiadaEdge* edges);
void export_edges(CyberiadaEdge** edges, const StateMachine* sm) const; void export_edges(CyberiadaEdge** edges, const StateMachine* sm) const;
CyberiadaMetainformation* export_meta() const;
String format; String format;
DocumentMetainformation metainfo; DocumentMetainformation metainfo;
Comment* metainfo_element;
}; };
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -0,0 +1,46 @@
/* -----------------------------------------------------------------------------
* The Cyberiada GraphML C++ library implemention
*
* The test
*
* Copyright (C) 2024 Alexey Fedoseev <aleksey@fedoseev.net>
*
* 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 https://www.gnu.org/licenses/
* ----------------------------------------------------------------------------- */
#include <iostream>
#include "cyberiadamlpp.h"
using namespace Cyberiada;
using namespace std;
#define CYB_ASSERT(q) if (!(q)) { \
throw AssertException(std::string(__FILE__) + ":" + std::to_string(__LINE__)); \
}
int main(int argc, char** argv)
{
Document d;
try {
d.load(string(argv[0]) + "-input.graphml", formatCyberiada10);
CYB_ASSERT(d.meta().name == "Test document");
d.set_name("Test document 2");
CYB_ASSERT(d.meta().name == "Test document 2");
cout << d << endl;
} catch (const Cyberiada::Exception& e) {
cerr << e.str() << endl;
return 1;
}
return 0;
}

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns">
<data key="gFormat">Cyberiada-GraphML-1.0</data>
<key id="gFormat" for="graphml" attr.name="format" attr.type="string"/>
<key id="dName" for="graph" attr.name="name" attr.type="string"/>
<key id="dName" for="node" attr.name="name" attr.type="string"/>
<key id="dStateMachine" for="graph" attr.name="stateMachine" attr.type="string"/>
<key id="dSubmachineState" for="node" attr.name="submachineState" attr.type="string"/>
<key id="dGeometry" for="graph" attr.name="geometry"/>
<key id="dGeometry" for="node" attr.name="geometry"/>
<key id="dGeometry" for="edge" attr.name="geometry"/>
<key id="dSourcePoint" for="edge" attr.name="sourcePoint"/>
<key id="dTargetPoint" for="edge" attr.name="targetPoint"/>
<key id="dLabelGeometry" for="edge" attr.name="labelGeometry"/>
<key id="dNote" for="node" attr.name="note" attr.type="string"/>
<key id="dVertex" for="node" attr.name="vertex" attr.type="string"/>
<key id="dData" for="node" attr.name="data" attr.type="string"/>
<key id="dData" for="edge" attr.name="data" attr.type="string"/>
<key id="dMarkup" for="node" attr.name="markup" attr.type="string"/>
<key id="dColor" for="node" attr.name="color" attr.type="string"/>
<key id="dColor" for="edge" attr.name="color" attr.type="string"/>
<key id="dPivot" for="edge" attr.name="pivot" attr.type="string"/>
<key id="dChunk" for="edge" attr.name="chunk" attr.type="string"/>
<graph id="G0" edgedefault="directed">
<data key="dName">SM</data>
<node id="nMeta">
<data key="dNote">formal</data>
<data key="dName">CGML_META</data>
<data key="dData">standardVersion/ 1.0
platform/ Berloga
platformVersion/ 1.4
platformLanguage/ script
target/ Unit
name/ Test document
author/ Author
contact/ platform@kruzhok.org
description/ 1
2
3
version/ 0.1
date/ 2024-04-14 11:22
markupLanguage/ html
transitionOrder/ exitFirst
eventPropagation/ propagate
</data>
</node>
</graph>
</graphml>

33
tests/05-output.txt Normal file
View File

@@ -0,0 +1,33 @@
Document [Cyberiada-GraphML-1.0] {Element type: doc, id: '', name: 'Test document 2', meta: {standard version: '1.0', platform name: 'Berloga', platform version: '1.4', platform language: 'script', target system: 'Unit', name: 'Test document 2', author: 'Author', contact: 'platform@kruzhok.org', description: '1
2
3', version: '0.1', date: '2024-04-14 11:22', markup language: 'html', transition order: exit first, event propagation: propagate events}, elements: {State Machine {Element type: stm, id: 'G0', name: 'SM', elements: {Comment { formal, Element type: fco, id: 'nMeta', name: 'CGML_META', body: 'standardVersion/ 1.0
platform/ Berloga
platformVersion/ 1.4
platformLanguage/ script
target/ Unit
name/ Test document 2
author/ Author
contact/ platform@kruzhok.org
description/ 1
2
3
version/ 0.1
date/ 2024-04-14 11:22
markupLanguage/ html
transitionOrder/ exitFirst
eventPropagation/ propagate
'}}}}