KDevelop API Documentation

parts/classview/digraphview.cpp

Go to the documentation of this file.
00001 /*************************************************************************** 00002 * Copyright (C) 2001 by Bernd Gehrmann * 00003 * bernd@kdevelop.org * 00004 * * 00005 * This program is free software; you can redistribute it and/or modify * 00006 * it under the terms of the GNU General Public License as published by * 00007 * the Free Software Foundation; either version 2 of the License, or * 00008 * (at your option) any later version. * 00009 * * 00010 ***************************************************************************/ 00011 00012 #include "digraphview.h" 00013 00014 #include <math.h> 00015 #include <stdlib.h> 00016 #include <qapplication.h> 00017 #include <qpainter.h> 00018 #include <qpaintdevicemetrics.h> 00019 #include <qtextstream.h> 00020 #include <kglobal.h> 00021 #include <klocale.h> 00022 #include <kmessagebox.h> 00023 #include <kprocess.h> 00024 #include <kstandarddirs.h> 00025 #include <kglobalsettings.h> 00026 #include <ktempfile.h> 00027 #include <kdeversion.h> 00028 00029 struct DigraphNode 00030 { 00031 int x; 00032 int y; 00033 int w; 00034 int h; 00035 QString name; 00036 }; 00037 00038 00039 struct DigraphEdge 00040 { 00041 QPointArray points; 00042 }; 00043 00044 00045 DigraphView::DigraphView(QWidget *parent, const char *name) 00046 : QScrollView(parent, name, WRepaintNoErase|WStaticContents|WResizeNoErase) 00047 { 00048 viewport()->setBackgroundMode(PaletteBase); 00049 00050 QPaintDeviceMetrics m(this); 00051 xscale = m.logicalDpiX(); 00052 yscale = m.logicalDpiY(); 00053 00054 width = -1; 00055 height = -1; 00056 00057 nodes.setAutoDelete(true); 00058 edges.setAutoDelete(true); 00059 selNode = 0; 00060 } 00061 00062 00063 DigraphView::~DigraphView() 00064 { 00065 } 00066 00067 00068 int DigraphView::toXPixel(double x) 00069 { 00070 return (int) (x*xscale); 00071 } 00072 00073 00074 int DigraphView::toYPixel(double y) 00075 { 00076 return height - (int) (y*yscale); 00077 } 00078 00079 00080 void DigraphView::setRenderedExtent(double w, double h) 00081 { 00082 width = (int) (w*xscale); 00083 height = (int) (h*yscale); 00084 resizeContents(width+1, height+1); 00085 } 00086 00087 00088 void DigraphView::addRenderedNode(const QString &name, 00089 double x, double y, double w, double h) 00090 { 00091 DigraphNode *node = new DigraphNode; 00092 node->x = toXPixel(x); 00093 node->y = toYPixel(y); 00094 node->w = (int) (w*xscale); 00095 node->h = (int) (h*yscale); 00096 node->name = name; 00097 nodes.append(node); 00098 } 00099 00100 00101 void DigraphView::addRenderedEdge(const QString &/*name1*/, const QString &/*name2*/, 00102 QMemArray<double> coords) 00103 { 00104 if (coords.count() < 4) 00105 return; 00106 00107 DigraphEdge *edge = new DigraphEdge; 00108 edge->points.resize(coords.count()/2); 00109 00110 for (uint i = 0; i < edge->points.count(); ++i) 00111 edge->points[i] = QPoint(toXPixel(coords[2*i]), toYPixel(coords[2*i+1])); 00112 00113 edges.append(edge); 00114 } 00115 00116 00117 void DigraphView::addEdge(const QString &name1, const QString &name2) 00118 { 00119 QString line; 00120 line = "\""; 00121 line += name1; 00122 line += "\" -> \""; 00123 line += name2; 00124 line += "\";"; 00125 inputs.append(line); 00126 } 00127 00128 00129 void DigraphView::clear() 00130 { 00131 nodes.clear(); 00132 edges.clear(); 00133 selNode = 0; 00134 viewport()->update(); 00135 } 00136 00137 00138 void DigraphView::setSelected(const QString &name) 00139 { 00140 QPtrListIterator<DigraphNode> it(nodes); 00141 for (; it.current(); ++it) { 00142 if (it.current()->name == name) { 00143 updateContents(selNode->x-selNode->w/2, selNode->y-selNode->h/2, 00144 selNode->w, selNode->h); 00145 selNode = it.current(); 00146 updateContents(selNode->x-selNode->w/2, selNode->y-selNode->h/2, 00147 selNode->w, selNode->h); 00148 return; 00149 } 00150 } 00151 } 00152 00153 00154 void DigraphView::ensureVisible(const QString &name) 00155 { 00156 QPtrListIterator<DigraphNode> it(nodes); 00157 for (; it.current(); ++it) { 00158 if (it.current()->name == name) { 00159 QScrollView::ensureVisible((*it)->x, (*it)->y, (*it)->w, (*it)->h); 00160 return; 00161 } 00162 } 00163 } 00164 00165 00166 QStringList DigraphView::splitLine(QString str) 00167 { 00168 QStringList result; 00169 00170 while (!str.isEmpty()) { 00171 if (str[0] == '"') { 00172 int pos = str.find('"', 1); 00173 if (pos == -1) 00174 pos = str.length(); 00175 result << str.mid(1, pos-1); 00176 str.remove(0, pos+1); 00177 } else { 00178 int pos = str.find(' '); 00179 if (pos == -1) 00180 pos = str.length(); 00181 result << str.left(pos); 00182 str.remove(0, pos+1); 00183 } 00184 uint i = 0; while (i<str.length() && str[i] == ' ') ++i; 00185 str.remove(0, i); 00186 } 00187 00188 return result; 00189 } 00190 00191 00192 void DigraphView::parseDotResults(const QStringList &list) 00193 { 00194 QStringList::ConstIterator it; 00195 for (it = list.begin(); it != list.end(); ++it) { 00196 QStringList tokens = splitLine(*it); 00197 if (tokens.count() == 0) 00198 continue; 00199 if (tokens[0] == "graph") { 00200 if (tokens.count() < 4) 00201 continue; 00202 setRenderedExtent(tokens[2].toDouble(), tokens[3].toDouble()); 00203 } else if (tokens[0] == "node") { 00204 if (tokens.count() < 6) 00205 continue; 00206 addRenderedNode(tokens[1], tokens[2].toDouble(), tokens[3].toDouble(), 00207 tokens[4].toDouble(), tokens[5].toDouble()); 00208 } else if (tokens[0] == "edge") { 00209 if (tokens.count() < 8) 00210 continue; 00211 QMemArray<double> coords(tokens.count()-6); 00212 for (uint i=0; i != tokens.count()-6; ++i) 00213 coords[i] = tokens[i+4].toDouble(); 00214 addRenderedEdge(tokens[1], tokens[2], coords); 00215 } 00216 } 00217 } 00218 00219 00220 void DigraphView::process() 00221 { 00222 QString cmd = KGlobal::dirs()->findExe("dot"); 00223 if (cmd.isEmpty()) { 00224 KMessageBox::sorry(0, i18n("You don't have 'dot' installed.\nIt can be downloaded from www.graphviz.org.")); 00225 return; 00226 } 00227 00228 QStringList results; 00229 00230 KTempFile ifile, ofile; 00231 QTextStream &is = *ifile.textStream(); 00232 is << "digraph G {" << endl; 00233 is << "rankdir=LR;" << endl; 00234 is << "node [shape=box,fontname=Helvetica,fontsize=12];" << endl; 00235 QStringList::Iterator it; 00236 for (it = inputs.begin(); it != inputs.end(); ++it) 00237 is << (*it) << endl; 00238 is << "}" << endl; 00239 ifile.close(); 00240 00241 KProcess proc; 00242 proc << cmd << "-Tplain" << ifile.name() << "-o" << ofile.name(); 00243 proc.start(KProcess::Block); 00244 00245 QTextStream &os = *ofile.textStream(); 00246 while (!os.atEnd()) 00247 results << os.readLine(); 00248 ofile.close(); 00249 00250 parseDotResults(results); 00251 inputs.clear(); 00252 00253 if (nodes.first()) 00254 selNode = nodes.first(); 00255 viewport()->update(); 00256 } 00257 00258 00259 void DigraphView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph) 00260 { 00261 QRect clipRect(clipx, clipy, clipw, cliph); 00262 p->eraseRect(clipRect); 00263 00264 p->setFont(KGlobalSettings::generalFont()); 00265 QPtrListIterator<DigraphNode> it1(nodes); 00266 for (; it1.current(); ++it1) { 00267 QRect r((*it1)->x-(*it1)->w/2, (*it1)->y-(*it1)->h/2, (*it1)->w, (*it1)->h); 00268 if (r.intersects(clipRect)) { 00269 if (it1.current() == selNode) 00270 p->fillRect(r, QBrush(lightGray, SolidPattern)); 00271 else 00272 p->drawRect(r); 00273 p->drawText(r, AlignCenter, (*it1)->name); 00274 } 00275 } 00276 p->setBrush(QBrush(black, SolidPattern)); 00277 QPtrListIterator<DigraphEdge> it2(edges); 00278 for (; it2.current(); ++it2) { 00279 int n = (*it2)->points.count(); 00280 for (int i=0; i+3 < n; i+=3) 00281 { 00282 QPointArray a(4); 00283 QPointArray &b = (*it2)->points; 00284 for (int j=0; j<4; ++j) 00285 a.setPoint(j, b.point(i+j)); 00286 if (a.boundingRect().intersects(clipRect)) 00287 p->drawCubicBezier((*it2)->points, i); 00288 } 00289 QPoint p1 = (*it2)->points[n-2]; 00290 QPoint p2 = (*it2)->points[n-1]; 00291 QPoint d = p1-p2; 00292 double l = sqrt(d.x()*d.x()+d.y()*d.y()); 00293 double d11 = (10.0)/l*d.x(); 00294 double d12 = (10.0)/l*d.y(); 00295 double d21 = -(3.0/l)*d.y(); 00296 double d22 = (3.0/l)*d.x(); 00297 QPointArray triangle(3); 00298 triangle[0] = p2 + QPoint((int)(d11+d21),(int)(d12+d22)); 00299 triangle[1] = p2 + QPoint((int)(d11-d21),(int)(d12-d22)); 00300 triangle[2] = p2; 00301 p->drawPolygon(triangle, true); 00302 } 00303 } 00304 00305 00306 void DigraphView::contentsMousePressEvent(QMouseEvent *e) 00307 { 00308 QPtrListIterator<DigraphNode> it1(nodes); 00309 for (; it1.current(); ++it1) { 00310 QRect r((*it1)->x-(*it1)->w/2, (*it1)->y-(*it1)->h/2, (*it1)->w, (*it1)->h); 00311 if (r.contains(e->pos())) { 00312 if (selNode) { 00313 QRect oldr(selNode->x-selNode->w/2, selNode->y-selNode->h/2, 00314 selNode->w, selNode->h); 00315 updateContents(oldr); 00316 } 00317 selNode = it1.current(); 00318 emit selected(selNode->name); 00319 updateContents(r); 00320 } 00321 00322 } 00323 } 00324 00325 00326 QSize DigraphView::sizeHint() const 00327 { 00328 if (width == -1) 00329 return QSize(100, 100); // arbitrary 00330 00331 #if defined(KDE_IS_VERSION) 00332 #if (KDE_IS_VERSION(3,1,90)) 00333 QSize dsize = KGlobalSettings::desktopGeometry(viewport()).size(); 00334 #else 00335 QSize dsize = QApplication::desktop()->size(); 00336 #endif 00337 #else 00338 QSize dsize = QApplication::desktop()->size(); 00339 #endif 00340 return QSize(width, height).boundedTo(QSize(dsize.width()*2/3, dsize.height()*2/3)); 00341 } 00342 00343 00344 #if 0 00345 int main(int argc, char **argv) 00346 { 00347 QApplication app(argc, argv); 00348 00349 DigraphView *dw = new DigraphView(0, "dot widget"); 00350 dw->addEdge( "5th Edition", "6th Edition"); 00351 dw->addEdge( "5th Edition", "PWB 1.0"); 00352 dw->addEdge( "6th Edition", "LSX"); 00353 dw->addEdge( "6th Edition", "1 BSD"); 00354 dw->addEdge( "6th Edition", "Mini Unix"); 00355 dw->addEdge( "6th Edition", "Wollongong"); 00356 dw->addEdge( "6th Edition", "Interdata"); 00357 dw->addEdge( "Interdata", "Unix/TS 3.0"); 00358 dw->addEdge( "Interdata", "PWB 2.0"); 00359 dw->addEdge( "Interdata", "7th Edition"); 00360 dw->addEdge( "7th Edition", "8th Edition"); 00361 dw->addEdge( "7th Edition", "32V"); 00362 dw->addEdge( "7th Edition", "V7M"); 00363 dw->addEdge( "7th Edition", "Ultrix-11"); 00364 dw->addEdge( "7th Edition", "Xenix"); 00365 dw->addEdge( "7th Edition", "UniPlus+"); 00366 dw->addEdge( "V7M", "Ultrix-11"); 00367 dw->addEdge( "8th Edition", "9th Edition"); 00368 dw->addEdge( "1 BSD", "2 BSD"); 00369 dw->addEdge( "2 BSD", "2.8 BSD"); 00370 dw->addEdge( "2.8 BSD", "Ultrix-11"); 00371 dw->addEdge( "2.8 BSD", "2.9 BSD"); 00372 dw->addEdge( "32V", "3 BSD"); 00373 dw->addEdge( "3 BSD", "4 BSD"); 00374 dw->addEdge( "4 BSD", "4.1 BSD"); 00375 dw->addEdge( "4.1 BSD", "4.2 BSD"); 00376 dw->addEdge( "4.1 BSD", "2.8 BSD"); 00377 dw->addEdge( "4.1 BSD", "8th Edition"); 00378 dw->addEdge( "4.2 BSD", "4.3 BSD"); 00379 dw->addEdge( "4.2 BSD", "Ultrix-32"); 00380 dw->addEdge( "PWB 1.0", "PWB 1.2"); 00381 dw->addEdge( "PWB 1.0", "USG 1.0"); 00382 dw->addEdge( "PWB 1.2", "PWB 2.0"); 00383 dw->addEdge( "USG 1.0", "CB Unix 1"); 00384 dw->addEdge( "USG 1.0", "USG 2.0"); 00385 dw->addEdge( "CB Unix 1", "CB Unix 2"); 00386 dw->addEdge( "CB Unix 2", "CB Unix 3"); 00387 dw->addEdge( "CB Unix 3", "Unix/TS++"); 00388 dw->addEdge( "CB Unix 3", "PDP-11 Sys V"); 00389 dw->addEdge( "USG 2.0", "USG 3.0"); 00390 dw->addEdge( "USG 3.0", "Unix/TS 3.0"); 00391 dw->addEdge( "PWB 2.0", "Unix/TS 3.0"); 00392 dw->addEdge( "Unix/TS 1.0", "Unix/TS 3.0"); 00393 dw->addEdge( "Unix/TS 3.0", "TS 4.0"); 00394 dw->addEdge( "Unix/TS++", "TS 4.0"); 00395 dw->addEdge( "CB Unix 3", "TS 4.0"); 00396 dw->addEdge( "TS 4.0", "System V.0"); 00397 dw->addEdge( "System V.0", "System V.2"); 00398 dw->addEdge( "System V.2", "System V.3"); 00399 dw->process(); 00400 dw->show(); 00401 00402 return app.exec(); 00403 } 00404 #endif 00405 00406 #include "digraphview.moc"
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:39:10 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003