save document to graphml implemented

This commit is contained in:
Alexey Fedoseev
2024-04-13 22:54:55 +03:00
parent aa6509b8f9
commit 8303a2de9b
5 changed files with 643 additions and 170 deletions

View File

@@ -9,7 +9,7 @@ endif
TEST_TARGET := cyberiadapp_test TEST_TARGET := cyberiadapp_test
LIB_SOURCES := cyberiadamlpp.cpp LIB_SOURCES := cyberiadamlpp.cpp
TEST_SOURCES := test.cpp TEST_SOURCES := main.cpp
LIB_OBJECTS := $(patsubst %.cpp, %.o, $(LIB_SOURCES)) LIB_OBJECTS := $(patsubst %.cpp, %.o, $(LIB_SOURCES))
TEST_OBJECTS := $(patsubst %.cpp, %.o, $(TEST_SOURCES)) TEST_OBJECTS := $(patsubst %.cpp, %.o, $(TEST_SOURCES))
@@ -41,8 +41,8 @@ $(TEST_TARGET): $(TEST_OBJECTS) $(LIB_TARGET) $(LIB_ORJECTS)
clean: clean:
rm -f *~ *.o $(TARGET) $(TEST_TARGET) $(LIB_TARGET_STATIC) $(LIB_TARGET_DYNAMIC) rm -f *~ *.o $(TARGET) $(TEST_TARGET) $(LIB_TARGET_STATIC) $(LIB_TARGET_DYNAMIC)
test: $(TEST_TARGET) main: $(TEST_TARGET)
all: $(LIB_TARGET) $(TEST_TARGET) all: $(LIB_TARGET) $(TEST_TARGET)
.PHONY: all clean test .PHONY: all clean main

View File

@@ -91,6 +91,31 @@ Element* Element::find_root()
} }
} }
#include <iostream>
CyberiadaNode* Element::to_node() const
{
CyberiadaNode* node = cyberiada_new_node(get_id().c_str());
switch (type) {
case elementSM: node->type = cybNodeSM; break;
case elementSimpleState: node->type = cybNodeSimpleState; break;
case elementCompositeState: node->type = cybNodeCompositeState; break;
case elementComment: node->type = cybNodeComment; break;
case elementFormalComment: node->type = cybNodeFormalComment; break;
case elementInitial: node->type = cybNodeInitial; break;
case elementFinal: node->type = cybNodeFinal; break;
case elementChoice: node->type = cybNodeChoice; break;
default:
std::cerr << id << " " << type << std::endl;
CYB_ASSERT(false);
}
if (has_name()) {
cyberiada_copy_string(&(node->title), &(node->title_len),
get_name().c_str());
}
return node;
}
std::ostream& Element::dump(std::ostream& os) const std::ostream& Element::dump(std::ostream& os) const
{ {
String type_str; String type_str;
@@ -136,6 +161,18 @@ Point::Point(CyberiadaPoint* p)
} }
} }
CyberiadaPoint* Point::c_point() const
{
if (valid) {
CyberiadaPoint* p = cyberiada_new_point();
p->x = x;
p->y = y;
return p;
} else {
return NULL;
}
}
Rect::Rect(CyberiadaRect* r) Rect::Rect(CyberiadaRect* r)
{ {
if (r) { if (r) {
@@ -149,6 +186,39 @@ Rect::Rect(CyberiadaRect* r)
} }
} }
CyberiadaRect* Rect::c_rect() const
{
if (valid) {
CyberiadaRect* r = cyberiada_new_rect();
r->x = x;
r->y = y;
r->width = width;
r->height = height;
return r;
} else {
return NULL;
}
}
CyberiadaPolyline* Cyberiada::c_polyline(const Polyline& polyline)
{
CyberiadaPolyline* result = NULL;
for (Polyline::const_iterator i = polyline.begin(); i != polyline.end(); i++) {
const Point& point = *i;
CyberiadaPolyline* pl = cyberiada_new_polyline();
pl->point.x = point.x;
pl->point.y = point.y;
if (result) {
CyberiadaPolyline* last_pl = result;
while (last_pl->next) last_pl = last_pl->next;
last_pl->next = pl;
} else {
result = pl;
}
}
return result;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Action // Action
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -165,17 +235,24 @@ Action::Action(const Event& _trigger, const Guard& _guard, const Behavior& _beha
std::ostream& Action::dump(std::ostream& os) const std::ostream& Action::dump(std::ostream& os) const
{ {
if (!trigger.empty()) { if (type != actionTransition) {
if (type == actionEntry) {
os << "entry";
} else {
CYB_ASSERT(type == actionExit);
os << "exit";
}
} else if (!trigger.empty()) {
os << "trigger: '" << trigger << "'"; os << "trigger: '" << trigger << "'";
} }
if (!guard.empty()) { if (!guard.empty()) {
if (!trigger.empty()) { if (type != actionTransition || !trigger.empty()) {
os << ", "; os << ", ";
} }
os << "guard: '" << guard << "'"; os << "guard: '" << guard << "'";
} }
if (!behavior.empty()) { if (!behavior.empty()) {
if (!trigger.empty() || !guard.empty()) { if (type != actionTransition || !trigger.empty() || !guard.empty()) {
os << ", "; os << ", ";
} }
os << "behavior: '" << behavior << "'"; os << "behavior: '" << behavior << "'";
@@ -224,20 +301,22 @@ std::ostream& Cyberiada::operator<<(std::ostream& os, const Polyline& pl)
// Comment // Comment
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
CommentSubject::CommentSubject(Element* _element, CommentSubject::CommentSubject(const ID& _id, Element* _element,
const Point& source, const Point& target, const Polyline& pl): const Point& source, const Point& target, const Polyline& pl):
type(commentSubjectElement), element(_element), has_frag(false), source_point(source), target_point(target), polyline(pl) type(commentSubjectElement), id(_id), element(_element), has_frag(false), source_point(source), target_point(target), polyline(pl)
{ {
} }
CommentSubject::CommentSubject(Element* _element, CommentSubjectType _type, const String& _fragment, CommentSubject::CommentSubject(const ID& _id, Element* _element, CommentSubjectType _type, const String& _fragment,
const Point& source, const Point& target, const Polyline& pl): const Point& source, const Point& target, const Polyline& pl):
type(_type), element(_element), has_frag(true), fragment(_fragment), source_point(source), target_point(target), polyline(pl) type(_type), id(_id), element(_element), has_frag(true), fragment(_fragment), source_point(source), target_point(target), polyline(pl)
{ {
} }
CommentSubject& CommentSubject::operator=(const CommentSubject& cs) CommentSubject& CommentSubject::operator=(const CommentSubject& cs)
{ {
type = cs.type;
id = cs.id;
element = cs.element; element = cs.element;
has_frag = cs.has_frag; has_frag = cs.has_frag;
fragment = cs.fragment; fragment = cs.fragment;
@@ -255,8 +334,6 @@ std::ostream& Cyberiada::operator<<(std::ostream& os, const CommentSubject& cs)
std::ostream& CommentSubject::dump(std::ostream& os) const std::ostream& CommentSubject::dump(std::ostream& os) const
{ {
os << "{";
if (element) {
String type_str; String type_str;
if (type == commentSubjectElement) { if (type == commentSubjectElement) {
type_str = "element"; type_str = "element";
@@ -266,8 +343,10 @@ std::ostream& CommentSubject::dump(std::ostream& os) const
CYB_ASSERT(type == commentSubjectData); CYB_ASSERT(type == commentSubjectData);
type_str = "data"; type_str = "data";
} }
os << "to: '" << element->get_id(); os << "{ id: '" << id << "'";
os << "', type: " << type_str; os << ", type: " << type_str;
if (element) {
os << ", to: '" << element->get_id() << "'";
if (has_frag) { if (has_frag) {
os << ", fragment: '" << fragment << "'"; os << ", fragment: '" << fragment << "'";
} }
@@ -328,6 +407,67 @@ void Comment::update_comment_type()
} }
} }
CyberiadaNode* Comment::to_node() const
{
CyberiadaNode* node = Element::to_node();
CyberiadaCommentData* data = cyberiada_new_comment_data();
if (!body.empty()) {
cyberiada_copy_string(&(data->body), &(data->body_len), body.c_str());
}
if (!markup.empty()) {
cyberiada_copy_string(&(data->markup), &(data->markup_len), markup.c_str());
}
node->comment_data = data;
if (has_geometry()) {
node->geometry_rect = geometry_rect.c_rect();
if (has_color()) {
cyberiada_copy_string(&(node->color), &(node->color_len), color.c_str());
}
}
return node;
}
CyberiadaEdge* Comment::subjects_to_edge() const
{
CyberiadaEdge* result = NULL;
if (has_subjects()) {
for (std::list<CommentSubject>::const_iterator i = subjects.begin(); i != subjects.end(); i++) {
CyberiadaEdge *edge = cyberiada_new_edge(i->get_id().c_str(),
get_id().c_str(),
i->get_element()->get_id().c_str());
edge->type = cybEdgeComment;
CyberiadaCommentSubjectType t;
if (i->get_type() == commentSubjectElement) {
t = cybCommentSubjectNode;
} else if (i->get_type() == commentSubjectName) {
t = cybCommentSubjectNameFragment;
} else {
CYB_ASSERT(i->get_type() == commentSubjectData);
t = cybCommentSubjectDataFragment;
}
CyberiadaCommentSubject* cs = cyberiada_new_comment_subject(t);
if (i->has_fragment()) {
cyberiada_copy_string(&(cs->fragment), &(cs->fragment_len), i->get_fragment().c_str());
}
edge->comment_subject = cs;
if (i->has_geometry()) {
if (i->get_geometry_source_point().valid) {
edge->geometry_source_point = i->get_geometry_source_point().c_point();
}
if (i->get_geometry_target_point().valid) {
edge->geometry_target_point = i->get_geometry_target_point().c_point();
}
if (i->has_polyline()) {
edge->geometry_polyline = c_polyline(i->get_geometry_polyline());
}
}
}
}
return result;
}
std::ostream& Comment::dump(std::ostream& os) const std::ostream& Comment::dump(std::ostream& os) const
{ {
os << "Comment { " << (human_readable ? "informal" : "formal") << ", "; os << "Comment { " << (human_readable ? "informal" : "formal") << ", ";
@@ -372,6 +512,15 @@ std::ostream& Vertex::dump(std::ostream& os) const
return os; return os;
} }
CyberiadaNode* Vertex::to_node() const
{
CyberiadaNode* node = Element::to_node();
if (has_geometry()) {
node->geometry_point = geometry_point.c_point();
}
return node;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Collection of Elements // Collection of Elements
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -576,6 +725,34 @@ std::list<Vertex*> ElementCollection::get_vertexes()
return result; return result;
} }
CyberiadaNode* ElementCollection::to_node() const
{
CyberiadaNode* node = Element::to_node();
if (has_geometry()) {
node->geometry_rect = geometry_rect.c_rect();
}
if (has_color()) {
cyberiada_copy_string(&(node->color), &(node->color_len), color.c_str());
}
for (ElementList::const_iterator i = children.begin(); i != children.end(); i++) {
const Element* e = *i;
CYB_ASSERT(e);
if (e->get_type() == elementTransition) {
continue;
}
CyberiadaNode* child = e->to_node();
CYB_ASSERT(child);
if (node->children) {
CyberiadaNode* n = node->children;
while (n->next) n = n->next;
n->next = child;
} else {
node->children = child;
}
}
return node;
}
std::ostream& ElementCollection::dump(std::ostream& os) const std::ostream& ElementCollection::dump(std::ostream& os) const
{ {
if (has_geometry()) { if (has_geometry()) {
@@ -650,6 +827,18 @@ ChoicePseudostate::ChoicePseudostate(Element* _parent, const ID& _id, const Name
{ {
} }
CyberiadaNode* ChoicePseudostate::to_node() const
{
CyberiadaNode* node = Element::to_node();
if (has_geometry()) {
node->geometry_rect = geometry_rect.c_rect();
if (has_color()) {
cyberiada_copy_string(&(node->color), &(node->color_len), color.c_str());
}
}
return node;
}
std::ostream& ChoicePseudostate::dump(std::ostream& os) const std::ostream& ChoicePseudostate::dump(std::ostream& os) const
{ {
os << "Choice {"; os << "Choice {";
@@ -752,6 +941,37 @@ void State::update_state_type()
} }
} }
CyberiadaNode* State::to_node() const
{
CyberiadaNode* node = ElementCollection::to_node();
if (has_actions()) {
for (std::list<Action>::const_iterator i = actions.begin(); i != actions.end(); i++) {
const Action& a = *i;
CyberiadaActionType at;
if (a.get_type() == actionEntry) {
at = cybActionEntry;
} else if (a.get_type() == actionExit) {
at = cybActionExit;
} else {
CYB_ASSERT(a.get_type() == actionTransition);
at = cybActionTransition;
}
CyberiadaAction* action = cyberiada_new_action(at,
a.get_trigger().c_str(),
a.get_guard().c_str(),
a.get_behavior().c_str());
if (node->actions) {
CyberiadaAction* last_a = node->actions;
while (last_a->next) last_a = last_a->next;
last_a->next = action;
} else {
node->actions = action;
}
}
}
return node;
}
std::ostream& State::dump(std::ostream& os) const std::ostream& State::dump(std::ostream& os) const
{ {
if (is_simple_state()) { if (is_simple_state()) {
@@ -763,7 +983,7 @@ std::ostream& State::dump(std::ostream& os) const
if (has_actions()) { if (has_actions()) {
os << ", actions: {"; os << ", actions: {";
for (std::list<Action>::const_iterator i = actions.begin(); i != actions.end(); i++) { for (std::list<Action>::const_iterator i = actions.begin(); i != actions.end(); i++) {
os << *i; os << "a {" << *i << "}";
if (std::next(i) != actions.end()) { if (std::next(i) != actions.end()) {
os << ", "; os << ", ";
} }
@@ -787,6 +1007,40 @@ Transition::Transition(Element* _parent, const ID& _id, Element* _source, Elemen
{ {
} }
CyberiadaEdge* Transition::to_edge() const
{
CYB_ASSERT(source);
CYB_ASSERT(target);
CyberiadaEdge* edge = cyberiada_new_edge(get_id().c_str(),
source->get_id().c_str(),
target->get_id().c_str());
edge->type = cybEdgeTransition;
if (has_action()) {
edge->action = cyberiada_new_action(cybActionTransition,
action.get_trigger().c_str(),
action.get_guard().c_str(),
action.get_behavior().c_str());
}
if (has_geometry()) {
if (source_point.valid) {
edge->geometry_source_point = source_point.c_point();
}
if (target_point.valid) {
edge->geometry_target_point = target_point.c_point();
}
if (label_point.valid) {
edge->geometry_label_point = label_point.c_point();
}
if (has_polyline()) {
edge->geometry_polyline = c_polyline(polyline);
}
if (has_color()) {
cyberiada_copy_string(&(edge->color), &(edge->color_len), color.c_str());
}
}
return edge;
}
std::ostream& Transition::dump(std::ostream& os) const std::ostream& Transition::dump(std::ostream& os) const
{ {
os << "Transition {"; os << "Transition {";
@@ -912,7 +1166,7 @@ StateMachine* Document::new_state_machine(const ID& _id, const String& sm_name,
return sm; return sm;
} }
void Document::check_cyberiada_error(int res, const String& msg) void Document::check_cyberiada_error(int res, const String& msg) const
{ {
switch (res) { switch (res) {
case CYBERIADA_XML_ERROR: throw XMLException(msg); case CYBERIADA_XML_ERROR: throw XMLException(msg);
@@ -1104,7 +1358,7 @@ void Document::import_edges(ElementCollection* collection, CyberiadaEdge* edges)
comment = static_cast<Comment*>(source_element); comment = static_cast<Comment*>(source_element);
if (e->comment_subject->type == cybCommentSubjectNode) { if (e->comment_subject->type == cybCommentSubjectNode) {
comment->add_subject(CommentSubject(target_element, source_point, target_point, polyline)); comment->add_subject(CommentSubject(e->id, target_element, source_point, target_point, polyline));
} else { } else {
CommentSubjectType cst; CommentSubjectType cst;
if (e->comment_subject->type == cybCommentSubjectNameFragment) { if (e->comment_subject->type == cybCommentSubjectNameFragment) {
@@ -1115,7 +1369,7 @@ void Document::import_edges(ElementCollection* collection, CyberiadaEdge* edges)
throw CybMLException("Unsupported comment subject type " + std::to_string(e->comment_subject->type)); throw CybMLException("Unsupported comment subject type " + std::to_string(e->comment_subject->type));
} }
CYB_ASSERT(e->comment_subject->fragment); CYB_ASSERT(e->comment_subject->fragment);
comment->add_subject(CommentSubject(target_element, cst, e->comment_subject->fragment, comment->add_subject(CommentSubject(e->id, target_element, cst, e->comment_subject->fragment,
source_point, target_point, polyline)); source_point, target_point, polyline));
} }
break; break;
@@ -1128,14 +1382,14 @@ void Document::import_edges(ElementCollection* collection, CyberiadaEdge* edges)
} }
} }
void Document::load(const String& path) void Document::load(const String& path, DocumentFormat f)
{ {
reset(); reset();
CyberiadaDocument doc; CyberiadaDocument doc;
int res = cyberiada_init_sm_document(&doc); int res = cyberiada_init_sm_document(&doc);
CYB_ASSERT(res == CYBERIADA_NO_ERROR); CYB_ASSERT(res == CYBERIADA_NO_ERROR);
res = cyberiada_read_sm_document(&doc, path.c_str(), cybxmlUnknown); res = cyberiada_read_sm_document(&doc, path.c_str(), CyberiadaXMLFormat(f));
if (res != CYBERIADA_NO_ERROR) { if (res != CYBERIADA_NO_ERROR) {
cyberiada_cleanup_sm_document(&doc); cyberiada_cleanup_sm_document(&doc);
CYB_CHECK_RESULT(res); CYB_CHECK_RESULT(res);
@@ -1179,8 +1433,11 @@ void Document::load(const String& path)
if (doc.meta_info->date) { if (doc.meta_info->date) {
metainfo.date = doc.meta_info->date; metainfo.date = doc.meta_info->date;
} }
metainfo.transition_order_flag = bool(doc.meta_info->transition_order_flag); if (doc.meta_info->markup_language) {
metainfo.event_propagation_flag = bool(doc.meta_info->event_propagation_flag); metainfo.markup_language = doc.meta_info->markup_language;
}
metainfo.transition_order_flag = doc.meta_info->transition_order_flag == 2;
metainfo.event_propagation_flag = doc.meta_info->event_propagation_flag == 2;
for (CyberiadaSM* sm = doc.state_machines; sm; sm = sm->next) { for (CyberiadaSM* sm = doc.state_machines; sm; sm = sm->next) {
CyberiadaNode* root = sm->nodes; CyberiadaNode* root = sm->nodes;
@@ -1213,9 +1470,150 @@ void Document::load(const String& path)
cyberiada_cleanup_sm_document(&doc); cyberiada_cleanup_sm_document(&doc);
} }
void Document::save(const String& path) const void Document::export_edges(CyberiadaEdge** edges, const StateMachine* sm) const
{ {
// TODO CyberiadaEdge* edge;
std::list<const Transition*> transitions = sm->get_transitions();
for (std::list<const Transition*>::const_iterator i = transitions.begin(); i != transitions.end(); i++) {
const Transition* t = *i;
edge = t->to_edge();
if (*edges) {
CyberiadaEdge* e = *edges;
while (e->next) e = e->next;
e->next = edge;
} else {
*edges = edge;
}
}
std::list<const Comment*> comments = sm->get_comments();
for (std::list<const Comment*>::const_iterator j = comments.begin(); j != comments.end(); j++) {
const Comment* c = *j;
edge = c->subjects_to_edge();
if (*edges) {
CyberiadaEdge* e = *edges;
while (e->next) e = e->next;
e->next = edge;
} else {
*edges = edge;
}
}
}
void Document::save(const String& path, DocumentFormat f) const
{
CyberiadaDocument doc;
int res;
if (f == formatDetect) {
throw ParametersException("Bad save format " + std::to_string(f));
} else if (f == formatLegacyYED) {
if (children_count() != 1) {
throw ParametersException("Legacy Berloga-YED format supports single-SM documents only");
}
}
std::list<const StateMachine*> state_machines = get_state_machines();
if (state_machines.empty()) {
throw ParametersException("At least one state machine required");
}
res = cyberiada_init_sm_document(&doc);
CYB_ASSERT(res == CYBERIADA_NO_ERROR);
try {
if (f == formatCyberiada10) {
cyberiada_copy_string(&(doc.format), &(doc.format_len),
DEFAULT_GRAPHML_FORMAT.c_str());
}
doc.meta_info = cyberiada_new_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++) {
const StateMachine* orig_sm = *i;
CYB_ASSERT(orig_sm);
CyberiadaSM* new_sm = cyberiada_new_sm();
new_sm->nodes = orig_sm->to_node();
export_edges(&(new_sm->edges), orig_sm);
if (doc.state_machines) {
CyberiadaSM* sm = doc.state_machines;
while(sm->next) sm = sm->next;
sm->next = new_sm;
} else {
doc.state_machines = new_sm;
}
}
} catch (const Exception& e) {
cyberiada_cleanup_sm_document(&doc);
throw AssertException("Internal save error: " + e.str());
}
res = cyberiada_write_sm_document(&doc, path.c_str(), CyberiadaXMLFormat(f));
if (res != CYBERIADA_NO_ERROR) {
cyberiada_cleanup_sm_document(&doc);
CYB_CHECK_RESULT(res);
}
cyberiada_cleanup_sm_document(&doc);
} }
std::list<const StateMachine*> Document::get_state_machines() const std::list<const StateMachine*> Document::get_state_machines() const
@@ -1277,6 +1675,9 @@ std::ostream& Document::dump(std::ostream& os) const
if (!metainfo.date.empty()) { if (!metainfo.date.empty()) {
params.push_back("date: '" + metainfo.date + "'"); params.push_back("date: '" + metainfo.date + "'");
} }
if (!metainfo.markup_language.empty()) {
params.push_back("markup language: '" + metainfo.markup_language + "'");
}
params.push_back(String("transition order: ") + (metainfo.transition_order_flag ? "transition first": "exit first")); params.push_back(String("transition order: ") + (metainfo.transition_order_flag ? "transition first": "exit first"));
params.push_back(String("event propagation: ") + (metainfo.event_propagation_flag ? "block events": "propagate events")); params.push_back(String("event propagation: ") + (metainfo.event_propagation_flag ? "block events": "propagate events"));
for (std::list<String>::const_iterator i = params.begin(); i != params.end(); i++) { for (std::list<String>::const_iterator i = params.begin(); i != params.end(); i++) {

View File

@@ -87,6 +87,7 @@ namespace Cyberiada {
virtual bool has_geometry() const = 0; virtual bool has_geometry() const = 0;
friend std::ostream& operator<<(std::ostream& os, const Element& e); friend std::ostream& operator<<(std::ostream& os, const Element& e);
virtual CyberiadaNode* to_node() const;
protected: protected:
Element* find_root(); Element* find_root();
@@ -112,6 +113,8 @@ namespace Cyberiada {
valid(true), x(_x), y(_y) {} valid(true), x(_x), y(_y) {}
Point(CyberiadaPoint* p); Point(CyberiadaPoint* p);
CyberiadaPoint* c_point() const;
bool valid; bool valid;
float x, y; float x, y;
}; };
@@ -122,6 +125,8 @@ namespace Cyberiada {
valid(true), x(_x), y(_y), width(_width), height(_height) {} valid(true), x(_x), y(_y), width(_width), height(_height) {}
Rect(CyberiadaRect* r); Rect(CyberiadaRect* r);
CyberiadaRect* c_rect() const;
bool valid; bool valid;
float x, y; float x, y;
float width, height; float width, height;
@@ -133,6 +138,8 @@ namespace Cyberiada {
std::ostream& operator<<(std::ostream& os, const Rect& r); std::ostream& operator<<(std::ostream& os, const Rect& r);
std::ostream& operator<<(std::ostream& os, const Polyline& pl); std::ostream& operator<<(std::ostream& os, const Polyline& pl);
CyberiadaPolyline* c_polyline(const Polyline& polyline);
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Comment // Comment
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -144,13 +151,14 @@ namespace Cyberiada {
class CommentSubject { class CommentSubject {
public: public:
CommentSubject(Element* element, CommentSubject(const ID& id, Element* element,
const Point& source = Point(), const Point& target = Point(), const Polyline& pl = Polyline()); const Point& source = Point(), const Point& target = Point(), const Polyline& pl = Polyline());
CommentSubject(Element* element, CommentSubjectType type, const String& fragment, CommentSubject(const ID& id, Element* element, CommentSubjectType type, const String& fragment,
const Point& source = Point(), const Point& target = Point(), const Polyline& pl = Polyline()); const Point& source = Point(), const Point& target = Point(), const Polyline& pl = Polyline());
CommentSubject& operator=(const CommentSubject& cs); CommentSubject& operator=(const CommentSubject& cs);
const ID& get_id() const { return id; }
CommentSubjectType get_type() const { return type; } CommentSubjectType get_type() const { return type; }
const Element* get_element() const { return element; } const Element* get_element() const { return element; }
Element* get_element() { return element; } Element* get_element() { return element; }
@@ -158,7 +166,8 @@ namespace Cyberiada {
bool has_fragment() const { return has_frag; } bool has_fragment() const { return has_frag; }
const String& get_fragment() const { return fragment; } const String& get_fragment() const { return fragment; }
bool has_geometry() const { return source_point.valid || target_point.valid || !polyline.empty(); } bool has_geometry() const { return source_point.valid || target_point.valid || has_polyline(); }
bool has_polyline() const { return !polyline.empty(); }
const Point& get_geometry_source_point() const { return source_point; } const Point& get_geometry_source_point() const { return source_point; }
const Point& get_geometry_target_point() const { return target_point; } const Point& get_geometry_target_point() const { return target_point; }
const Polyline& get_geometry_polyline() const { return polyline; } const Polyline& get_geometry_polyline() const { return polyline; }
@@ -169,6 +178,7 @@ namespace Cyberiada {
private: private:
CommentSubjectType type; CommentSubjectType type;
ID id;
Element* element; Element* element;
bool has_frag; bool has_frag;
String fragment; String fragment;
@@ -205,6 +215,9 @@ namespace Cyberiada {
bool has_markup() const { return !markup.empty(); } bool has_markup() const { return !markup.empty(); }
const String& get_markup() const { return markup; } const String& get_markup() const { return markup; }
virtual CyberiadaNode* to_node() const;
virtual CyberiadaEdge* subjects_to_edge() const;
protected: protected:
virtual std::ostream& dump(std::ostream& os) const; virtual std::ostream& dump(std::ostream& os) const;
@@ -232,6 +245,8 @@ namespace Cyberiada {
virtual bool has_children() const { return false; } virtual bool has_children() const { return false; }
virtual CyberiadaNode* to_node() const;
protected: protected:
virtual std::ostream& dump(std::ostream& os) const; virtual std::ostream& dump(std::ostream& os) const;
@@ -279,6 +294,8 @@ namespace Cyberiada {
bool has_color() const { return !color.empty(); } bool has_color() const { return !color.empty(); }
const Color& get_color() const { return color; } const Color& get_color() const { return color; }
virtual CyberiadaNode* to_node() const;
protected: protected:
virtual std::ostream& dump(std::ostream& os) const; virtual std::ostream& dump(std::ostream& os) const;
@@ -326,6 +343,8 @@ namespace Cyberiada {
bool has_color() const { return !color.empty(); } bool has_color() const { return !color.empty(); }
const Color& get_color() const { return color; } const Color& get_color() const { return color; }
virtual CyberiadaNode* to_node() const;
protected: protected:
virtual std::ostream& dump(std::ostream& os) const; virtual std::ostream& dump(std::ostream& os) const;
@@ -368,11 +387,11 @@ namespace Cyberiada {
ActionType get_type() const { return type; } ActionType get_type() const { return type; }
bool has_trigger() const { return !trigger.empty(); } bool has_trigger() const { return !trigger.empty(); }
const Event& get_trigger() { return trigger; } const Event& get_trigger() const { return trigger; }
bool has_guard() const { return !guard.empty(); } bool has_guard() const { return !guard.empty(); }
const Guard& get_guard() { return guard; } const Guard& get_guard() const { return guard; }
bool has_behavior() const { return !behavior.empty(); } bool has_behavior() const { return !behavior.empty(); }
const Behavior& get_behavior() { return behavior; } const Behavior& get_behavior() const { return behavior; }
protected: protected:
std::ostream& dump(std::ostream& os) const; std::ostream& dump(std::ostream& os) const;
@@ -409,6 +428,8 @@ namespace Cyberiada {
std::list<Action>& get_actions() { return actions; } std::list<Action>& get_actions() { return actions; }
void add_action(const Action& a); void add_action(const Action& a);
virtual CyberiadaNode* to_node() const;
protected: protected:
virtual std::ostream& dump(std::ostream& os) const; virtual std::ostream& dump(std::ostream& os) const;
void update_state_type(); void update_state_type();
@@ -446,6 +467,8 @@ namespace Cyberiada {
bool has_color() const { return !color.empty(); } bool has_color() const { return !color.empty(); }
virtual CyberiadaEdge* to_edge() const;
protected: protected:
virtual std::ostream& dump(std::ostream& os) const; virtual std::ostream& dump(std::ostream& os) const;
@@ -480,6 +503,12 @@ namespace Cyberiada {
// Cyberiada-GraphML document // Cyberiada-GraphML document
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
enum DocumentFormat {
formatCyberiada10 = 0, // Cyberiada 1.0 format
formatLegacyYED = 1, // Legacy YED-based Berloga/Ostranna format
formatDetect = 99 // Format is not specified and will be detected while loading
};
struct DocumentMetainformation { struct DocumentMetainformation {
String standard_version; // PRIMS standard version String standard_version; // PRIMS standard version
String platform_name; // target platform name String platform_name; // target platform name
@@ -492,8 +521,9 @@ namespace Cyberiada {
String description; // document description String description; // document description
String version; // document version String version; // document version
String date; // document date String date; // document date
bool transition_order_flag; String markup_language; // default comments' markup language
bool event_propagation_flag; bool transition_order_flag; // false = transition first; true = exit first
bool event_propagation_flag;// false = block events; true = propagate events
}; };
class Document: public ElementCollection { class Document: public ElementCollection {
@@ -503,8 +533,8 @@ namespace Cyberiada {
void reset(); void reset();
StateMachine* new_state_machine(const String& sm_nam, const Rect& r = Rect()); StateMachine* new_state_machine(const String& sm_nam, const Rect& r = Rect());
StateMachine* new_state_machine(const ID& id, const String& sm_name, const Rect& r = Rect()); StateMachine* new_state_machine(const ID& id, const String& sm_name, const Rect& r = Rect());
void load(const String& path); void load(const String& path, DocumentFormat f = formatDetect);
void save(const String& path) const; void save(const String& path, DocumentFormat f = formatCyberiada10) const;
const DocumentMetainformation& meta() const { return metainfo; } const DocumentMetainformation& meta() const { return metainfo; }
DocumentMetainformation& meta() { return metainfo; } DocumentMetainformation& meta() { return metainfo; }
@@ -516,12 +546,13 @@ namespace Cyberiada {
virtual std::ostream& dump(std::ostream& os) const; virtual std::ostream& dump(std::ostream& os) const;
private: private:
void check_cyberiada_error(int res, const String& msg = ""); void check_cyberiada_error(int res, const String& msg = "") const;
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;
String format; String format;
DocumentMetainformation metainfo; DocumentMetainformation metainfo;

93
main.cpp Normal file
View File

@@ -0,0 +1,93 @@
/* -----------------------------------------------------------------------------
* The Cyberiada GraphML C++ library implemention
*
* The testing program
*
* 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 <stdlib.h>
#include "cyberiadamlpp.h"
using namespace Cyberiada;
using namespace std;
void usage(const char* program)
{
cerr << program << " <print|convert> [[-f <cyberiada|yed>] -o <path-to-output-graphml-file>] <path-to-input-graphml-file>" << endl;
cerr << "\tprint\tPrint the graphml SM structure of the file <path-to-input-graphml-file>" << endl;
cerr << "\tconvert\tConvert the graphml SM file from <path-to-input-graphml-file> to <path-to-output-graphml-file> using format:" << endl;
cerr << "\t\t\tcyberiada Cyberiada-GraphML 1.0 format" << endl;
cerr << "\t\t\tyed Legacy Berloga-YED format" << endl;
exit(1);
}
int main(int argc, char** argv)
{
Document d;
DocumentFormat format;
string command, from_file, to_file, format_str;
if (argc < 3) {
usage(argv[0]);
}
command = argv[1];
if (command == "print" && argc == 3) {
from_file = argv[2];
} else if (command == "convert" && (argc == 5 || argc == 7)) {
if (argc == 5 && string(argv[2]) == "-o") {
to_file = argv[3];
from_file = argv[4];
} else if (argc == 7) {
if (string(argv[2]) == "-f" && string(argv[4]) == "-o") {
to_file = argv[5];
format_str = argv[3];
} else if (string(argv[2]) == "-o" && string(argv[4]) == "-f") {
to_file = argv[3];
format_str = argv[5];
} else {
usage(argv[0]);
}
from_file = argv[6];
} else {
usage(argv[0]);
}
if (format_str.empty() || format_str == "cyberiada") {
format = formatCyberiada10;
} else if (format_str == "yes") {
format = formatLegacyYED;
} else {
usage(argv[0]);
}
} else {
usage(argv[0]);
}
try {
d.load(from_file);
if (argc == 3) {
cout << d << endl;
} else {
d.save(to_file, format);
}
} catch (const Cyberiada::Exception& e) {
cerr << "Error while processing graphml file: " << e.str() << endl;
return 2;
}
return 0;
}

View File

@@ -1,52 +0,0 @@
/* -----------------------------------------------------------------------------
* The Cyberiada GraphML C++ library implemention
*
* The testing program
*
* 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 <stdlib.h>
#include "cyberiadamlpp.h"
using namespace Cyberiada;
using namespace std;
void usage(const char* program)
{
cerr << program << " <path-to-graphml-file>" << endl;
cerr << "\tPrint the graphml SM structure of the file <path-to-graphml-file>" << endl;
exit(1);
}
int main(int argc, char** argv)
{
Document d;
if (argc != 2) {
usage(argv[0]);
}
try {
d.load(argv[1]);
cout << d << endl;
} catch (const Cyberiada::Exception& e) {
cerr << "Error while opening graphml file: " << e.str() << endl;
return 2;
}
return 0;
}