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

0001 /* This file is part of KGraphViewer.
0002    Copyright (C) 2005 Gaƫl 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 /*
0020  * Graph Subgraph
0021  */
0022 
0023 #include "graphsubgraph.h"
0024 #include "canvassubgraph.h"
0025 #include "dotdefaults.h"
0026 #include "graphnode.h"
0027 #include "kgraphviewerlib_debug.h"
0028 
0029 #include <QDebug>
0030 
0031 namespace KGraphViewer
0032 {
0033 //
0034 // GraphSubgraph
0035 //
0036 
0037 GraphSubgraph::GraphSubgraph()
0038     : GraphElement()
0039     , m_content()
0040 {
0041 }
0042 
0043 GraphSubgraph::GraphSubgraph(graph_t *sg)
0044     : GraphElement()
0045     , m_content()
0046 {
0047     updateWithSubgraph(sg);
0048 }
0049 
0050 void GraphSubgraph::updateWithSubgraph(const GraphSubgraph &subgraph)
0051 {
0052     qCDebug(KGRAPHVIEWERLIB_LOG) << id() << subgraph.id();
0053     GraphElement::updateWithElement(subgraph);
0054 
0055     bool found = false;
0056     for (GraphElement *updatingge : subgraph.content()) {
0057         for (GraphElement *ge : content()) {
0058             if (ge->id() == updatingge->id()) {
0059                 found = true;
0060                 if (dynamic_cast<GraphNode *>(ge)) {
0061                     dynamic_cast<GraphNode *>(ge)->updateWithNode(*dynamic_cast<GraphNode *>(updatingge));
0062                     //     qCDebug(KGRAPHVIEWERLIB_LOG) << "node " << ngn->id();
0063                 } else if (dynamic_cast<GraphSubgraph *>(ge)) {
0064                     dynamic_cast<GraphSubgraph *>(ge)->updateWithSubgraph(*dynamic_cast<GraphSubgraph *>(updatingge));
0065                 } else {
0066                     qCWarning(KGRAPHVIEWERLIB_LOG) << "Updated element is neither a node nor a subgraph";
0067                 }
0068                 break;
0069             }
0070         }
0071         if (!found) {
0072             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "new";
0073             if (dynamic_cast<GraphNode *>(updatingge)) {
0074                 GraphNode *newgn = new GraphNode(*dynamic_cast<GraphNode *>(updatingge));
0075                 //       qCDebug(KGRAPHVIEWERLIB_LOG) << "new created";
0076                 content().push_back(newgn);
0077                 //       qCDebug(KGRAPHVIEWERLIB_LOG) << "new inserted";
0078             } else if (dynamic_cast<GraphSubgraph *>(updatingge)) {
0079                 GraphSubgraph *newsg = new GraphSubgraph(*dynamic_cast<GraphSubgraph *>(updatingge));
0080                 content().push_back(newsg);
0081             }
0082         }
0083     }
0084 
0085     if (canvasSubgraph()) {
0086         canvasSubgraph()->modelChanged();
0087         canvasSubgraph()->computeBoundingRect();
0088     }
0089     //   qCDebug(KGRAPHVIEWERLIB_LOG) << "done";
0090 }
0091 
0092 void GraphSubgraph::updateWithSubgraph(graph_t *subgraph)
0093 {
0094     qCDebug(KGRAPHVIEWERLIB_LOG) << agnameof(subgraph);
0095     m_attributes["id"] = agnameof(subgraph);
0096     if (GD_label(subgraph))
0097         m_attributes["label"] = GD_label(subgraph)->text;
0098 
0099     DotRenderOpVec ops;
0100     // decrease mem peak
0101     setRenderOperations(ops);
0102 
0103     if (agget(subgraph, (char *)"_draw_")) {
0104         parse_renderop(agget(subgraph, (char *)"_draw_"), ops);
0105         qCDebug(KGRAPHVIEWERLIB_LOG) << "_draw_: element renderOperations size is now " << ops.size();
0106     }
0107     if (agget(subgraph, (char *)"_ldraw_")) {
0108         parse_renderop(agget(subgraph, (char *)"_ldraw_"), ops);
0109         qCDebug(KGRAPHVIEWERLIB_LOG) << "_ldraw_: element renderOperations size is now " << ops.size();
0110     }
0111 
0112     setRenderOperations(ops);
0113 
0114     Agsym_t *attr = agnxtattr(subgraph, AGRAPH, nullptr);
0115     while (attr) {
0116         qCDebug(KGRAPHVIEWERLIB_LOG) << agnameof(subgraph) << ":" << attr->name << agxget(subgraph, attr);
0117         m_attributes[attr->name] = agxget(subgraph, attr);
0118         attr = agnxtattr(subgraph, AGRAPH, attr);
0119     }
0120 
0121     for (graph_t *sg = agfstsubg(subgraph); sg; sg = agnxtsubg(sg)) {
0122         qCDebug(KGRAPHVIEWERLIB_LOG) << "subsubgraph:" << agnameof(sg);
0123         if (subgraphs().contains(agnameof(sg))) {
0124             qCDebug(KGRAPHVIEWERLIB_LOG) << "known subsubgraph";
0125             // ???
0126             //       nodes()[ngn->name]->setZ(ngn->z());
0127             subgraphs()[agnameof(sg)]->updateWithSubgraph(sg);
0128             if (subgraphs()[agnameof(sg)]->canvasElement()) {
0129                 //         nodes()[ngn->id()]->canvasElement()->setGh(m_height);
0130             }
0131         } else {
0132             qCDebug(KGRAPHVIEWERLIB_LOG) << "new subsubgraph";
0133             GraphSubgraph *newsg = new GraphSubgraph(sg);
0134             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "new created";
0135             subgraphs().insert(agnameof(sg), newsg);
0136             //       qCDebug(KGRAPHVIEWERLIB_LOG) << "new inserted";
0137         }
0138     }
0139 }
0140 
0141 QString GraphSubgraph::backColor() const
0142 {
0143     if (m_attributes.find("bgcolor") != m_attributes.end()) {
0144         return m_attributes["bgcolor"];
0145     } else if ((m_attributes.find("style") != m_attributes.end()) && (m_attributes["style"] == "filled") && (m_attributes.find("color") != m_attributes.end())) {
0146         return m_attributes["color"];
0147     } else if ((m_attributes.find("style") != m_attributes.end()) && (m_attributes["style"] == "filled") && (m_attributes.find("fillcolor") != m_attributes.end())) {
0148         return m_attributes["fillcolor"];
0149     } else {
0150         return DOT_DEFAULT_BACKCOLOR;
0151     }
0152 }
0153 
0154 void GraphSubgraph::removeElement(GraphElement *element)
0155 {
0156     m_content.removeAll(element);
0157 }
0158 
0159 GraphElement *GraphSubgraph::elementNamed(const QString &id)
0160 {
0161     if (this->id() == id)
0162         return this;
0163     for (GraphElement *element : content()) {
0164         if (element->id() == id) {
0165             return element;
0166         } else if (dynamic_cast<GraphSubgraph *>(element)) {
0167             GraphElement *subgraphElement = dynamic_cast<GraphSubgraph *>(element)->elementNamed(id);
0168             if (subgraphElement) {
0169                 return subgraphElement;
0170             }
0171         }
0172     }
0173     return nullptr;
0174 }
0175 
0176 bool GraphSubgraph::setElementSelected(GraphElement *element, bool selectValue, bool unselectOthers)
0177 {
0178     if (element)
0179         qCDebug(KGRAPHVIEWERLIB_LOG) << element->id() << selectValue << unselectOthers;
0180     bool res = false;
0181     if (element == this) {
0182         if (isSelected() != selectValue) {
0183             setSelected(selectValue);
0184             canvasElement()->update();
0185         }
0186         res = true;
0187     } else if (isSelected() && unselectOthers) {
0188         setSelected(false);
0189         canvasElement()->update();
0190     }
0191     for (GraphElement *el : content()) {
0192         if (dynamic_cast<GraphSubgraph *>(el)) {
0193             bool subres = dynamic_cast<GraphSubgraph *>(el)->setElementSelected(element, selectValue, unselectOthers);
0194             if (!res)
0195                 res = subres;
0196         } else if (element == el) {
0197             res = true;
0198             if (el->isSelected() != selectValue) {
0199                 el->setSelected(selectValue);
0200                 el->canvasElement()->update();
0201             }
0202         } else {
0203             if (unselectOthers && el->isSelected()) {
0204                 el->setSelected(false);
0205                 el->canvasElement()->update();
0206             }
0207         }
0208     }
0209     return res;
0210 }
0211 
0212 void GraphSubgraph::retrieveSelectedElementsIds(QList<QString> selection)
0213 {
0214     if (isSelected()) {
0215         selection.push_back(id());
0216     }
0217     for (GraphElement *el : content()) {
0218         if (dynamic_cast<GraphSubgraph *>(el)) {
0219             dynamic_cast<GraphSubgraph *>(el)->retrieveSelectedElementsIds(selection);
0220         } else if (el->isSelected()) {
0221             selection.push_back(el->id());
0222         }
0223     }
0224 }
0225 
0226 QTextStream &operator<<(QTextStream &s, const GraphSubgraph &sg)
0227 {
0228     s << "subgraph " << sg.id() << "  {" << Qt::endl << "graph [ " << dynamic_cast<const GraphElement &>(sg) << " ] " << Qt::endl;
0229     for (const GraphElement *el : sg.content()) {
0230         s << *(dynamic_cast<const GraphNode *>(el));
0231     }
0232     s << "}" << Qt::endl;
0233     return s;
0234 }
0235 
0236 }
0237 
0238 #include "moc_graphsubgraph.cpp"