/*************************************************************************
 * This file is part of Graphic des EDitor project    
 *
 * Project created in conformity with the requirements for the Degree of
 * Master of Engineering in Software Engineering, Computing and Software
 * Department, McMaster University 2004 - 2008
 *
 * Author:	Xiao Ma
 * Supervisor: Dr. Ryan Leduc
*************************************************************************/

/* 
 NAME
   GedDesTrans.cpp - Ged DES transition function. 
 FUNCTION
   The class provides the graphic transition function. 
 NOTES
 MODIFIED
   xma	    04/01/07 - CREATION 
*/
#include <math.h>
#include <assert.h>

#include "GedDesTrans.h"
#include "GedTextItem.h"
#include "Des.h"
#include "GedDesTransCurve.h"
#include "DistCommon.h"

// for debug
// #include <iostream>


namespace DESpot
{

static const double Pi = 3.14159265358979323846264338327950288419717;
static const double TwoPi = 2.0 * Pi;
static const double HalfPi = Pi / 2.0;
static const double Square_root_of_2 = 1.4142135623730950488016887242097;
static const qreal sz_sl = 50; // size of self loop rect
static const qreal ArrowSize = 12.5;


void GedDesTrans::setReadOnly(bool readOnly)
{
	setFlag(QGraphicsItem::ItemIsMovable, !readOnly);
	setFlag(QGraphicsItem::ItemIsSelectable, !readOnly);
	label->setFlag(QGraphicsItem::ItemIsMovable, !readOnly);
	label->setFlag(QGraphicsItem::ItemIsSelectable, !readOnly);
}

void GedDesTrans::initTransProps()
{
    setFlag(QGraphicsItem::ItemIsSelectable, true);

    // next needed for changes made to qt 4.6 and greater
#ifdef  __QT_Vers_gteq_4_6__
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
#endif

    //myColor = Qt::black;
    setPen(QPen(Qt::black, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
	line = null;

	// set to default value so can tell when position has been
	// assigned
	currentAngle = defaultGedItemValue;

	if (DistCommon::GUI_Enabled)
	{
		label = new GedDesLabel(this);
	}
}

GedDesTrans::GedDesTrans(Des* des,GedDesState *startState, GedDesState *endState, 
						 QMenu *contextMenu, QGraphicsItem *parent, 
						 QGraphicsScene *scene, bool isCurve)
    : QGraphicsPathItem(parent, scene),
        startState(startState),
        endState(endState),
        contextMenu(contextMenu),
        des(des),
        m_pEligEvents(0),
        m_pPrevEvent(0),
        m_pNextEvent(0),
		m_isCurve(isCurve)
{
        m_lastStartPos = startState->pos();
	m_lastEndPos = endState->pos();
	initTransProps();
	assert(label);
}


QVariant GedDesTrans::itemChange(GraphicsItemChange change,
	const QVariant &value)
{

	if (change == QGraphicsItem::ItemSelectedChange) {

		// value is a boolean giving new selected state
		// this part added to allow movement of entire DES at once
		// This prevents a selfloop transition to be moved (which moves
		// its label as well)  and then have the a second movement applied
		// to label itself.
		if (value.toBool() && label->isSelected() && isSelfLoop()) {
			label->setFlag(QGraphicsItem::ItemIsMovable,false);
		} else {
			// ensures when only label selected, it can be repositioned
			label->setFlag(QGraphicsItem::ItemIsMovable,true);
		}
	}

	return value;

}

void GedDesTrans::updatePosition()
{
	// `line` member variable represents the line that is being used in the GED
	// to modify this transition

    QLineF myLine;

	if (!DistCommon::GUI_Enabled)
		return;

    // Self loop
	if (startState == endState)
	{

		resetTransform();
		myLine = createCircle();

		if (line != 0) 
		{

			QLineF line2 = QLineF(QPointF(0,0),mapFromScene(line->p2()));

			qreal x = line2.p2().x();
			qreal y = line2.p2().y();
			qreal angle;
			
			if (y == 0)
			{
				if (x >= 0) 
					currentAngle = 0;
				else
					currentAngle = 180;
			}
			else if (x == 0)
			{
				currentAngle = 0;
			}
			else
			{
				angle = atan(y / x);
				//1st ok, no change needed
				//2nd. atan < 0, => +pi
				if (x < 0 && y > 0) 
					angle = Pi + angle;
				//3nd
				if (x < 0 && y < 0)
					angle = Pi + angle;
				if (x > 0 && y < 0)
					angle = TwoPi + angle;
				
				currentAngle = angle * (180.0 / Pi);
				currentAngle -= 45.0;
			}

			line = 0;

		}

		// make sure current angle not left at default if line is null

		// this rotates selfloop so it is above the state
		if (currentAngle <= defaultGedItemValue)
		{
			currentAngle = 225;
		}

		// must always do a rotate as transform was reset.
		rotateSelfLoop(currentAngle);
		
	}
	
	// Normal transition, i.e  not self loop
	if (startState != endState)
	{
		if (naPath.elementCount() == 0)
			myLine = createLine();
		else 
			myLine = changeLine();
	}

	// Set this object's path based off the naPath. This representation is used
	// by the QGraphicsScene for everything except drawing purposes.
	QPainterPath myPath;
	if (startState == endState) {
		// Use the existing circle for self-loops
		myPath = naPath;
	} else if (isCurve()) {
		// If it's a curve, turn the naPath into a curve and use that as the
		// path
		// NOTE: naPath consists only of inflection points of the generated
		// path. As well, getPos() gets the points of the naPath
		myPath = GedDesTransCurve(getPos(), CurveType::CATMULL_ROM).getCurve();
	} else {
		// It's a line; use the naPath
		myPath = naPath;
	}
	setPath(myPath);

	//Relocate the label
    // NOTE: the following code is due to 2 bug fixes
	   /*  basic concept
	       1) label is initialized as a child of trans
		   2) when rotate self-loop, we set label parent to 0
                      (this is no longer done)
		   so we need the following code
		   1) selfloop && there is parent => selfloop created, not rotated
		   2) selfloop && no parent => selfloop has been rotated.
	   */

	//RJL: add check here to prevent label pos changing if not default.
	QPointF tmpPoint(label->pos());
	if ((tmpPoint.x() <= defaultGedItemValue)
		&& (tmpPoint.y() <= defaultGedItemValue))
	{
		// Calculate where the label should be in relation to the endpoint of
		// the line
		QLineF vect = myLine.unitVector();
		QLineF norm = vect.normalVector();
		QPointF shift = QPointF(norm.dx() + vect.dx(), norm.dy() + vect.dy());
		QLineF labelPosLine = QLineF(myLine.p1(), myLine.p1() + shift);
		labelPosLine.setLength(labelPosLine.length()*1.8);
		if (startState == endState) //self-loop => label has no parent
		{
			if (label->parentItem())
				label->setPos(labelPosLine.p2());
			else
				label->setPos(labelPosLine.p2() + mapToScene(QPointF(0,0)));
		}
		else
			label->setPos(labelPosLine.p2());
	}

}

void GedDesTrans::rotateSelfLoop(qreal angle)
{
	resetTransform();
	QPointF tmpPoint2(label->pos());
	label->setPos(0,0);
	rotate(angle);
	label->resetTransform();
	label->rotate(-angle);
	label->setPos(tmpPoint2);
}	

  // this function should only be called by simulator, never by 
  // graphical des editor

  void GedDesTrans::draw(QPainter* painter, QPointF& offset)
{
	if (isSelfLoop())
	{
		painter->save();
		painter->translate(getStartState()->pos()- offset);
		painter->rotate(angle());
		drawTrans(painter, true);
		painter->restore();
	}
	else
	{
		painter->save();
		painter->translate(-offset);
		drawTrans(painter, true);
		painter->restore();
	}

	if (label)
	{
		painter->save();
		painter->translate(mapToScene(label->pos())- offset);

		QRectF rect = label->boundingRect();

		QFontMetrics fm = painter->fontMetrics();

                int x = (int)rect.x();
		int y = 0;
                int w = (int)rect.width();
                int h = (int)fm.height();

		foreach (SimLabel lbl, simLabels)
		{
			if (lbl.prev && simType == PrevSimTrans)
				// BH - This condition doesn't work with multiple events in a transition,
				// and colour now handled in updateLabel(), but leaving as a just in case for transitions
				// with single events.
				painter->setPen(Qt::magenta);
			else if (lbl.next && simType == SelectedSimTrans)
				painter->setPen(Qt::green);
			else
				painter->setPen(lbl.color);

			const QFont& oldFont = painter->font();
			if (lbl.controllable)
			{
				QFont font = QFont(painter->font());
				font.setItalic(true);
				painter->setFont(font);
			}

			painter->drawText(QRect(x, y, w, h), lbl.text,
					QTextOption(Qt::AlignBottom | Qt::AlignHCenter));

			if (lbl.prev)
			{
				painter->setPen(Qt::magenta);
				painter->drawText(QRect(w, y, fm.width("*"), h),
						"*", QTextOption(Qt::AlignBottom | Qt::AlignHCenter));
			}

			y += painter->fontMetrics().lineSpacing();

			painter->setFont(oldFont);
		}
		painter->restore();
	}
}


void GedDesTrans::drawTrans(QPainter* painter, bool simMode)
{
	painter->setRenderHint(QPainter::Antialiasing);

	// Do not paint if states are too close
	if (startState != endState &&
		startState->collidesWithItem(endState))
		return;

	QPainterPath myPath = path();

	// Set line and fill colour
	QColor color = Qt::black;
	QColor brushColor = Qt::black;

	// Special colours for simulation
	if (simMode)
	{
		if (simType == EligibleSimTrans) {
			brushColor = color = Qt::blue;
		} else if (simType == PrevSimTrans) {
			brushColor = color = Qt::magenta;
		} else if (simType == EligiblePrevSimTrans) {
			color = Qt::blue;
			brushColor = Qt::magenta;
		} else if (simType == SelectedSimTrans) {
			color = Qt::green;
		}
	}

	painter->setPen(QPen(color, 1, Qt::SolidLine));

	// Draw the lines that represent the transition (whether it be a circle,
	// line, curve, etc..). Also draw the arrow

	if (startState != endState) {
		// For anything that isn't a self-loop
		CurveType curveType;
		if (m_isCurve) {
			curveType = CurveType::CATMULL_ROM;
		}
		else {
			curveType = CurveType::LINE;
		}
		GedDesTransCurve curveObj(getPos(), curveType);
		painter->drawPath(curveObj.getCurve());
		painter->fillPath(curveObj.getArrow(), QBrush(brushColor));
	} else {
		// Self Loop
		QList<QPointF> rearrangement;
		rearrangement.push_back(getPos()[7]);
		rearrangement.push_back(getPos()[5]);
		GedDesTransCurve curveObj(rearrangement, CurveType::LINE);
		painter->drawPath(myPath);
		painter->fillPath(curveObj.getArrow(), QBrush(brushColor));
	}

	// Draw dotted lines if this item is selected
	if (isSelected() && !simMode)
	{
		painter->setPen(QPen(color, 1, Qt::DashLine));
		if(startState == endState)
		{
			QRectF myRect = myPath.boundingRect();
			painter->drawRect(myRect);
		}
		else
		{
			painter->drawPath(myPath);

			QList<QPointF> pos = getPos();
			painter->setBrush(Qt::SolidPattern);
			foreach(QPointF pnt, pos)
				painter->drawRect(QRectF(pnt.x()-4,pnt.y()-4,8,8));
		}

		label->setSelected(true);
	}
}

void GedDesTrans::paint(
	QPainter * painter,
	const QStyleOptionGraphicsItem * option,
	QWidget * widget)
{
	drawTrans(painter, false);
}

QLineF GedDesTrans::createCircle()
{
	//Move origin to state origin
	setPos(startState->pos());

	// Draw a circle. 10.0 is length of radian of state
	QPainterPath myPath;
	qreal r = (10.0/(Square_root_of_2-1));
	myPath.addEllipse(0,0,2*r,2*r);

	// Line for arrow header
	QLineF myLine=QLineF(
		QPointF(10.0/Square_root_of_2,10.0/Square_root_of_2),
		QPointF(r,0));

	naPath = myPath;
	return myLine;
}


QLineF GedDesTrans::createLine()
{
	QPainterPath myPath;

	QLineF centerLine(startState->pos(), endState->pos());
	QPolygonF endPolygon = endState->polygon();
	QPointF p1 = endPolygon.first() + endState->pos();
	QPointF p2;
	QPointF intersectPoint;
	QLineF polyLine;
	for (int i = 1; i < endPolygon.count(); ++i) {
		p2 = endPolygon.at(i) + endState->pos();
		polyLine = QLineF(p1, p2);
		QLineF::IntersectType intersectType =
			polyLine.intersect(centerLine, &intersectPoint);
		if (intersectType == QLineF::BoundedIntersection)
			break;
		p1 = p2;
	}
	
	//Because path item does not seem respecting zvalue,
	//We do this for start state as well
	QPolygonF startPolygon = startState->polygon();
	p1 = startPolygon.first() + startState->pos();
	QPointF startIntersectPoint;
	for (int i = 1; i < startPolygon.count(); ++i) {
		p2 = startPolygon.at(i) + startState->pos();
		polyLine = QLineF(p1, p2);
		QLineF::IntersectType intersectType =
			polyLine.intersect(centerLine, &startIntersectPoint);
		if (intersectType == QLineF::BoundedIntersection)
			break;
		p1 = p2;
	}

	myPath.moveTo(intersectPoint);
	myPath.lineTo(startIntersectPoint);
	//myPath.lineTo(startState->pos());

	naPath = myPath;
	QLineF myLine = QLineF(intersectPoint,startState->pos());

	return myLine;
}


/******************************************************************
If exists, we break the line
We iterator all elements in the PainterPath
Get the subpath (line for now) that intersect with the given 
line (paramters). Break this line into two lines.	
		 NOTE: for now, we only consider line 
How do I change a line?
1. if in scene, in line mode, we draw a line
2. the scene set class number myLine and pass the line to trans
3. if the start point of the line belongs to an existing line
4.   we break the line and change the line shape
We paint the shape of the trans using naPath + arrow
5.  intermediate points make the same delta move as the start and end states.
******************************************************************/
QLineF GedDesTrans::changeLine()
{
	// `line` member variable represents the movement specified in the GED

	QPainterPath myPath = naPath;
	int ec = myPath.elementCount();
	assert(ec > 0);

	if (line != 0){

		int subIdx = 0;
		bool foundExist = false; //we will move an existing interfection
		                         //if it is in the selection rect

		// Look for an existing point in a 10x10 rectangle
		// don't include the staring and end point
		QRectF rect = QRectF(line->p1().x()-5, line->p1().y()-5, 10, 10);
		for (int i = 1; i < naPath.elementCount() - 1; i++) {
			const QPainterPath::Element ele = naPath.elementAt(i);
			if (rect.contains(ele.x,ele.y))
			{
				subIdx = i;
				foundExist = true;
				break;
			}
		}

		if (foundExist) // We just need to move an existing interfection
		{
			QPainterPath myNewPath;
			for (int i = 0; i <= subIdx-1; i++)
			{
				QPainterPath::Element e = myPath.elementAt(i);
				if (e.isMoveTo())
					myNewPath.moveTo(e.x,e.y);
				if (e.isLineTo())
					myNewPath.lineTo(e.x,e.y);
			}
			myNewPath.lineTo(line->p2());
			for (int i = subIdx+1; i< ec; i++)
			{
				QPainterPath::Element e = myPath.elementAt(i);
				if (e.isMoveTo())
					myNewPath.moveTo(e.x,e.y);
				if (e.isLineTo())
					myNewPath.lineTo(e.x,e.y);
			}
			myPath=myNewPath;

		}
		else  //We add a new interfection into the path
		{
			// |Fidn which segment of the path the new point should be added to
			bool found = false;
			for (int i = 0; i < ec; i++)
			{
				if (myPath.elementAt(i).isLineTo())
				{
					QLineF centerLine(myPath.elementAt(i-1).x,
									  myPath.elementAt(i-1).y,
									  myPath.elementAt(i).x,
									  myPath.elementAt(i).y);	
					QLineF line1 = QLineF(line->p2(), line->p1());
					line1.setLength(line->length() + 20);  // add some extra
					QPointF ip;
					QLineF::IntersectType it = centerLine.intersect(line1, &ip);
					if (it == 1)
					{
						found=true;
						subIdx = i;
						break;
					}
				}
			}
				
			if (found)
			{
				QPainterPath myNewPath;
				for (int i = 0; i < subIdx; i++)
				{
					QPainterPath::Element e = myPath.elementAt(i);
					if (e.isMoveTo())
						myNewPath.moveTo(e.x,e.y);
					if (e.isLineTo())
						myNewPath.lineTo(e.x,e.y);
				}
				myNewPath.lineTo(line->p2());
				for (int i = subIdx; i< ec; i++)
				{
					QPainterPath::Element e = myPath.elementAt(i);
					if (e.isMoveTo())
						myNewPath.moveTo(e.x,e.y);
					if (e.isLineTo())
						myNewPath.lineTo(e.x,e.y);
				}
				myPath = myNewPath;
			}
		}
	}

	// Adjust start / end point for move
	// Note: element[0] - endState central point
	//       element[1] - if straight line, central pt of startState
	ec = myPath.elementCount();
	QLineF centerLine(QPointF(myPath.elementAt(1).x,
							  myPath.elementAt(1).y),
					endState->pos());
	QPolygonF endPolygon = endState->polygon();
	QPointF p1 = endPolygon.first() + endState->pos();
	QPointF p2;
	QPointF intersectPoint;
	QLineF polyLine;
	for (int i = 1; i < endPolygon.count(); ++i) {
		p2 = endPolygon.at(i) + endState->pos();
		polyLine = QLineF(p1, p2);
		QLineF::IntersectType intersectType =
			polyLine.intersect(centerLine, &intersectPoint);
		if (intersectType == QLineF::BoundedIntersection)
			break;
		p1 = p2;
	}

	//Because path item does not seem respecting zvalue,
	//We do this for start state as well
	centerLine = QLineF(QPointF(myPath.elementAt(ec-2).x,
								myPath.elementAt(ec-2).y),
						startState->pos());
	QPolygonF startPolygon = startState->polygon();
	p1 = startPolygon.first() + startState->pos();
	QPointF startIntersectPoint;
	for (int i = 1; i < startPolygon.count(); ++i)
	{
		p2 = startPolygon.at(i) + startState->pos();
		polyLine = QLineF(p1, p2);
		QLineF::IntersectType intersectType =
			polyLine.intersect(centerLine, &startIntersectPoint);
		if (intersectType == QLineF::BoundedIntersection)
			break;
		p1 = p2;
	}

	myPath.setElementPositionAt(0,intersectPoint.x(),intersectPoint.y());
	myPath.setElementPositionAt(ec-1,startIntersectPoint.x(),startIntersectPoint.y());

	// Remove the line that signals a change in the transition line was
	// requested
	delete line;
	line = 0;

	// need to update intermiediate points due to movement of
	// start and end states.  Calculate net x and y movement
	// for a given state, then divide in two, and move the
	// intermediate points this amount.
	QPointF lastStartPos = m_lastStartPos;
	QPointF lastEndPos = m_lastEndPos;
	QPointF newStartPos = startState->pos();
	QPointF newEndPos = endState->pos();

	// update stored last  start/end positions
	m_lastStartPos = newStartPos;
	m_lastEndPos = newEndPos;

	// calculate relative movement of start/end state - div 2.0
	QPointF chngStartPos = (newStartPos - lastStartPos)/2.0;
	QPointF chngEndPos = (newEndPos - lastEndPos)/2.0;


	// update intermediate points
	for (int i = 1; i < ec - 1; ++i) {
		QPointF tmpPoint = myPath.elementAt(i);
		tmpPoint += chngStartPos + chngEndPos;
		myPath.setElementPositionAt(i,tmpPoint.rx(),tmpPoint.ry());
	}

	QPainterPath::Element e1 = myPath.elementAt(0);
	QPainterPath::Element e2 = myPath.elementAt(1);

	QLineF myLine = QLineF(QPointF(e1.x,e1.y), QPointF(e2.x,e2.y));

	naPath = myPath;
	return myLine;

} 

void GedDesTrans::setTransShape(QList<QPointF> pos)
{
	naPath.moveTo(pos[0]);
	for(int i=1; i<pos.count(); i++){
		naPath.lineTo(pos.at(i));
		QPointF p=pos.at(i);
		//int j=0;
	}
}

void GedDesTrans::setAngle(qreal angle)
{
	currentAngle=angle;
}

void GedDesTrans::restoreDefaultShape()
{
	if (startState == endState)
		if (currentAngle==0) 
			return;
		else {
			currentAngle=0;
			updatePosition();
			setSelected(false);
		}
	else
		if (naPath.elementCount() == 2) 
			return;
		else {
			createLine();
			updatePosition();
			setSelected(false);
		}
}

// This is called by GedDesScene when drawing a line to insert 
// a new trans. This is NOT the same as insertEvent as in this 
// case, we have inserted DesTransition to DES already; this is 
// not the case in insertEvent()
void GedDesTrans::insertDesTrans(const DesTransition* desTrans)
{
	desEventList.append(&desTrans->event());
	updateLabel();
}

void GedDesTrans::setDesEvents(QList<const DesEvent* > events)
{
	QListIterator<const DesEvent* > i(desEventList);
	while (i.hasNext()) {
		deleteEvent(i.next());
	}
	
	QListIterator<const DesEvent* > j(events);
	while (j.hasNext()) {
		insertEvent(j.next());
	}
	updateLabel();
}

bool GedDesTrans::findEvent(const DesEvent *ev)
{
	return desEventList.contains(ev);
}

void GedDesTrans::clearEvents()
{

	QListIterator<const DesEvent* > i(desEventList);
	while (i.hasNext()) {
		deleteEvent(i.next());
	}

	//The item will be deleted from the scene so no updateLable() is needed.
	//updateLabel();
}


// the event must be valid at this point. This two function itself does not verify it
void GedDesTrans::insertEvent(const DesEvent* ev)
{
	const DesState* fromState = startState->getDesState();
	const DesState* toState = endState->getDesState();
	DesTransition *trans = new DesTransition(*fromState,*ev,*toState);
	des->addTransition(*trans);
	desEventList.append(ev);
}

void GedDesTrans::deleteEvent(const DesEvent* ev)
{
	const DesState* fromState = startState->getDesState();
	const DesState* toState = endState->getDesState();
	DesTransition *trans = new DesTransition(*fromState,*ev,*toState);
	des->deleteTransition(*trans);
	desEventList.removeAll(ev);
}

//To support delete event
void GedDesTrans::deleteEventOnly(const DesEvent* ev)
{
	assert(findEvent(ev));
	desEventList.removeAll(ev);
}

void GedDesTrans::updateLabel()
{
	QString text;
	simLabels.clear();
	foreach (const DesEvent *ev, desEventList)
	{
		SimLabel lbl;
		QString  uEventSymbol = "!";

		if (!ev->isControllable())
		{
		  // prepend uncontrollable event names by "!"
		  lbl.text = uEventSymbol + QString::fromStdWString(ev->getName());
		}
		else
		{
		  lbl.text = QString::fromStdWString(ev->getName());	
		}

		//		lbl.text = QString::fromStdWString(ev->getName());
		lbl.color = Qt::black;
		lbl.controllable = false;
		lbl.prev = false;
		lbl.next = false;

		if (m_pEligEvents)
		{
			// Try to mark all eligible events
			std::set<ProjectEvent*>::iterator it = m_pEligEvents->begin();
			for (; it != m_pEligEvents->end(); ++it)
			{
				ProjectEvent* pProjectEvent = *it;
				if (pProjectEvent->findSourceEvent(ev))
				{
					// Found GedEvent in a given transition and it's eligible
					// BH - Comparing against the transition type instead of a 'found' bool, and assuming
					// the sim type is set to a default normal trans value before.  If not, might need to 
					// re-introduce a found bool but outside of the event for loop
					if (simType == PrevSimTrans)
						setSimType(EligiblePrevSimTrans);
					else if (simType != EligiblePrevSimTrans)
						setSimType(EligibleSimTrans);
					lbl.color = Qt::blue;
				}
			}
		}

		// Mark previous event that was used to get to current state
		if (m_pPrevEvent)
		{
			if (m_pPrevEvent->findSourceEvent(ev))
			{
				lbl.prev = true;
				lbl.color = Qt::magenta;

				// BH - Handle if an event in this transition was also an eligible event
				if (simType == EligibleSimTrans || simType == PrevSimTrans)
				{
					setSimType(EligiblePrevSimTrans);
				}
				else if (simType != EligiblePrevSimTrans)
				{
					setSimType(PrevSimTrans);
				}
			}
		}

		// Mark next event that will be taken. Only set in history mode
		if (m_pNextEvent)
		{
			if (m_pNextEvent->findSourceEvent(ev))
			{
				lbl.next = true;
				setSimType(SelectedSimTrans);
			}
		}

		text.append("<div>");

		if (!ev->isControllable())
		{
			lbl.controllable = true;
			text.append("<i>");
			text.append(lbl.text);
			text.append("</i>");
		}
		else
		{
			text.append(lbl.text);
		}
		text.append("</div>");

		simLabels.push_back(lbl);
	}	
	label->setHtml(text);
	label->update();
}


// The position of the transition (no arrow)
const QList<QPointF> GedDesTrans::getPos() const
{
	QList<QPointF> pt_lst;
	
	int cnt = naPath.elementCount();

	for(int i=0; i<cnt; i++){
		const QPainterPath::Element ele = naPath.elementAt(i);
		pt_lst.append(QPointF(ele.x,ele.y));
	}
	return pt_lst;
}

void GedDesTrans::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
	if (!contextMenu) { return; }

    scene()->clearSelection();
    setSelected(true);
    contextMenu->exec(event->screenPos());
}

void GedDesTrans::setLine(const QLineF &ln) 
{
	if (line == 0) 
		line = new QLineF(ln);
}

void GedDesTrans::setSimType(GedSimType type)
{
	simType = type;
}

//This function is not currently used.
QPainterPath GedDesTrans::selectShape() const
{
	QPainterPath path;
	if (startState == endState)
	{
		path.addRect(this->boundingRect());
		return path;
	}

	int ec = naPath.elementCount();

	qreal extra = (pen().width() + 20) / 2.0;


	for (int i = 0; i< ec; i++)  //find which subpath is choosen
		if (naPath.elementAt(i).isLineTo()){
			QLineF cline(naPath.elementAt(i-1).x,naPath.elementAt(i-1).y,
							  naPath.elementAt(i).x,naPath.elementAt(i).y);	
			path.addRect(QRectF(cline.p1(), QSizeF(cline.p2().x() - cline.p1().x(),
                                                   cline.p2().y() - cline.p1().y()))
								.normalized()
								.adjusted(-extra, -extra, extra, extra)
						);
			}

    return path;
} 

QPainterPath GedDesTrans::shape() const
{
	//return this->path();
	//return naPath;
	QPainterPathStroker p;
	//return p.createStroke(naPath);
	p.setWidth(8);
	return p.createStroke(path());

}

void GedDesTrans::toggleCurvature()
{
	m_isCurve = !m_isCurve;
}


}
