RoseTreeView.cpp

Go to the documentation of this file.
00001 #include "rose.h"
00002 
00003 #include "RoseTreeView.h"
00004 #include "ItemTreeModel.h"
00005 #include "AstFilters.h"
00006 #include "SageMimeData.h"
00007 
00008 #include <QApplication>
00009 #include <QDataStream>
00010 #include <QDragEnterEvent>
00011 #include <QDragMoveEvent>
00012 #include <QDropEvent>
00013 #include <QPainter>
00014 #include <QPaintEvent>
00015 #include <cmath>
00016 
00017 #include <QDebug>
00018 
00019 
00020 RoseTreeView::RoseTreeView(QWidget * par)
00021     : QTreeView(par),
00022       curFilter(NULL),
00023       curNode(NULL),
00024       dragEnabled(true),
00025       dropEnabled(true)
00026 {
00027     setAcceptDrops(true);
00028     viewport()->setAcceptDrops(true);
00029 
00030     model = new ItemTreeModel(this);
00031 
00032     updateModel();
00033 
00034     setModel(model);
00035 
00036     connect(this,SIGNAL(clicked(const QModelIndex &)),
00037                  SLOT(viewClicked(const QModelIndex &)));
00038     connect(this,SIGNAL(doubleClicked(const QModelIndex &)),
00039                  SLOT(viewDoubleClicked(const QModelIndex &)));
00040 
00041 }
00042 
00043 
00044 RoseTreeView::~RoseTreeView()
00045 {
00046 }
00047 
00048 void RoseTreeView::setNode(SgNode * node)
00049 {
00050     curNode = node;
00051     updateModel();
00052 }
00053 
00054 void RoseTreeView::setFilter(AstFilterInterface * filter)
00055 {
00056     if(curFilter)
00057         delete curFilter;
00058 
00059     curFilter = filter->copy();
00060     updateModel();
00061 }
00062 
00063 bool RoseTreeView::gotoNode( SgNode *node )
00064 {
00065     QModelIndex pos( findSgNodeInModel( node, *model, model->index(0,0, QModelIndex() ) ) );
00066 
00067     if( !pos.isValid() )
00068     {
00069         qDebug() << "RoseTreeView::gotoNode - no node found";
00070         return false;
00071     }
00072 
00073     setCurrentIndex( pos );
00074     return true;
00075 }
00076 
00077 void RoseTreeView::viewClicked(const QModelIndex & ind)
00078 {
00079     if(! ind.isValid())
00080         return;
00081 
00082     QVariant nodeAsVariant = model->data(ind,SgNodeRole);
00083     if(!nodeAsVariant.isValid())
00084         return;
00085 
00086     SgNode * node= qvariant_cast<SgNode*>( nodeAsVariant);
00087     if( node == NULL ) return;
00088 
00089     emit nodeActivated(node);
00090 
00091     SgLocatedNode* sgLocNode = isSgLocatedNode(node);
00092     if(sgLocNode)
00093     {
00094         Sg_File_Info* start = sgLocNode->get_startOfConstruct();
00095         Sg_File_Info *end   = sgLocNode->get_endOfConstruct();
00096 
00097         emit clicked(QString(start->get_filenameString().c_str()),
00098                      start->get_line(),
00099                      start->get_col(),
00100                      end->get_line(),
00101                      end->get_col());
00102     }
00103     else
00104         emit clicked(QString(),-1,-1,-1,-1);
00105 }
00106 
00107 
00108 void RoseTreeView::viewDoubleClicked( const QModelIndex & ind )
00109 {
00110     if(! ind.isValid() )
00111         return;
00112 
00113 
00114     QVariant nodeAsVariant = model->data(ind,SgNodeRole);
00115     if(!nodeAsVariant.isValid())
00116         return;
00117 
00118     SgNode * node= qvariant_cast<SgNode*>( nodeAsVariant);
00119     Q_ASSERT(node);
00120     emit nodeActivatedAlt(node);
00121 }
00122 
00123 
00124 
00125 // ------------------------- Drag and Drop Functions --------------------------
00126 
00127 
00128 void RoseTreeView::mousePressEvent(QMouseEvent *ev)
00129 {
00130     if (ev->button() == Qt::LeftButton)
00131         dragStartPosition = ev->pos();
00132 
00133     QTreeView::mousePressEvent(ev);
00134 }
00135 
00136 void RoseTreeView::mouseMoveEvent(QMouseEvent *ev)
00137 {
00138     if(!dragEnabled)
00139         return  QTreeView::mouseMoveEvent(ev);
00140 
00141     if (!(ev->buttons() & Qt::LeftButton))
00142         return QTreeView::mouseMoveEvent(ev);;
00143     if ((ev->pos() - dragStartPosition).manhattanLength() < QApplication::startDragDistance())
00144         return QTreeView::mouseMoveEvent(ev);;
00145 
00146 
00147     // get the SgNode out of the model
00148     QVariant nodeAsVariant = model->data(indexAt(dragStartPosition),SgNodeRole);
00149     if(!nodeAsVariant.isValid())
00150         return  QTreeView::mouseMoveEvent(ev);;
00151     SgNode * node = qvariant_cast<SgNode*>(nodeAsVariant);
00152     if(!node)
00153         return;
00154 
00155     // create drag object, set pixmap and data
00156     QDrag *drag = new QDrag(viewport());
00157     //QMimeData *mimeData = new QMimeData();
00158     QIcon icon = qvariant_cast<QIcon>( model->data(indexAt(dragStartPosition),Qt::DecorationRole));
00159     if(!icon.isNull())
00160         drag->setPixmap(icon.pixmap(16,16));
00161 
00162     //mimeData->setData(SG_NODE_MIMETYPE, d);
00163     drag->setMimeData( createSageMimeData( node ) );
00164     drag->exec();
00165 
00166 
00167 
00168     QTreeView::mouseMoveEvent(ev);
00169 }
00170 
00171 void RoseTreeView::dragEnterEvent(QDragEnterEvent * ev)
00172 {
00173     if( acceptMimeData( ev->mimeData() ) && this != ev->source() )
00174         ev->accept();
00175     else
00176         ev->ignore();
00177 }
00178 
00179 void RoseTreeView::dragMoveEvent(QDragMoveEvent * ev)
00180 {
00181     QWidget::dragMoveEvent(ev);
00182 }
00183 
00184 
00185 void RoseTreeView::dropEvent(QDropEvent *ev)
00186 {
00187     if(ev->source()==this ||  ev->source()== viewport() ||  !dropEnabled )
00188         return;
00189 
00190     handleMimeData( ev->mimeData(), ev->pos() );
00191 
00192     ev->acceptProposedAction();
00193 }
00194 
00195 bool RoseTreeView::acceptMimeData( const QMimeData *mimeData )
00196 {
00197     return mimeData->hasFormat(SG_NODE_MIMETYPE) && dropEnabled ;
00198 }
00199 
00200 void RoseTreeView::handleMimeData( const QMimeData *mimeData, const QPoint& pos )
00201 {
00202     SgNode *node( getGeneralNode( mimeData ) );
00203     emit nodeDropped( node, pos );
00204 }
00205 
00206 
00207 void RoseTreeView::addArrow(const QModelIndex & i1, const QModelIndex & i2)
00208 {
00209     arrows.push_back(qMakePair(i1,i2));
00210     viewport()->update();
00211 }
00212 
00213 void RoseTreeView::removeAllArrows()
00214 {
00215     arrows.clear();
00216     viewport()->update();
00217 }
00218 
00219 
00220 void RoseTreeView::paintEvent(QPaintEvent * pEv)
00221 {
00222     QTreeView::paintEvent(pEv);
00223     QPainter painter(viewport());
00224     painter.setClipRegion(QRegion(QRect(0,0,100000,100000)),Qt::NoClip);
00225     painter.setClipping(false);
00226     QPen pen(Qt::red);
00227     pen.setWidth(3);
00228     painter.setPen(pen);
00229     painter.setBrush(Qt::red);
00230 
00231     painter.setRenderHint(QPainter::Antialiasing,true);
00232 
00233     for(int i=0; i<arrows.size(); i++)
00234     {
00235         QRect r1 = visualRect(arrows[i].first);
00236         QRect r2 = visualRect(arrows[i].second);
00237         QPoint p1=r1.bottomLeft();
00238         QPoint p2=r2.topLeft();
00239 
00240         drawArrowBezier(p1,p2,&painter,-0.3);
00241     }
00242 
00243     //Paint original window
00244     // TODO
00245     //QPaintEvent newPe(QRect(0,0,1000,1000));
00246     //QTreeView::paintEvent(&newPe);
00247 
00248 }
00249 
00250 void RoseTreeView::normalizeVec(QPointF & vec) const
00251 {
00252     float xVal=vec.x();
00253     float yVal=vec.y();
00254     float norm = std::sqrt(xVal*xVal + yVal*yVal);
00255     vec /= norm;
00256 }
00257 
00258 
00259 QPointF RoseTreeView::getOrtho(const QPointF & i, bool direction) const
00260 {
00261     QPointF ret(i.y(), -i.x());
00262     return direction ? ret : -ret;
00263 }
00264 
00265 
00266 void RoseTreeView::drawArrowBezier(const QPoint & p1, const QPoint & p2, QPainter * painter, float curvature)
00267 {
00268     QPointF midpoint = (p1+p2)/2;
00269     QPointF p1p2 = p2-p1;
00270 
00271     QPointF ortho = getOrtho(p1p2);
00272     QPointF controlPoint= midpoint+curvature*ortho;
00273 
00274     //Create Painter path starting from p1
00275     QPainterPath arrowLine(p1);
00276     //paint quadratic bezier curve
00277     arrowLine.quadTo(controlPoint,p2);
00278     painter->strokePath(arrowLine,painter->pen());
00279 
00280 
00281     //Optional using cubic Bezier
00282     //QPointF c1 = p1+0.2*p1p2+ curvature*ortho;
00283     //QPointF c2 = p1+0.8*p1p2+ curvature*ortho;
00284 
00285     //painter->drawEllipse(c1,4,4);
00286     //painter->drawEllipse(controlPoint,4,4);
00287     //path.cubicTo(c1,c2,p2);
00288     //controlPoint=c2
00289 
00290     // Paint the arrow head
00291     // rotate the coordinate system such that [controlpoint,p2] is the new y-axis
00292     QPointF yAxis = p2-controlPoint;
00293 
00294     normalizeVec(yAxis);
00295     QPointF xAxis = getOrtho(yAxis);
00296 
00297     QMatrix mat(xAxis.x(), -yAxis.x(),
00298                 xAxis.y(), -yAxis.y(),
00299                 p2.x(),p2.y());
00300 
00301     painter->setWorldTransform(QTransform(mat),true);
00302 
00303     static const float ARROW_OPEN_FACTOR   = 0.4; //opening angle of the head: 1 means 90 degrees, 0 means no
00304     static const float ARROW_LENGTH_FACTOR = 0.1; //the arrow side length is computed as tangentLength*ARROW_LENGTH_FACTOR
00305     static const float ARROW_LENGTH_MAX    = 16;  //limits for the arrowhead sideLength
00306     static const float ARROW_LENGTH_MIN    = 10;
00307 
00308 
00309     QPointF tangent  = p2-controlPoint;
00310     float tangLength = std::sqrt(tangent.x()*tangent.x() + tangent.y()*tangent.y());
00311     float arrLength  = tangLength*ARROW_LENGTH_FACTOR;
00312 
00313     if(arrLength > ARROW_LENGTH_MAX)      arrLength=ARROW_LENGTH_MAX;
00314     if(arrLength < ARROW_LENGTH_MIN)      arrLength=ARROW_LENGTH_MIN;
00315 
00316 
00317     QPainterPath head(QPointF(0,0));
00318 
00319     head.lineTo(QPointF(ARROW_OPEN_FACTOR * arrLength,arrLength));
00320     head.lineTo(QPointF(-ARROW_OPEN_FACTOR * arrLength,arrLength));
00321     head.lineTo(QPointF(0,0));
00322     painter->drawPath(head);
00323 }

Generated on Tue Sep 15 14:48:47 2009 for RoseQtWidgets by  doxygen 1.4.7