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"