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