/*************************************************************************** * Copyright (C) 2006-2007 by Rajko Albrecht * * ral@alwins-world.de * * * * 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 2 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "revgraphview.h" #include "graphtreelabel.h" #include "pannerview.h" #include "graphtree_defines.h" #include "src/settings/kdesvnsettings.h" #include "../stopdlg.h" #include "src/svnqt/client.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LABEL_WIDTH 160 #define LABEL_HEIGHT 90 class GraphViewTip:public QToolTip { public: GraphViewTip( QWidget* p ):QToolTip(p) {} virtual ~GraphViewTip(){} protected: void maybeTip( const QPoint & ); }; void GraphViewTip::maybeTip( const QPoint & pos) { if (!parentWidget()->inherits( "RevGraphView" )) return; RevGraphView* cgv = (RevGraphView*)parentWidget(); QPoint cPos = cgv->viewportToContents(pos); QCanvasItemList l = cgv->canvas()->collisions(cPos); if (l.count() == 0) return; QCanvasItem* i = l.first(); if (i->rtti() == GRAPHTREE_LABEL) { GraphTreeLabel*tl = (GraphTreeLabel*)i; QString nm = tl->nodename(); QString tipStr = cgv->toolTip(nm); if (tipStr.length()>0) { QPoint vPosTL = cgv->contentsToViewport(i->boundingRect().topLeft()); QPoint vPosBR = cgv->contentsToViewport(i->boundingRect().bottomRight()); tip(QRect(vPosTL, vPosBR), tipStr); } } } RevGraphView::RevGraphView(QObject*aListener,svn::Client*_client,QWidget * parent, const char * name, WFlags f) : QCanvasView(parent,name,f) { m_Canvas = 0L; m_Client = _client; m_Listener = aListener; dotTmpFile = 0; m_Selected = 0; renderProcess = 0; m_Marker = 0; m_Tip = new GraphViewTip(this); m_CompleteView = new PannerView(this); m_CompleteView->setVScrollBarMode(QScrollView::AlwaysOff); m_CompleteView->setHScrollBarMode(QScrollView::AlwaysOff); m_CompleteView->raise(); m_CompleteView->hide(); connect(this, SIGNAL(contentsMoving(int,int)), this, SLOT(contentsMovingSlot(int,int))); connect(m_CompleteView, SIGNAL(zoomRectMoved(int,int)), this, SLOT(zoomRectMoved(int,int))); connect(m_CompleteView, SIGNAL(zoomRectMoveFinished()), this, SLOT(zoomRectMoveFinished())); m_LastAutoPosition = TopLeft; _isMoving = false; _noUpdateZoomerPos = false; m_LabelMap[""]=""; } RevGraphView::~RevGraphView() { setCanvas(0); delete m_Canvas; delete dotTmpFile; delete m_CompleteView; delete m_Tip; delete renderProcess; } void RevGraphView::showText(const QString&s) { clear(); m_Canvas = new QCanvas(QApplication::desktop()->width(), QApplication::desktop()->height()); QCanvasText* t = new QCanvasText(s, m_Canvas); t->move(5, 5); t->show(); center(0,0); setCanvas(m_Canvas); m_Canvas->update(); m_CompleteView->hide(); } void RevGraphView::clear() { if (m_Selected) { m_Selected->setSelected(false); m_Selected=0; } if (m_Marker) { m_Marker->hide(); delete m_Marker; m_Marker=0; } if (!m_Canvas) return; delete m_Canvas; m_Canvas = 0; setCanvas(0); m_CompleteView->setCanvas(0); } void RevGraphView::beginInsert() { viewport()->setUpdatesEnabled(false); } void RevGraphView::endInsert() { if (m_Canvas) { _cvZoom = 0; updateSizes(); m_Canvas->update(); } viewport()->setUpdatesEnabled(true); } void RevGraphView::readDotOutput(KProcess*,char * buffer,int buflen) { dotOutput+=QString::fromLocal8Bit(buffer, buflen); } void RevGraphView::dotExit(KProcess*p) { if (p!=renderProcess)return; // remove line breaks when lines to long QRegExp endslash("\\\\\\n"); dotOutput.replace(endslash,""); double scale = 1.0, scaleX = 1.0, scaleY = 1.0; double dotWidth, dotHeight; QTextStream* dotStream; dotStream = new QTextStream(dotOutput, IO_ReadOnly); QString line,cmd; int lineno=0; clear(); beginInsert(); /* mostly taken from kcachegrind */ while (1) { line = dotStream->readLine(); if (line.isNull()) break; lineno++; if (line.isEmpty()) continue; QTextStream lineStream(line, IO_ReadOnly); lineStream >> cmd; if (cmd == "stop") {break; } if (cmd == "graph") { lineStream >> scale >> dotWidth >> dotHeight; scaleX = scale * 60; scaleY = scale * 100; int w = (int)(scaleX * dotWidth); int h = (int)(scaleY * dotHeight); _xMargin = 50; if (w < QApplication::desktop()->width()) _xMargin += (QApplication::desktop()->width()-w)/2; _yMargin = 50; if (h < QApplication::desktop()->height()) _yMargin += (QApplication::desktop()->height()-h)/2; m_Canvas = new QCanvas(int(w+2*_xMargin), int(h+2*_yMargin)); continue; } if ((cmd != "node") && (cmd != "edge")) { kdWarning() << "Ignoring unknown command '" << cmd << "' from dot (" << dotTmpFile->name() << ":" << lineno << ")" << endl; continue; } if (cmd=="node") { QString nodeName, label; QString _x,_y,_w,_h; double x, y, width, height; lineStream >> nodeName >> _x >> _y >> _w >> _h; x=_x.toDouble(); y=_y.toDouble(); width=_w.toDouble(); height=_h.toDouble(); // better here 'cause dot may scramble utf8 labels so we regenerate it better // and do not read it in. label = getLabelstring(nodeName); int xx = (int)(scaleX * x + _xMargin); int yy = (int)(scaleY * (dotHeight - y) + _yMargin); int w = (int)(scaleX * width); int h = (int)(scaleY * height); QRect r(xx-w/2, yy-h/2, w, h); GraphTreeLabel*t=new GraphTreeLabel(label,nodeName,r,m_Canvas); if (isStart(nodeName)) { ensureVisible(r.x(),r.y()); } t->setBgColor(getBgColor(nodeName)); t->setZ(1.0); t->show(); m_NodeList[nodeName]=t; } else { QString node1Name, node2Name, label; QString _x,_y; double x, y; QPointArray pa; int points, i; lineStream >> node1Name >> node2Name; lineStream >> points; pa.resize(points); for (i=0;i> _x >> _y; x=_x.toDouble(); y=_y.toDouble(); int xx = (int)(scaleX * x + _xMargin); int yy = (int)(scaleY * (dotHeight - y) + _yMargin); if (0) qDebug(" P %d: ( %f / %f ) => ( %d / %d)", i, x, y, xx, yy); pa.setPoint(i, xx, yy); } if (i < points) { qDebug("CallGraphView: Can't read %d spline points (%d)", points, lineno); continue; } GraphEdge * n = new GraphEdge(m_Canvas); QColor arrowColor = Qt::black; n->setPen(QPen(arrowColor,1)); n->setControlPoints(pa,false); n->setZ(0.5); n->show(); /* arrow */ QPoint arrowDir; int indexHead = -1; QMap::Iterator it; it = m_NodeList.find(node2Name); if (it!=m_NodeList.end()) { it.data()->setSource(node1Name); } it = m_NodeList.find(node1Name); if (it!=m_NodeList.end()) { GraphTreeLabel*tlab = it.data(); if (tlab) { QPoint toCenter = tlab->rect().center(); int dx0 = pa.point(0).x() - toCenter.x(); int dy0 = pa.point(0).y() - toCenter.y(); int dx1 = pa.point(points-1).x() - toCenter.x(); int dy1 = pa.point(points-1).y() - toCenter.y(); if (dx0*dx0+dy0*dy0 > dx1*dx1+dy1*dy1) { // start of spline is nearer to call target node indexHead=-1; while(arrowDir.isNull() && (indexHead1)) { indexHead--; arrowDir = pa.point(indexHead) - pa.point(indexHead-1); } } if (!arrowDir.isNull()) { arrowDir *= 10.0/sqrt(double(arrowDir.x()*arrowDir.x() + arrowDir.y()*arrowDir.y())); QPointArray a(3); a.setPoint(0, pa.point(indexHead) + arrowDir); a.setPoint(1, pa.point(indexHead) + QPoint(arrowDir.y()/2, -arrowDir.x()/2)); a.setPoint(2, pa.point(indexHead) + QPoint(-arrowDir.y()/2, arrowDir.x()/2)); GraphEdgeArrow* aItem = new GraphEdgeArrow(n,m_Canvas); aItem->setPoints(a); aItem->setBrush(arrowColor); aItem->setZ(1.5); aItem->show(); // sItem->setArrow(aItem); } } } if (!m_Canvas) { QString s = i18n("Error running the graph layouting tool.\n"); s += i18n("Please check that 'dot' is installed (package GraphViz)."); showText(s); } else { setCanvas(m_Canvas); m_CompleteView->setCanvas(m_Canvas); } endInsert(); delete p; renderProcess=0; } bool RevGraphView::isStart(const QString&nodeName)const { bool res = false; trevTree::ConstIterator it; it = m_Tree.find(nodeName); if (it==m_Tree.end()) { return res; } switch (it.data().Action) { case 'A': res = true; break; } return res; } char RevGraphView::getAction(const QString&nodeName)const { trevTree::ConstIterator it; it = m_Tree.find(nodeName); if (it==m_Tree.end()) { return (char)0; } return it.data().Action; } QColor RevGraphView::getBgColor(const QString&nodeName)const { trevTree::ConstIterator it; it = m_Tree.find(nodeName); QColor res = Qt::white; if (it==m_Tree.end()) { return res; } switch (it.data().Action) { case 'D': res = Kdesvnsettings::tree_delete_color(); break; case 'R': case 'M': res = Kdesvnsettings::tree_modify_color(); break; case 'A': res = Kdesvnsettings::tree_add_color(); break; case 'C': case 1: res = Kdesvnsettings::tree_copy_color(); break; case 2: res = Kdesvnsettings::tree_rename_color(); break; default: res = Kdesvnsettings::tree_modify_color(); break; } return res; } const QString&RevGraphView::getLabelstring(const QString&nodeName) { QMap::ConstIterator nIt; nIt = m_LabelMap.find(nodeName); if (nIt!=m_LabelMap.end()) { return nIt.data(); } trevTree::ConstIterator it1; it1 = m_Tree.find(nodeName); if (it1==m_Tree.end()) { return m_LabelMap[""]; } QString res; switch (it1.data().Action) { case 'D': res = i18n("Deleted at revision %1").arg(it1.data().rev); break; case 'A': res = i18n("Added at revision %1 as %2") .arg(it1.data().rev) .arg(it1.data().name); break; case 'C': case 1: res = i18n("Copied to %1 at revision %2").arg(it1.data().name).arg(it1.data().rev); break; case 2: res = i18n("Renamed to %1 at revision %2").arg(it1.data().name).arg(it1.data().rev); break; case 'M': res = i18n("Modified at revision %1").arg(it1.data().rev); break; case 'R': res = i18n("Replaced at revision %1").arg(it1.data().rev); break; default: res=i18n("Revision %1").arg(it1.data().rev); break; } m_LabelMap[nodeName]=res; return m_LabelMap[nodeName]; } void RevGraphView::dumpRevtree() { delete dotTmpFile; clear(); dotOutput = ""; dotTmpFile = new KTempFile(QString::null,".dot"); dotTmpFile->setAutoDelete(true); QTextStream* stream = dotTmpFile->textStream(); if (!stream) { showText(i18n("Could not open tempfile %1 for writing.").arg(dotTmpFile->name())); return; } *stream << "digraph \"callgraph\" {\n"; *stream << " bgcolor=\"transparent\";\n"; int dir = Kdesvnsettings::tree_direction(); *stream << QString(" rankdir=\""); switch (dir) { case 3: *stream << "TB"; break; case 2: *stream << "RL"; break; case 1: *stream << "BT"; break; case 0: default: *stream << "LR"; break; } *stream << "\";\n"; //*stream << QString(" overlap=false;\n splines=true;\n"); RevGraphView::trevTree::ConstIterator it1; for (it1=m_Tree.begin();it1!=m_Tree.end();++it1) { *stream << " " << it1.key() << "[ " << "shape=box, " << "label=\""<"<<" "<setEnvironment("LANG","C"); *renderProcess << "dot"; *renderProcess << dotTmpFile->name() << "-Tplain"; connect(renderProcess,SIGNAL(processExited(KProcess*)),this,SLOT(dotExit(KProcess*))); connect(renderProcess,SIGNAL(receivedStdout(KProcess*,char*,int)), this,SLOT(readDotOutput(KProcess*,char*,int)) ); if (!renderProcess->start(KProcess::NotifyOnExit,KProcess::Stdout)) { QString arguments; for (unsigned c=0;cargs().count();++c) { arguments+=QString(" %1").arg(renderProcess->args()[c]); } QString error = i18n("Could not start process \"%1\".").arg(arguments); showText(error); renderProcess=0; //delete renderProcess;< } } QString RevGraphView::toolTip(const QString&_nodename,bool full)const { QString res = QString::null; trevTree::ConstIterator it; it = m_Tree.find(_nodename); if (it==m_Tree.end()) { return res; } QStringList sp = QStringList::split("\n",it.data().Message); QString sm; if (sp.count()==0) { sm = it.data().Message; } else { if (!full) { sm = sp[0]+"..."; } else { for (unsigned j = 0; j0) sm+="
"; sm+=sp[j]; } } } if (!full && sm.length()>50) { sm.truncate(47); sm+="..."; } static QString csep = ""; static QString rend = ""; static QString rstart = ""; res = QString(""); if (!full) { res+=QString("%1").arg(it.data().name); res += i18n("
Revision: %1
Author: %2
Date: %3
Log: %4") .arg(it.data().rev) .arg(it.data().Author) .arg(it.data().Date) .arg(sm); } else { res+=""; res+=rstart; res+=i18n("Revision%1%2%3").arg(csep).arg(it.data().rev).arg(rend); res+=rstart+i18n("Author%1%2%3").arg(csep).arg(it.data().Author).arg(rend); res+=rstart+i18n("Date%1%2%3").arg(csep).arg(it.data().Date).arg(rend); res+=rstart+i18n("Log%1%2%3").arg(csep).arg(sm).arg(rend); res+="
"+it.data().name+"
"; } return res; } void RevGraphView::updateSizes(QSize s) { if (!m_Canvas) return; if (s == QSize(0,0)) s = size(); // the part of the canvas that should be visible int cWidth = m_Canvas->width() - 2*_xMargin + 100; int cHeight = m_Canvas->height() - 2*_yMargin + 100; // hide birds eye view if no overview needed if (((cWidth < s.width()) && cHeight < s.height())||m_NodeList.count()==0) { m_CompleteView->hide(); return; } m_CompleteView->show(); // first, assume use of 1/3 of width/height (possible larger) double zoom = .33 * s.width() / cWidth; if (zoom * cHeight < .33 * s.height()) zoom = .33 * s.height() / cHeight; // fit to widget size if (cWidth * zoom > s.width()) zoom = s.width() / (double)cWidth; if (cHeight * zoom > s.height()) zoom = s.height() / (double)cHeight; // scale to never use full height/width zoom = zoom * 3/4; // at most a zoom of 1/3 if (zoom > .33) zoom = .33; if (zoom != _cvZoom) { _cvZoom = zoom; if (0) qDebug("Canvas Size: %dx%d, Visible: %dx%d, Zoom: %f", m_Canvas->width(), m_Canvas->height(), cWidth, cHeight, zoom); QWMatrix wm; wm.scale( zoom, zoom ); m_CompleteView->setWorldMatrix(wm); // make it a little bigger to compensate for widget frame m_CompleteView->resize(int(cWidth * zoom) + 4, int(cHeight * zoom) + 4); // update ZoomRect in completeView contentsMovingSlot(contentsX(), contentsY()); } m_CompleteView->setContentsPos(int(zoom*(_xMargin-50)), int(zoom*(_yMargin-50))); updateZoomerPos(); } void RevGraphView::updateZoomerPos() { int cvW = m_CompleteView->width(); int cvH = m_CompleteView->height(); int x = width()- cvW - verticalScrollBar()->width() -2; int y = height()-cvH - horizontalScrollBar()->height() -2; QPoint oldZoomPos = m_CompleteView->pos(); QPoint newZoomPos = QPoint(0,0); #if 0 ZoomPosition zp = _zoomPosition; if (zp == Auto) { #else ZoomPosition zp = m_LastAutoPosition; #endif QPoint tl1Pos = viewportToContents(QPoint(0,0)); QPoint tl2Pos = viewportToContents(QPoint(cvW,cvH)); QPoint tr1Pos = viewportToContents(QPoint(x,0)); QPoint tr2Pos = viewportToContents(QPoint(x+cvW,cvH)); QPoint bl1Pos = viewportToContents(QPoint(0,y)); QPoint bl2Pos = viewportToContents(QPoint(cvW,y+cvH)); QPoint br1Pos = viewportToContents(QPoint(x,y)); QPoint br2Pos = viewportToContents(QPoint(x+cvW,y+cvH)); int tlCols = m_Canvas->collisions(QRect(tl1Pos,tl2Pos)).count(); int trCols = m_Canvas->collisions(QRect(tr1Pos,tr2Pos)).count(); int blCols = m_Canvas->collisions(QRect(bl1Pos,bl2Pos)).count(); int brCols = m_Canvas->collisions(QRect(br1Pos,br2Pos)).count(); int minCols = tlCols; zp = m_LastAutoPosition; switch(zp) { case TopRight: minCols = trCols; break; case BottomLeft: minCols = blCols; break; case BottomRight: minCols = brCols; break; default: case TopLeft: minCols = tlCols; break; } if (minCols > tlCols) { minCols = tlCols; zp = TopLeft; } if (minCols > trCols) { minCols = trCols; zp = TopRight; } if (minCols > blCols) { minCols = blCols; zp = BottomLeft; } if (minCols > brCols) { minCols = brCols; zp = BottomRight; } m_LastAutoPosition = zp; #if 0 } #endif switch(zp) { case TopRight: newZoomPos = QPoint(x,0); break; case BottomLeft: newZoomPos = QPoint(0,y); break; case BottomRight: newZoomPos = QPoint(x,y); break; default: break; } if (newZoomPos != oldZoomPos) m_CompleteView->move(newZoomPos); } void RevGraphView::contentsMovingSlot(int x,int y) { QRect z(int(x * _cvZoom), int(y * _cvZoom), int(visibleWidth() * _cvZoom)-1, int(visibleHeight() * _cvZoom)-1); if (0) qDebug("moving: (%d,%d) => (%d/%d - %dx%d)", x, y, z.x(), z.y(), z.width(), z.height()); m_CompleteView->setZoomRect(z); if (!_noUpdateZoomerPos) { updateZoomerPos(); } } void RevGraphView::zoomRectMoved(int dx,int dy) { if (leftMargin()>0) dx = 0; if (topMargin()>0) dy = 0; _noUpdateZoomerPos = true; scrollBy(int(dx/_cvZoom),int(dy/_cvZoom)); _noUpdateZoomerPos = false; } void RevGraphView::zoomRectMoveFinished() { #if 0 if (_zoomPosition == Auto) #endif updateZoomerPos(); } void RevGraphView::resizeEvent(QResizeEvent*e) { QCanvasView::resizeEvent(e); if (m_Canvas) updateSizes(e->size()); } void RevGraphView::makeSelected(GraphTreeLabel*gtl) { if (m_Selected) { m_Selected->setSelected(false); } m_Selected=gtl; if (m_Marker) { m_Marker->hide(); delete m_Marker; m_Marker=0; } if (gtl) { m_Marker = new GraphMark(gtl,m_Canvas); m_Marker->setZ(-1); m_Marker->show(); m_Selected->setSelected(true); } m_Canvas->update(); m_CompleteView->updateCurrentRect(); } void RevGraphView::contentsMouseDoubleClickEvent ( QMouseEvent * e ) { setFocus(); if (e->button() == Qt::LeftButton) { QCanvasItemList l = canvas()->collisions(e->pos()); if (l.count()>0) { QCanvasItem* i = l.first(); if (i->rtti()==GRAPHTREE_LABEL) { makeSelected( (GraphTreeLabel*)i); emit dispDetails(toolTip(((GraphTreeLabel*)i)->nodename(),true)); } } } } void RevGraphView::contentsMousePressEvent ( QMouseEvent * e ) { setFocus(); _isMoving = true; _lastPos = e->globalPos(); } void RevGraphView::contentsMouseReleaseEvent ( QMouseEvent * ) { _isMoving = false; updateZoomerPos(); } void RevGraphView::contentsMouseMoveEvent ( QMouseEvent * e ) { if (_isMoving) { int dx = e->globalPos().x() - _lastPos.x(); int dy = e->globalPos().y() - _lastPos.y(); _noUpdateZoomerPos = true; scrollBy(-dx, -dy); _noUpdateZoomerPos = false; _lastPos = e->globalPos(); } } void RevGraphView::setNewDirection(int dir) { if (dir<0)dir=3; else if (dir>3)dir=0; Kdesvnsettings::setTree_direction(dir); dumpRevtree(); } void RevGraphView::contentsContextMenuEvent(QContextMenuEvent* e) { if (!m_Canvas) return; QCanvasItemList l = canvas()->collisions(e->pos()); QCanvasItem* i = (l.count() == 0) ? 0 : l.first(); QPopupMenu popup; if (i && i->rtti()==GRAPHTREE_LABEL) { if (!((GraphTreeLabel*)i)->source().isEmpty() && getAction(((GraphTreeLabel*)i)->nodename())!='D') { popup.insertItem(i18n("Diff to previous"),301); } if (m_Selected && m_Selected != i && getAction(m_Selected->nodename())!='D' && getAction(((GraphTreeLabel*)i)->nodename())!='D') { popup.insertItem(i18n("Diff to selected item"),302); } if (getAction(((GraphTreeLabel*)i)->nodename())!='D') { popup.insertItem(i18n("Cat this version"),303); } if (m_Selected == i) { popup.insertItem(i18n("Unselect item"),401); } else { popup.insertItem(i18n("Select item"),402); } popup.insertSeparator(); popup.insertItem(i18n("Display details"),403); popup.insertSeparator(); } popup.insertItem(i18n("Rotate counter-clockwise"),101); popup.insertItem(i18n("Rotate clockwise"),102); popup.insertSeparator(); int it = popup.insertItem(i18n("Diff in revisiontree is recursive"),202); popup.setCheckable(true); popup.setItemChecked(it,Kdesvnsettings::tree_diff_rec()); popup.insertItem(i18n("Save tree as png"),201); int r = popup.exec(e->globalPos()); switch (r) { case 101: { int dir = Kdesvnsettings::tree_direction(); setNewDirection(++dir); } break; case 102: { int dir = Kdesvnsettings::tree_direction(); setNewDirection(--dir); } break; case 201: { QString fn = KFileDialog::getSaveFileName(":","*.png"); if (!fn.isEmpty()) { if (m_Marker) { m_Marker->hide(); } if (m_Selected) { m_Selected->setSelected(false); } QPixmap pix(m_Canvas->size()); QPainter p(&pix); m_Canvas->drawArea( m_Canvas->rect(), &p ); pix.save(fn,"PNG"); if (m_Marker) { m_Marker->show(); } if (m_Selected) { m_Selected->setSelected(true); m_Canvas->update(); m_CompleteView->updateCurrentRect(); } } } case 202: { Kdesvnsettings::setTree_diff_rec(!Kdesvnsettings::tree_diff_rec()); break; } break; case 301: if (i && i->rtti()==GRAPHTREE_LABEL && !((GraphTreeLabel*)i)->source().isEmpty()) { makeDiffPrev((GraphTreeLabel*)i); } break; case 302: if (i && i->rtti()==GRAPHTREE_LABEL && m_Selected) { makeDiff(((GraphTreeLabel*)i)->nodename(),m_Selected->nodename()); } break; case 303: if (i && i->rtti()==GRAPHTREE_LABEL) { makeCat((GraphTreeLabel*)i); } break; case 401: makeSelected(0); break; case 402: makeSelected((GraphTreeLabel*)i); break; case 403: emit dispDetails(toolTip(((GraphTreeLabel*)i)->nodename(),true)); break; default: break; } } void RevGraphView::makeCat(GraphTreeLabel*_l) { if (!_l) { return; } QString n1 = _l->nodename(); trevTree::ConstIterator it = m_Tree.find(n1); if (it==m_Tree.end()) { return; } svn::Revision tr(it.data().rev); QString tp = _basePath+it.data().name; emit makeCat(tr,tp,it.data().name,tr,kapp->activeModalWidget()); } void RevGraphView::makeDiffPrev(GraphTreeLabel*_l) { if (!_l) return; QString n1,n2; n1 = _l->nodename(); n2 = _l->source(); makeDiff(n1,n2); } void RevGraphView::makeDiff(const QString&n1,const QString&n2) { if (n1.isEmpty()||n2.isEmpty()) return; trevTree::ConstIterator it; it = m_Tree.find(n2); if (it==m_Tree.end()) { return; } svn::Revision sr(it.data().rev); QString sp = _basePath+it.data().name; it = m_Tree.find(n1); if (it==m_Tree.end()) { return; } svn::Revision tr(it.data().rev); QString tp = _basePath+it.data().name; if (Kdesvnsettings::tree_diff_rec()) { emit makeRecDiff(sp,sr,tp,tr,kapp->activeModalWidget()); } else { emit makeNorecDiff(sp,sr,tp,tr,kapp->activeModalWidget()); } } void RevGraphView::setBasePath(const QString&_path) { _basePath = _path; } void RevGraphView::slotClientException(const QString&what) { KMessageBox::sorry(KApplication::activeModalWidget(),what,i18n("SVN Error")); } #include "revgraphview.moc"