1 //
2 // C++ Implementation: parallelcoor
3 //
4 // Description:
5 //
6 //
7 // Author: Pierre Marchand <pierremarc@oep-h.com>, (C) 2008
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12
13 #include "parallelcoor.h"
14 #include "typotek.h"
15
16
17 #include <QGraphicsScene>
18 #ifdef HAVE_QTOPENGL
19 #include <QGLWidget>
20 #endif
21 #include <QApplication>
22 #include <QDebug>
23 #include <QGraphicsSceneMouseEvent>
24 #include <QGraphicsItemGroup>
25 #include <QFontMetricsF>
26 #include <QSettings>
27 #include <QVariant>
28 #include <QColor>
29
30 /**
31 DataSet
32 */
33 const QString ParallelCoorDataSet::FieldSep = ":";
34
ParallelCoorDataSet()35 ParallelCoorDataSet::ParallelCoorDataSet()
36 {
37 }
38
~ParallelCoorDataSet()39 ParallelCoorDataSet::~ ParallelCoorDataSet()
40 {
41 }
42
43
getCategoryDescriptions() const44 QMap< QString , QString> ParallelCoorDataSet::getCategoryDescriptions() const
45 {
46 return m_categoryDescriptions;
47 }
48
49
setCategoryDescriptions(const QMap<QString,QString> & theValue)50 void ParallelCoorDataSet::setCategoryDescriptions ( const QMap< QString , QString >& theValue )
51 {
52 m_categoryDescriptions = theValue;
53 }
54
55
getValueDescriptions() const56 QMap< QString , QString> ParallelCoorDataSet::getValueDescriptions() const
57 {
58 return m_valueDescriptions;
59 }
60
61
setValueDescriptions(const QMap<QString,QString> & theValue)62 void ParallelCoorDataSet::setValueDescriptions ( const QMap< QString , QString >& theValue )
63 {
64 m_valueDescriptions = theValue;
65 }
66
getData() const67 ParallelCoorDataType ParallelCoorDataSet::getData() const
68 {
69 return m_data;
70 }
71
72
setData(const ParallelCoorDataType & theValue)73 void ParallelCoorDataSet::setData ( const ParallelCoorDataType& theValue )
74 {
75 m_data = theValue;
76 }
77
78
79 /**
80 View
81 */
82 QMap<QString, QPen> ParallelCoorView::pens;
83 QMap<QString, QBrush> ParallelCoorView::brushes;
84 QPainterPath ParallelCoorView::markPath;
85
ParallelCoorView(QWidget * parent)86 ParallelCoorView::ParallelCoorView(QWidget * parent)
87 :QGraphicsView(parent), m_dataSet(0)
88 {
89 setScene(new QGraphicsScene(this));
90 #ifdef HAVE_QTOPENGL
91 QGLFormat glfmt;
92 glfmt.setSampleBuffers ( true );
93 QGLWidget *glwgt = new QGLWidget ( glfmt );
94 if ( glwgt->format().sampleBuffers() )
95 {
96 setViewport ( glwgt );
97 setRenderHint(QPainter::Antialiasing,true);
98 }
99 else
100 {
101 delete glwgt;
102 setRenderHint(QPainter::Antialiasing,false);
103 }
104 #endif
105 setBackgroundBrush(Qt::white);
106 initPensAndBrushes();
107 doConnect();
108 }
109
ParallelCoorView(ParallelCoorDataSet * dataset,QWidget * parent)110 ParallelCoorView::ParallelCoorView(ParallelCoorDataSet * dataset, QWidget * parent)
111 :QGraphicsView(parent), m_dataSet(dataset)
112 {
113 setScene(new QGraphicsScene(this));
114 #ifdef HAVE_QTOPENGL
115 QGLFormat glfmt;
116 glfmt.setSampleBuffers ( true );
117 QGLWidget *glwgt = new QGLWidget ( glfmt );
118 if ( glwgt->format().sampleBuffers() )
119 {
120 setViewport ( glwgt );
121 setRenderHint(QPainter::Antialiasing,true);
122 }
123 else
124 {
125 delete glwgt;
126 setRenderHint(QPainter::Antialiasing,false);
127 }
128 #endif
129 setBackgroundBrush(Qt::white);
130 initPensAndBrushes();
131 doConnect();
132 }
133
~ParallelCoorView()134 ParallelCoorView::~ParallelCoorView()
135 {
136 }
137
selectField(const QString & field)138 void ParallelCoorView::selectField(const QString & field)
139 {
140 emit selectedField(field);
141 setCurrentField(field);
142 }
143
getCurrentField() const144 QString ParallelCoorView::getCurrentField() const
145 {
146 return m_currentField;
147 }
148
setCurrentField(const QString & theValue)149 void ParallelCoorView::setCurrentField ( const QString& theValue )
150 {
151 if(theValue!=m_currentField)
152 {
153 m_currentField = theValue;
154 cleanLists(ValueList);
155 drawValues();
156 }
157 }
158
getDataSet() const159 ParallelCoorDataSet* ParallelCoorView::getDataSet() const
160 {
161 return m_dataSet;
162 }
163
164
setDataSet(ParallelCoorDataSet * theValue)165 void ParallelCoorView::setDataSet ( ParallelCoorDataSet* theValue )
166 {
167 if(m_dataSet && (m_dataSet != theValue))
168 delete m_dataSet;
169 m_dataSet = theValue;
170 }
171
Units(int width,int height,int count)172 ParallelCoorView::Units::Units(int width, int height, int count)
173 {
174 hunit = static_cast<double> ( height ) /1000.0 ;
175 wunit = static_cast<double> ( width ) /1000.0 ;
176 XOffset = wunit * 200.0;
177 YOffset = hunit * 100.0 ;
178 H = hunit * 800.0 ;
179 W = wunit * 700.0 ;
180 C = count ;
181 step = W / static_cast<double> ( C-1 ) ;
182 }
183
initPensAndBrushes()184 void ParallelCoorView::initPensAndBrushes()
185 {
186 // bars
187 pens["bar"] = QPen(QColor(200,200,200), 6.0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
188 pens["bar-hover"] = QPen(QColor(160,160,160), 6.0, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
189
190 // vertices
191 pens["vertice-filter"] = QPen(Qt::black, 1.0);
192 pens["vertice-unfilter"] = QPen(QColor(200,200,200), 1.0);
193
194 // marks
195 double size(0.5);
196 markPath.addRect(-10.0*size,-10.0*size,20.0*size,20.0*size);
197 brushes["mark"] = QBrush(Qt::black);
198 brushes["mark-active"] = QBrush(Qt::red);
199
200 // debug
201 pens["debug-1"] = QPen(Qt::blue, 5.0);
202
203 QString cat("Panose/color-%1");
204 QSettings settings;
205 foreach(QString attr, pens.keys())
206 {
207 pens[attr].setColor( QColor(settings.value(cat.arg(attr),pens[attr].color().name()).toString()) );
208 settings.setValue(cat.arg(attr),pens[attr].color().name());
209 }
210 foreach(QString attr, brushes.keys())
211 {
212 brushes[attr].setColor( QColor(settings.value(cat.arg(attr),brushes[attr].color().name()).toString()) );
213 settings.setValue(cat.arg(attr),pens[attr].color().name());
214 }
215 }
216
cleanLists(ItemList il)217 void ParallelCoorView::cleanLists(ItemList il)
218 {
219 if((il == AllList) || (il == ValueList))
220 {
221 foreach(ParallelCoorValueItem* ti, valueLabels)
222 {
223 delete ti;
224 }
225 valueLabels.clear();
226
227 foreach(ParallelCoorMarkItem *mi, marks)
228 {
229 delete mi;
230 }
231 marks.clear();
232 }
233 if((il == AllList) || (il == FieldList))
234 {
235 foreach(ParallelCoorFieldItem* ti, fieldLabels)
236 {
237 delete ti;
238 }
239 fieldLabels.clear();
240 }
241 if((il == AllList) || (il == VerticeList))
242 {
243 foreach(QGraphicsLineItem* pi, vertices)
244 {
245 delete pi;
246 }
247 vertices.clear();
248 }
249 if((il == AllList) || (il == BarList))
250 {
251 foreach(ParallelCoorBarItem* li, bars)
252 {
253 delete li;
254 }
255 bars.clear();
256 }
257
258 }
259
redraw()260 void ParallelCoorView::redraw()
261 {
262 // qDebug()<<"ParallelCoorView::redraw";
263 if ( !m_dataSet )
264 {
265 qWarning()<<"No Dataset";
266 return;
267 }
268 if ( m_dataSet->isEmpty() )
269 {
270 qWarning()<<"Empty Dataset";
271 return;
272 }
273 if(controlSize != size())
274 {
275 // there will be another resize event soon, no need to draw now
276 return;
277 }
278
279 units = Units(width(), height(), m_dataSet->count());
280 // QTime t;
281 // int tclean, tbar, tvert, tfield, tval;
282 // t.start();
283 cleanLists(AllList);
284 // // tclean = t.elapsed();
285 // t.start();
286 drawBars();
287 // tbar = t.elapsed();
288 // t.start();
289 drawVertices();
290 // // tvert = t.elapsed();
291 // // t.start();
292 drawFields();
293 // tfield = t.elapsed();
294 // t.start();
295 drawValues();
296 // tval = t.elapsed();
297
298 // qDebug()<<"C"<<tclean<<"B"<<tbar<<"Ve"<<tvert<<"F"<<tfield<<"Va"<<tval;
299 }
300
drawBars()301 void ParallelCoorView::drawBars()
302 {
303 for ( int i ( 0 ); i < units.C ; ++i )
304 {
305 double di ( static_cast<double> ( i ) );
306 QLineF bl(units.XOffset + ( di * units.step ), units.YOffset,
307 units.XOffset + ( di * units.step ), units.YOffset + units.H);
308 ParallelCoorBarItem * bi ( new ParallelCoorBarItem(m_dataSet->at(i).first, this) );
309 bars << bi;
310 bi->setPen(pens["bar"]);
311 bi->setLine(bl);
312 scene()->addItem(bi);
313 }
314
315 }
316
drawVertices()317 void ParallelCoorView::drawVertices()
318 {
319 // qDebug()<<this<<"::drawVertices"<<m_dataSet->getData().count();
320 int tc, td, ta, to;
321 tc = td = ta = to = 0;
322 QTime t;
323 t.start();
324 const int N ( m_dataSet->getData().count() );
325 QMap<int, QMap< int, QPointF> > placeCoords;
326 for ( int k ( 0 );k < m_dataSet->count(); ++k )
327 {
328 QStringList list ( m_dataSet->at ( k ).second );
329 double x ( units.XOffset + ( static_cast<double> ( k ) * units.step ) );
330 double v ( units.H / static_cast<double> ( list.count()-1 ) );
331 for ( int l ( 0 ); l < list.count(); ++l )
332 {
333 double y ( units.YOffset + ( static_cast<double> ( l ) * v ) );
334 placeCoords[k][l] = QPointF ( x,y );
335 }
336 }
337 // QList<QLineF> cflines;
338 // QList<QLineF> culines;
339 QMap<double, QMap<double ,QList<QPointF> > > cflines;
340 QMap<double, QMap<double ,QList<QPointF> > > culines;
341 to = t.elapsed();
342 QGraphicsLineItem *li;
343 for ( int a ( 0 );a<N;++a )
344 {
345 // if( m_dataSet->getData().at(a).count() == m_dataSet->count() )
346 {
347 QList<QPointF> pol;
348 t.start();
349 for ( int b ( 0 ); b < m_dataSet->getData().at ( a ).count() ; ++b )
350 {
351 if(placeCoords[b].contains( m_dataSet->getData().at ( a ).at ( b ) ))
352 pol << QPointF( placeCoords[b][m_dataSet->getData().at ( a ).at ( b ) ] );
353 else
354 pol << QPointF( placeCoords[b][0] );
355
356 }
357 tc += t.elapsed();
358 t.start();
359 if ( pol.count() == m_dataSet->count() )
360 {
361 for(int vi(1);vi<pol.count();++vi)
362 {
363 bool f ( matchFilter ( m_dataSet->getData().at ( a ) ) );
364 if(f)
365 {
366 if(cflines.contains(pol[vi-1].x()))
367 {
368 if(cflines[pol[vi-1].x()].contains(pol[vi-1].y()))
369 {
370 if(cflines[pol[vi-1].x()][pol[vi-1].y()].contains(pol[vi]))
371 {
372 continue;
373 }
374 }
375 }
376 QLineF lf(pol[vi-1],pol[vi]);
377 li = new QGraphicsLineItem( lf );
378 li->setPen( pens["vertice-filter"] );
379 li->setZValue(100.0);
380 vertices << li;
381 cflines[pol[vi-1].x()][pol[vi-1].y()] << pol[vi];
382 }
383 else
384 {
385 if(culines.contains(pol[vi-1].x()))
386 {
387 if(culines[pol[vi-1].x()].contains(pol[vi-1].y()))
388 {
389 if(culines[pol[vi-1].x()][pol[vi-1].y()].contains(pol[vi]))
390 {
391 continue;
392 }
393 }
394 }
395 QLineF lf(pol[vi-1],pol[vi]);
396 li = new QGraphicsLineItem( lf );
397 li->setPen( pens["vertice-unfilter"] );
398 vertices << li;
399 culines[pol[vi-1].x()][pol[vi-1].y()] << pol[vi];
400 }
401 }
402 }
403 td += t.elapsed();
404
405 }
406 }
407 t.start();
408 int vcount(vertices.count());
409 QGraphicsScene * ls(scene());
410 for(int i(0); i < vcount; ++i)
411 {
412 ls->addItem( vertices[i] );
413 }
414 ta = t.elapsed();
415 qDebug()<<"R"<< to << tc << td << ta;
416 }
417
drawFields()418 void ParallelCoorView::drawFields()
419 {
420 // qDebug()<<"ParallelCoorView::drawFields";
421 QFont fontF( "Helvetica" , 100.0 , QFont::DemiBold, false );
422 double lastW(0.0);
423 bool lastPosShifted(false);
424 double maxAscent(0.0);
425 for(int k(0);k < m_dataSet->count(); ++k)
426 {
427 QString f(m_dataSet->at(k).first);
428 QFontMetricsF metrics(fontF);
429 double w(metrics.boundingRect(f).width());
430 double fsize( units.step * 100.0 / w );
431 double ascent(metrics.ascent() * fsize / 100.0 );
432 maxAscent = qMax(maxAscent, ascent);
433 }
434 for(int k(0);k < m_dataSet->count(); ++k)
435 {
436 QString f(m_dataSet->at(k).first);
437
438 fontF.setPointSizeF(100.0);
439 QFontMetricsF metrics(fontF);
440 double w(metrics.boundingRect(f).width());
441 double fsize( (units.step * 0.9) * 100.0 / w );
442 double ascent(metrics.ascent() * fsize / 100.0);
443 double sw(w * fsize / 100.0 );
444 fontF.setPointSizeF(fsize);
445
446 ParallelCoorFieldItem * ti = new ParallelCoorFieldItem(f,this);
447 fieldLabels << ti;
448 ti->setFont(fontF);
449 scene()->addItem(ti);
450 ti->setPos(units.XOffset + (k*units.step) - (sw/2.0), units.H + units.YOffset + (maxAscent - ascent));
451 // double h(ti->boundingRect().height());
452 // if(lastW > units.step * 1.1)
453 // {
454 // if(!lastPosShifted)
455 // {
456 // ti->setPos(units.XOffset + (k*units.step) , units.H + units.YOffset + h);
457 // lastPosShifted = true;
458 // }
459 // else
460 // {
461 // ti->setPos(units.XOffset + (k*units.step) , units.H + units.YOffset );
462 // lastPosShifted = false;
463 // }
464 // }
465 // else
466 // {
467 // ti->setPos(units.XOffset + (k*units.step) /*- (w/3.0)*/, units.H+units.YOffset);
468 // lastPosShifted = false;
469 // }
470 // lastW = w;
471 }
472
473 }
474
drawValues()475 void ParallelCoorView::drawValues()
476 {
477 int di(0);
478 if(!m_currentField.isEmpty())
479 {
480 for(int i(0);i<m_dataSet->count();++i)
481 {
482 if(m_dataSet->at(i).first == m_currentField)
483 {
484 di = i;
485 break;
486 }
487 }
488 }
489 else
490 m_currentField = m_dataSet->at(0).first;
491
492 QFont fontV( "Helvetica" , 9, QFont::Normal , true );
493 QFont fontS( "Helvetica" , 10, QFont::DemiBold , true );
494 double din(static_cast<double>(di));
495 double dn(static_cast<double>(m_dataSet->at(di).second.count()-1));
496 double vsep(units.H / dn);
497 QList<QString> list (m_dataSet->at(di).second);
498 for(int i(0); i< list.count(); ++i)
499 {
500 ParallelCoorValueItem *vi = new ParallelCoorValueItem(list[i], this);
501 valueLabels << vi;
502 ParallelCoorMarkItem *mi = new ParallelCoorMarkItem(vi, this);
503 marks << mi;
504 if(cfilter.contains(di))
505 {
506 if(cfilter[di].contains(i))
507 vi->setFont(fontS);
508 else
509 vi->setFont(fontV);
510 }
511 else
512 vi->setFont(fontV);
513
514 scene()->addItem(vi);
515 scene()->addItem(mi);
516
517 double w((units.XOffset * .9) - vi->boundingRect().width());
518 double h(vi->boundingRect().height() / 2.0);
519 // qDebug()<<"V"<<w<<vi->boundingRect().width()<<units.XOffset;
520 vi->setPos( w , units.YOffset + (static_cast<double>(i) * vsep) - h);
521 mi->setPos( units.XOffset + ( static_cast<double>(di) * units.step ), units.YOffset + (static_cast<double>(i) * vsep));
522 vi->setZValue(1000.0);
523 mi->setZValue(1000.0);
524 // qDebug()<<"=========================================================";
525 // qDebug()<<vi;
526 // qDebug()<<mi;
527 // qDebug()<<"=========================================================";
528 }
529 }
530
updateGraphic()531 void ParallelCoorView::updateGraphic()
532 {
533 if(isVisible())
534 redraw();
535 }
536
resizeEvent(QResizeEvent * event)537 void ParallelCoorView::resizeEvent(QResizeEvent * event)
538 {
539 controlSize = size();
540 updateGraphic();
541 QGraphicsView::resizeEvent(event);
542 }
543
showEvent(QShowEvent * event)544 void ParallelCoorView::showEvent(QShowEvent * event)
545 {
546 // updateGraphic();
547 QGraphicsView::showEvent(event);
548 }
549
550
getFilter() const551 QMap< QString, QStringList > ParallelCoorView::getFilter() const
552 {
553 return m_filter;
554 }
555
filterAsString()556 QString ParallelCoorView::filterAsString()
557 {
558 QString ret;
559 foreach(QString key, m_filter.keys())
560 {
561 const QStringList& l = m_filter[key];
562 if(!l.isEmpty())
563 {
564 if(ret.isEmpty())
565 ret += key + " {" + l.join(";") + "}";
566 else
567 ret += "\n" + key + " {" + l.join(";") + "}";
568 }
569
570 }
571 return ret;
572
573 }
574
setFilter(const QMap<QString,QStringList> & theValue)575 void ParallelCoorView::setFilter ( const QMap< QString, QStringList >& theValue )
576 {
577 m_filter.clear();
578 cfilter.clear();
579
580 m_filter = theValue;
581
582 for(int i(0);i < m_dataSet->count(); i++)
583 {
584 if(m_filter.contains(m_dataSet->at(i).first))
585 {
586 foreach(QString v, m_filter[m_dataSet->at(i).first])
587 {
588 cfilter[i] << m_dataSet->at(i).second.indexOf(v);
589 }
590 }
591 }
592
593 emit filterChanged();
594 updateGraphic();
595 }
596
597
598
matchFilter(QList<int> list) const599 bool ParallelCoorView::matchFilter(QList< int > list) const
600 {
601 if(list.isEmpty())
602 {
603 // qDebug()<<"List empty";
604 return false;
605 }
606 if(m_filter.isEmpty())
607 {
608 // qDebug()<<"Filter empty";
609 return true;
610 }
611
612 bool ret(false);
613 for(int i(0); i < list.count();++i)
614 {
615 if(cfilter.contains(i))
616 {
617 if(cfilter[i].contains(list[i]))
618 ret = true;
619 else
620 {
621 ret = false;
622 break;
623 }
624 }
625 }
626 return ret;
627 }
628
629
630 /**
631 Field label
632 */
hoverEnterEvent(QGraphicsSceneHoverEvent * event)633 void ParallelCoorFieldItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
634 {
635 qApp->setOverrideCursor(Qt::PointingHandCursor);
636 QBrush b = brush();
637 b.setColor(Qt::red);
638 setBrush(b);
639 }
640
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)641 void ParallelCoorFieldItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
642 {
643 QBrush b = brush();
644 b.setColor(Qt::black);
645 setBrush(b);
646 qApp->restoreOverrideCursor();
647 }
648
mousePressEvent(QGraphicsSceneMouseEvent * event)649 void ParallelCoorFieldItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
650 {
651 event->accept();
652 }
653
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)654 void ParallelCoorFieldItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
655 {
656 if(QString(pview->metaObject()->className()) == QString("ParallelCoorView") )
657 {
658 ParallelCoorView *pcv = reinterpret_cast<ParallelCoorView*>(pview);
659 pcv->selectField(text());
660 }
661
662 qApp->restoreOverrideCursor();
663 }
664
ParallelCoorFieldItem(QString text,QGraphicsView * pcv,QGraphicsItem * parent)665 ParallelCoorFieldItem::ParallelCoorFieldItem(QString text, QGraphicsView* pcv, QGraphicsItem * parent)
666 :QGraphicsSimpleTextItem(parent), pview(pcv)
667 {
668 setText(text);
669 setEnabled(true);
670 setAcceptHoverEvents ( true );
671 }
672
673 /**
674 Value label
675 */
ParallelCoorValueItem(QString text,QGraphicsView * pcv,QGraphicsItem * parent)676 ParallelCoorValueItem::ParallelCoorValueItem(QString text, QGraphicsView * pcv, QGraphicsItem * parent)
677 :QGraphicsSimpleTextItem(parent), pview(pcv)
678 {
679 setText(text);
680 setEnabled(true);
681 setAcceptHoverEvents ( true );
682 }
683
hoverEnter()684 void ParallelCoorValueItem::hoverEnter()
685 {
686 qApp->setOverrideCursor(Qt::PointingHandCursor);
687 QBrush b = brush();
688 b.setColor(Qt::red);
689 setBrush(b);
690 }
691
hoverLeave()692 void ParallelCoorValueItem::hoverLeave()
693 {
694 QBrush b = brush();
695 b.setColor(Qt::black);
696 setBrush(b);
697 qApp->restoreOverrideCursor();
698 }
699
click(int mod)700 void ParallelCoorValueItem::click(int mod)
701 {
702 if(QString(pview->metaObject()->className()) == QString("ParallelCoorView") )
703 {
704 ParallelCoorView *pcv = reinterpret_cast<ParallelCoorView*>(pview);
705
706 QMap<QString, QStringList> filter;
707 if(mod == 0) // bare left click
708 {
709 filter[pcv->getCurrentField()] << text();
710 }
711 else if(mod == 1) // with Shift
712 {
713 filter = pcv->getFilter();
714 filter[pcv->getCurrentField()] << text();
715 }
716 else if(mod == 2) // with Control
717 {
718 filter = pcv->getFilter();
719 filter[pcv->getCurrentField()].removeAll(text());
720 }
721
722 pcv->setFilter(filter);
723 }
724 qApp->restoreOverrideCursor();
725 }
726
hoverEnterEvent(QGraphicsSceneHoverEvent * event)727 void ParallelCoorValueItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
728 {
729 hoverEnter();
730 }
731
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)732 void ParallelCoorValueItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
733 {
734 hoverLeave();
735 }
736
mousePressEvent(QGraphicsSceneMouseEvent * event)737 void ParallelCoorValueItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
738 {
739 event->accept();
740 }
741
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)742 void ParallelCoorValueItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
743 {
744 if(event->modifiers() & Qt::ShiftModifier)
745 click(1);
746 else if(event->modifiers() & Qt::ControlModifier)
747 click(2);
748 else
749 click();
750 }
751
752 /**
753 Bars
754 */
ParallelCoorBarItem(const QString & field,QGraphicsView * pcv,QGraphicsItem * parent)755 ParallelCoorBarItem::ParallelCoorBarItem(const QString& field, QGraphicsView * pcv, QGraphicsItem * parent)
756 :QGraphicsLineItem(parent), pview(pcv), attachedField(field)
757 {
758 setEnabled(true);
759 setAcceptHoverEvents ( true );
760 }
761
hoverEnterEvent(QGraphicsSceneHoverEvent * event)762 void ParallelCoorBarItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
763 {
764 // qApp->setOverrideCursor(Qt::PointingHandCursor);
765 setPen(ParallelCoorView::pens["bar-hover"]);
766 if(QString(pview->metaObject()->className()) == QString("ParallelCoorView") )
767 {
768 ParallelCoorView *pcv = reinterpret_cast<ParallelCoorView*>(pview);
769 pcv->selectField(attachedField);
770 }
771 }
772
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)773 void ParallelCoorBarItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
774 {
775 setPen(ParallelCoorView::pens["bar"]);
776 // qApp->restoreOverrideCursor();
777 }
778
mousePressEvent(QGraphicsSceneMouseEvent * event)779 void ParallelCoorBarItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
780 {
781 // event->accept();
782 }
783
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)784 void ParallelCoorBarItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
785 {
786 // if(QString(pview->metaObject()->className()) == QString("ParallelCoorView") )
787 // {
788 // ParallelCoorView *pcv = reinterpret_cast<ParallelCoorView*>(pview);
789 // pcv->selectField(attachedField);
790 // }
791 // qApp->restoreOverrideCursor();
792 }
793
794 /**
795 Marks
796 */
797
ParallelCoorMarkItem(ParallelCoorValueItem * relative,QGraphicsView * pcv,QGraphicsItem * parent)798 ParallelCoorMarkItem::ParallelCoorMarkItem(ParallelCoorValueItem * relative, QGraphicsView * pcv, QGraphicsItem * parent)
799 :QGraphicsPathItem(parent), pview(pcv), value(relative)
800 {
801 setEnabled(true);
802 setAcceptHoverEvents ( true );
803
804 setBrush(ParallelCoorView::brushes["mark"]);
805 setPen(QPen(Qt::transparent,0.0));
806 setPath(ParallelCoorView::markPath);
807
808 }
809
hoverEnterEvent(QGraphicsSceneHoverEvent * event)810 void ParallelCoorMarkItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
811 {
812 setBrush(ParallelCoorView::brushes["mark-active"]);
813 value->hoverEnter();
814 QGraphicsPathItem::hoverEnterEvent(event);
815 }
816
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)817 void ParallelCoorMarkItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
818 {
819 setBrush(ParallelCoorView::brushes["mark"]);
820 value->hoverLeave();
821 QGraphicsPathItem::hoverLeaveEvent(event);
822 }
823
mousePressEvent(QGraphicsSceneMouseEvent * event)824 void ParallelCoorMarkItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
825 {
826 event->accept();
827 }
828
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)829 void ParallelCoorMarkItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
830 {
831 if(event->modifiers() & Qt::ShiftModifier)
832 value->click(1);
833 else if(event->modifiers() & Qt::ControlModifier)
834 value->click(2);
835 else
836 value->click();
837 }
838
slotSaveColors()839 void ParallelCoorView::slotSaveColors()
840 {
841 // qDebug()<<"ParallelCoorView::~ParallelCoorView()";
842 // QString cat("Panose/%1");
843 // QSettings settings;
844 // foreach(QString attr, pens.keys())
845 // {
846 // qDebug()<<cat.arg(attr);
847 // settings.setValue(cat.arg(attr),pens[attr].color() );
848 // }
849 // foreach(QString attr, brushes.keys())
850 // {
851 // qDebug()<<cat.arg(attr);
852 // settings.setValue(cat.arg(attr),brushes[attr].color() );
853 // }
854 }
855
doConnect()856 void ParallelCoorView::doConnect()
857 {
858 // connect(this, SIGNAL(destroyed( QObject* )), this, SLOT(slotSaveColors()));
859 }
860
861
862
863
864
865
866
867
868
869
870