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
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
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
00156 QDrag *drag = new QDrag(viewport());
00157
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
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
00244
00245
00246
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
00275 QPainterPath arrowLine(p1);
00276
00277 arrowLine.quadTo(controlPoint,p2);
00278 painter->strokePath(arrowLine,painter->pen());
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
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;
00304 static const float ARROW_LENGTH_FACTOR = 0.1;
00305 static const float ARROW_LENGTH_MAX = 16;
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 }