File indexing completed on 2024-05-19 15:27:47

0001 /* This file is part of KGraphViewer.
0002    Copyright (C) 2006-2007 Gael de Chalendar <kleag@free.fr>
0003 
0004    KGraphViewer is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public
0006    License as published by the Free Software Foundation, version 2.
0007 
0008    This program is distributed in the hope that it will be useful,
0009    but WITHOUT ANY WARRANTY; without even the implied warranty of
0010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0011    General Public License for more details.
0012 
0013    You should have received a copy of the GNU General Public License
0014    along with this program; if not, write to the Free Software
0015    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0016    02110-1301, USA
0017 */
0018 
0019 #include "DotGraphParsingHelper.h"
0020 #include "dotdefaults.h"
0021 #include "dotgrammar.h"
0022 #include "dotgraph.h"
0023 //#include "graphsubgraph.h"
0024 #include "graphedge.h"
0025 #include "graphnode.h"
0026 #include "kgraphviewerlib_debug.h"
0027 
0028 #include <boost/spirit/include/classic_confix.hpp>
0029 #include <boost/spirit/include/classic_core.hpp>
0030 #include <boost/spirit/include/classic_distinct.hpp>
0031 #include <boost/spirit/include/classic_loops.hpp>
0032 #include <boost/throw_exception.hpp>
0033 
0034 #include <iostream>
0035 
0036 #include <QDebug>
0037 
0038 #include <QFile>
0039 #include <QUuid>
0040 
0041 using namespace std;
0042 
0043 extern KGraphViewer::DotGraphParsingHelper *phelper;
0044 
0045 namespace KGraphViewer
0046 {
0047 #define KGV_MAX_ITEMS_TO_LOAD std::numeric_limits<int>::max()
0048 
0049 DotGraphParsingHelper::DotGraphParsingHelper()
0050     : attrid()
0051     , valid()
0052     , attributed()
0053     , subgraphid()
0054     , uniq(0)
0055     , attributes()
0056     , graphAttributes()
0057     , nodesAttributes()
0058     , edgesAttributes()
0059     , graphAttributesStack()
0060     , nodesAttributesStack()
0061     , edgesAttributesStack()
0062     , edgebounds()
0063     , z(0)
0064     , maxZ(0)
0065     , graph(nullptr)
0066     , gs(nullptr)
0067     , gn(nullptr)
0068     , ge(nullptr)
0069 {
0070 }
0071 
0072 void DotGraphParsingHelper::setgraphelementattributes(GraphElement *ge, const AttributesMap &attributes)
0073 {
0074     AttributesMap::const_iterator it, it_end;
0075     it = attributes.begin();
0076     it_end = attributes.end();
0077     for (; it != it_end; it++) {
0078         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "    " << QString::fromStdString((*it).first) << "\t=\t'" << QString::fromStdString((*it).second) <<"'";
0079         if ((*it).first == "label") {
0080             QString label = QString::fromUtf8((*it).second.c_str());
0081             label.replace("\\n", "\n");
0082             (*ge).attributes()["label"] = label;
0083         } else {
0084             (*ge).attributes()[QString::fromStdString((*it).first)] = QString::fromStdString((*it).second);
0085         }
0086     }
0087 
0088     DotRenderOpVec ops = ge->renderOperations();
0089     if (attributes.find("_draw_") != attributes.end()) {
0090         parse_renderop((attributes.find("_draw_"))->second, ops);
0091         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "element renderOperations size is now " << ge->renderOperations().size();
0092     }
0093     if (attributes.find("_ldraw_") != attributes.end()) {
0094         parse_renderop(attributes.find("_ldraw_")->second, ops);
0095         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "element renderOperations size is now " << ge->renderOperations().size();
0096     }
0097     if (attributes.find("_hldraw_") != attributes.end()) {
0098         parse_renderop(attributes.find("_hldraw_")->second, ops);
0099         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "element renderOperations size is now " << ge->renderOperations().size();
0100     }
0101     if (attributes.find("_tldraw_") != attributes.end()) {
0102         parse_renderop(attributes.find("_tldraw_")->second, ops);
0103         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "element renderOperations size is now " << ge->renderOperations().size();
0104     }
0105     ge->setRenderOperations(ops);
0106 }
0107 
0108 void DotGraphParsingHelper::setgraphattributes()
0109 {
0110     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "Attributes for graph are : ";
0111     setgraphelementattributes(graph, graphAttributes);
0112 }
0113 
0114 void DotGraphParsingHelper::setsubgraphattributes()
0115 {
0116     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "Attributes for subgraph are : ";
0117     gs->setZ(z);
0118     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "z="<<gs->z();
0119     setgraphelementattributes(gs, graphAttributes);
0120 }
0121 
0122 void DotGraphParsingHelper::setnodeattributes()
0123 {
0124     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "setnodeattributes with z = " << z;
0125 
0126     if (gn == nullptr) {
0127         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "gn is null";
0128         return;
0129     }
0130     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "Attributes for node " << gn->id() << " are : ";
0131     gn->setZ(z + 1);
0132     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "z="<<gn->z();
0133     setgraphelementattributes(gn, nodesAttributes);
0134 }
0135 
0136 void DotGraphParsingHelper::setedgeattributes()
0137 {
0138     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "setedgeattributeswith z = " << z;
0139 
0140     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "Attributes for edge " << ge->fromNode()->id() << "->" << ge->toNode()->id() << " are : ";
0141     ge->setZ(z + 1);
0142     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "z="<<ge->z();
0143     setgraphelementattributes(ge, edgesAttributes);
0144 
0145     DotRenderOpVec ops = ge->renderOperations();
0146     if (edgesAttributes.find("_tdraw_") != edgesAttributes.end()) {
0147         parse_renderop(edgesAttributes["_tdraw_"], ops);
0148         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "edge renderOperations size is now " << ge->renderOperations().size();
0149         DotRenderOpVec::const_iterator it, it_end;
0150         it = ops.constBegin();
0151         it_end = ops.constEnd();
0152         for (; it != it_end; it++)
0153             ge->arrowheads().push_back(*it);
0154     }
0155     if (edgesAttributes.find("_hdraw_") != edgesAttributes.end()) {
0156         parse_renderop(edgesAttributes["_hdraw_"], ops);
0157         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "edge renderOperations size is now " << ge->renderOperations().size();
0158         DotRenderOpVec::const_iterator it, it_end;
0159         it = ops.constBegin();
0160         it_end = ops.constEnd();
0161         for (; it != it_end; it++)
0162             ge->arrowheads().push_back(*it);
0163     }
0164     ge->setRenderOperations(ops);
0165 }
0166 
0167 void DotGraphParsingHelper::setattributedlist()
0168 {
0169     // //   qCDebug(KGRAPHVIEWERLIB_LOG) << "Setting attributes list for " << QString::fromStdString(attributed);
0170     if (attributed == "graph") {
0171         if (attributes.find("bb") != attributes.end()) {
0172             std::vector<int> v;
0173             parse_integers(attributes["bb"].c_str(), v);
0174             if (v.size() >= 4) {
0175                 //         qCDebug(KGRAPHVIEWERLIB_LOG) << "setting width and height to " << v[2] << v[3];
0176                 graph->width(v[2]);
0177                 graph->height(v[3]);
0178             }
0179         }
0180         AttributesMap::const_iterator it, it_end;
0181         it = attributes.begin();
0182         it_end = attributes.end();
0183         for (; it != it_end; it++) {
0184             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "    " << QString::fromStdString((*it).first) << " = " <<  QString::fromStdString((*it).second);
0185             graphAttributes[(*it).first] = (*it).second;
0186         }
0187     } else if (attributed == "node") {
0188         AttributesMap::const_iterator it, it_end;
0189         it = attributes.begin();
0190         it_end = attributes.end();
0191         for (; it != it_end; it++) {
0192             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "    " << QString::fromStdString((*it).first) << " = " <<  QString::fromStdString((*it).second);
0193             nodesAttributes[(*it).first] = (*it).second;
0194         }
0195     } else if (attributed == "edge") {
0196         AttributesMap::const_iterator it, it_end;
0197         it = attributes.begin();
0198         it_end = attributes.end();
0199         for (; it != it_end; it++) {
0200             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "    " << QString::fromStdString((*it).first) << " = " <<  QString::fromStdString((*it).second);
0201             edgesAttributes[(*it).first] = (*it).second;
0202         }
0203     }
0204     attributes.clear();
0205 }
0206 
0207 void DotGraphParsingHelper::createnode(const std::string &nodeid)
0208 {
0209     QString id = QString::fromStdString(nodeid);
0210     //   qCDebug(KGRAPHVIEWERLIB_LOG) << id;
0211     gn = dynamic_cast<GraphNode *>(graph->elementNamed(id));
0212     if (gn == nullptr && graph->nodes().size() < KGV_MAX_ITEMS_TO_LOAD) {
0213         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "Creating a new node" << z << (void*)gs;
0214         gn = new GraphNode();
0215         gn->setId(id);
0216         //     gn->label(QString::fromStdString(nodeid));
0217         if (z > 0 && gs) {
0218             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "Adding node" << id << "in subgraph" << gs->id();
0219             gs->content().push_back(gn);
0220         } else {
0221             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "Adding node" << id;
0222             graph->nodes()[id] = gn;
0223         }
0224     }
0225     edgebounds.clear();
0226 }
0227 
0228 void DotGraphParsingHelper::createsubgraph()
0229 {
0230     //   qCDebug(KGRAPHVIEWERLIB_LOG) ;
0231     if (phelper) {
0232         std::string str = phelper->subgraphid;
0233         if (str.empty()) {
0234             std::ostringstream oss;
0235             oss << "kgv_id_" << phelper->uniq++;
0236             str = oss.str();
0237         }
0238         //     qCDebug(KGRAPHVIEWERLIB_LOG) << QString::fromStdString(str);
0239         if (graph->subgraphs().find(QString::fromStdString(str)) == graph->subgraphs().end()) {
0240             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "Creating a new subgraph";
0241             gs = new GraphSubgraph();
0242             gs->setId(QString::fromStdString(str));
0243             //       gs->label(QString::fromStdString(str));
0244             graph->subgraphs().insert(QString::fromStdString(str), gs);
0245             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "there is now"<<graph->subgraphs().size()<<"subgraphs in" << graph;
0246         } else {
0247             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "Found existing subgraph";
0248             gs = *(graph->subgraphs().find(QString::fromStdString(str)));
0249         }
0250         phelper->subgraphid = "";
0251     }
0252 }
0253 
0254 void DotGraphParsingHelper::createedges()
0255 {
0256     //   qCDebug(KGRAPHVIEWERLIB_LOG);
0257     std::string node1Name, node2Name;
0258     node1Name = edgebounds.front();
0259     edgebounds.pop_front();
0260     while (!edgebounds.empty()) {
0261         node2Name = edgebounds.front();
0262         edgebounds.pop_front();
0263 
0264         if (graph->nodes().size() >= KGV_MAX_ITEMS_TO_LOAD || graph->edges().size() >= KGV_MAX_ITEMS_TO_LOAD) {
0265             return;
0266         }
0267         //     qCDebug(KGRAPHVIEWERLIB_LOG) << QString::fromStdString(node1Name) << ", " << QString::fromStdString(node2Name);
0268         ge = new GraphEdge();
0269         GraphElement *gn1 = graph->elementNamed(QString::fromStdString(node1Name));
0270         if (gn1 == nullptr) {
0271             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "new node 1";
0272             gn1 = new GraphNode();
0273             gn1->setId(QString::fromStdString(node1Name));
0274             graph->nodes()[QString::fromStdString(node1Name)] = dynamic_cast<GraphNode *>(gn1);
0275         }
0276         GraphElement *gn2 = graph->elementNamed(QString::fromStdString(node2Name));
0277         if (gn2 == nullptr) {
0278             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "new node 2";
0279             gn2 = new GraphNode();
0280             gn2->setId(QString::fromStdString(node2Name));
0281             graph->nodes()[QString::fromStdString(node2Name)] = dynamic_cast<GraphNode *>(gn2);
0282         }
0283         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "Found gn1="<<gn1<<" and gn2=" << gn2;
0284         if (gn1 == nullptr || gn2 == nullptr) {
0285             qCWarning(KGRAPHVIEWERLIB_LOG) << "Unable to find or create edge bound(s) gn1=" << gn1 << "; gn2=" << gn2;
0286         }
0287         ge->setFromNode(gn1);
0288         ge->setToNode(gn2);
0289         //     qCDebug(KGRAPHVIEWERLIB_LOG) << ge->fromNode()->id() << " -> " << ge->toNode()->id();
0290         setedgeattributes();
0291         //     qCDebug(KGRAPHVIEWERLIB_LOG) << ge->id();
0292         if (ge->id().isEmpty()) {
0293             ge->setId(QString::fromStdString(node1Name) + QString::fromStdString(node2Name) + QUuid::createUuid().toString().remove('{').remove('}').remove('-'));
0294         }
0295         //     qCDebug(KGRAPHVIEWERLIB_LOG) << ge->id();
0296         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "num before=" << graph->edges().size();
0297         graph->edges().insert(ge->id(), ge);
0298         //     qCDebug(KGRAPHVIEWERLIB_LOG) << "num after=" << graph->edges().size();
0299 
0300         node1Name = node2Name;
0301     }
0302     edgebounds.clear();
0303 }
0304 
0305 void DotGraphParsingHelper::finalactions()
0306 {
0307     GraphEdgeMap::iterator it, it_end;
0308     it = graph->edges().begin();
0309     it_end = graph->edges().end();
0310     for (; it != it_end; it++) {
0311         (*it)->setZ(maxZ + 1);
0312     }
0313 }
0314 
0315 }