linkablemapobj.cpp
author insilmaril
Mon, 04 Aug 2008 13:35:54 +0000
changeset 724 cf14046909cd
parent 723 11f9124c1cca
child 726 7f43b93242aa
permissions -rw-r--r--
Adding/moving MCO works again
     1 #include <iostream>
     2 #include <math.h>
     3 
     4 #include "linkablemapobj.h"
     5 #include "branchobj.h"
     6 #include "vymmodel.h"
     7 
     8 using namespace std;
     9 
    10 /////////////////////////////////////////////////////////////////
    11 // LinkableMapObj
    12 /////////////////////////////////////////////////////////////////
    13 
    14 LinkableMapObj::LinkableMapObj():MapObj()
    15 {
    16   //  cout << "Const LinkableMapObj ()\n";
    17     init ();
    18 }
    19 
    20 LinkableMapObj::LinkableMapObj(QGraphicsScene* s) :MapObj(s)
    21 {
    22 //    cout << "Const LinkableMapObj (s)\n";
    23     init ();
    24 }
    25 
    26 LinkableMapObj::LinkableMapObj (LinkableMapObj* lmo) : MapObj (lmo->scene)
    27 {
    28     copy (lmo);
    29 }
    30 
    31 LinkableMapObj::~LinkableMapObj()
    32 {
    33     delete (bottomline);
    34 	delLink();
    35 }
    36 
    37 void LinkableMapObj::delLink()
    38 {
    39 	switch (style)
    40 	{
    41 		case Line:
    42 			delete (l);
    43 			break;
    44 		case Parabel:
    45 			while (!segment.isEmpty()) delete segment.takeFirst();
    46 			break;
    47 		case PolyLine:
    48 			delete (p);
    49 			break;
    50 		case PolyParabel:
    51 			delete (p);
    52 			break;
    53 		default:
    54 			break;
    55 	}		
    56 }
    57 
    58 void LinkableMapObj::init ()
    59 {
    60 	model=NULL;
    61 
    62     depth=-1;	
    63 	mapEditor=NULL;
    64     childObj=NULL;
    65     parObj=NULL;
    66     parObjTmpBuf=NULL;
    67     parPos=QPointF(0,0);
    68     childPos=QPointF(0,0);
    69 	link2ParPos=false;
    70     l=NULL;
    71     orientation=UndefinedOrientation;
    72     linkwidth=20;		
    73 	thickness_start=8;
    74     style=UndefinedStyle;
    75 	linkpos=Bottom;
    76     arcsegs=13;
    77     
    78 // TODO instead of linkcolor pen.color() could be used	all around
    79 	pen.setWidth (1);
    80 	pen.setColor (linkcolor);
    81 	pen.setCapStyle ( Qt::RoundCap );
    82 	bottomline=scene->addLine(QLineF(1,1,1,1),pen);
    83     bottomline->setZValue(Z_LINK);
    84     bottomline->show();
    85 
    86     // Prepare showing the selection of a MapObj
    87     selected=false;
    88 
    89 	hideLinkUnselected=false;
    90 
    91 	topPad=botPad=leftPad=rightPad=0;
    92 
    93 	repositionRequest=false;
    94 
    95 	// Rel Positions
    96 	relPos=QPointF(0,0);
    97 	useRelPos=false;
    98 	useOrientation=true;
    99 
   100 	// Reset ID
   101 	objID="";
   102 }
   103 
   104 void LinkableMapObj::copy (LinkableMapObj* other)
   105 {
   106     MapObj::copy(other);
   107 	model=other->model;
   108 	bboxTotal=other->bboxTotal;
   109     setLinkStyle(other->style);
   110     setLinkColor (other->linkcolor);
   111 	relPos=other->relPos;
   112 	useOrientation=other->useOrientation;
   113 	objID=other->objID;
   114 }
   115 
   116 void LinkableMapObj::setModel (VymModel *vm)
   117 {
   118 	model=vm;
   119 }
   120 
   121 VymModel* LinkableMapObj::getModel()
   122 {
   123 	return model;
   124 }
   125 
   126 void LinkableMapObj::setChildObj(LinkableMapObj* o)
   127 {
   128     childObj=o;
   129 }
   130 
   131 void LinkableMapObj::setParObj(LinkableMapObj* o)
   132 {
   133     parObj=o;
   134 	mapEditor=parObj->getMapEditor();
   135 	model=parObj->getModel();	
   136 }
   137 
   138 void LinkableMapObj::setParObjTmp(LinkableMapObj*,QPointF,int)	// FIXME make pure virtual
   139 {
   140 }
   141 
   142 void LinkableMapObj::unsetParObjTmp()	// FIXME make pure virtual
   143 {
   144 }
   145 
   146 bool LinkableMapObj::hasParObjTmp()
   147 {
   148 	if (parObjTmpBuf) return true;
   149 	return false;
   150 }
   151 
   152 void LinkableMapObj::setUseRelPos (const bool &b)
   153 {
   154 	useRelPos=b;
   155 }
   156 
   157 void LinkableMapObj::setRelPos()
   158 {
   159 	if (parObj)
   160 	{	
   161 		relPos.setX (absPos.x() - parObj->getChildPos().x() );
   162 		relPos.setY (absPos.y() - parObj->getChildPos().y() );
   163 		parObj->calcBBoxSize();
   164 	}	
   165 }
   166 
   167 void LinkableMapObj::setRelPos(const QPointF &p)
   168 {
   169 	relPos=p;
   170 	if (parObj)
   171 	{		
   172 		parObj->calcBBoxSize();
   173 		requestReposition();
   174 	}
   175 }
   176 
   177 QPointF LinkableMapObj::getRelPos()
   178 {
   179 	if (!parObj) return QPointF();
   180 	return relPos;
   181 }
   182 
   183 qreal LinkableMapObj::getTopPad()
   184 {
   185 	return topPad;
   186 }
   187 
   188 qreal LinkableMapObj::getLeftPad()
   189 {
   190 	return leftPad;
   191 }
   192 
   193 qreal LinkableMapObj::getRightPad()
   194 {
   195 	return rightPad;
   196 }
   197 
   198 LinkableMapObj::Style LinkableMapObj::getDefLinkStyle ()
   199 {
   200 	if (!model)
   201 	{
   202 		qWarning ("LMO::getDefLinkStyle   model=NULL");
   203 		return UndefinedStyle;
   204 	}
   205 	Style ls=model->getMapLinkStyle();
   206 	switch (ls)
   207 	{
   208 		case Line: 
   209 			return ls;
   210 			break;
   211 		case Parabel:
   212 			return ls;
   213 			break;
   214 		case PolyLine:	
   215 			if (depth>1)
   216 				return Line;
   217 			else	
   218 				return ls;
   219 			break;
   220 		case PolyParabel:	
   221 			if (depth>1)
   222 				return Parabel;
   223 			else	
   224 				return ls;
   225 			break;
   226 		default: 
   227 			break;	
   228 	}	
   229 	return UndefinedStyle;
   230 }
   231 
   232 void LinkableMapObj::setLinkStyle(Style newstyle)
   233 {
   234 	//if (newstyle=style) return;
   235 	delLink();
   236 		
   237 	style=newstyle;
   238 
   239     if (childObj!=NULL && parObj != NULL)
   240     {
   241 		QGraphicsLineItem *cl;
   242 		switch (style)
   243 		{
   244 			case UndefinedStyle:
   245 				bottomline->hide();
   246 				break;
   247 			case Line: 
   248 				l = scene->addLine(QLineF(1,1,1,1),pen);
   249 				l->setZValue(Z_LINK);
   250 				if (visible)
   251 					l->show();
   252 				else
   253 					l->hide();
   254 				break;
   255 			case Parabel:
   256 				for (int i=0;i<arcsegs;i++)
   257 				{
   258 					cl = scene->addLine(QLineF(i*5,0,i*10,100),pen);
   259 					cl->setZValue(Z_LINK);
   260 					if (visible)
   261 						cl->show();
   262 					else
   263 						cl->hide();
   264 					segment.append(cl);
   265 				}
   266 				pa0.resize (arcsegs+1);
   267 				break;
   268 			case PolyLine:	
   269 				p =scene->addPolygon(QPolygonF(),pen,linkcolor);
   270 				p->setZValue(Z_LINK);
   271 				if (visible)
   272 					p->show();
   273 				else
   274 					p->hide();
   275 				pa0.resize (3);
   276 				break;
   277 			case PolyParabel:	
   278 				p = scene->addPolygon(QPolygonF(),pen,linkcolor);
   279 				p->setZValue(Z_LINK);
   280 				if (visible)
   281 					p->show();
   282 				else
   283 					p->hide();
   284 				pa0.resize (arcsegs*2+2);
   285 				pa1.resize (arcsegs+1);
   286 				pa2.resize (arcsegs+1);
   287 				break;
   288 			default: 
   289 				break;	
   290 		}	
   291 	} 
   292 }
   293 
   294 LinkableMapObj::Style LinkableMapObj::getLinkStyle()
   295 {
   296 	return style;
   297 }
   298 
   299 void LinkableMapObj::setHideLinkUnselected(bool b)
   300 {
   301 	hideLinkUnselected=b;
   302 	setVisibility (visible);
   303 	updateLink();
   304 }
   305 
   306 bool LinkableMapObj::getHideLinkUnselected()
   307 {
   308 	return hideLinkUnselected;
   309 }
   310 
   311 void LinkableMapObj::setLinkPos(Position lp)
   312 {
   313 	linkpos=lp;
   314 }
   315 
   316 LinkableMapObj::Position LinkableMapObj::getLinkPos()
   317 {
   318 	return linkpos;
   319 }
   320 
   321 void LinkableMapObj::setID (const QString &s)
   322 {
   323 	objID=s;
   324 }
   325 
   326 QString LinkableMapObj::getID()
   327 {
   328 	return objID;
   329 }
   330 
   331 void LinkableMapObj::setLinkColor()
   332 {
   333 	// Overloaded in BranchObj and children
   334 	// here only set default color
   335 	if (model)
   336 		setLinkColor (model->getMapDefLinkColor());
   337 }
   338 
   339 void LinkableMapObj::setLinkColor(QColor col)
   340 {
   341 	linkcolor=col;
   342 	pen.setColor(col);
   343     bottomline->setPen( pen );
   344 	switch (style)
   345 	{
   346 		case Line:
   347 			l->setPen( pen);
   348 			break;	
   349 		case Parabel:	
   350 			for (int i=0; i<segment.size(); ++i)
   351 				segment.at(i)->setPen( pen);
   352 			break;
   353 		case PolyLine:
   354 			p->setBrush( QBrush(col));
   355 			p->setPen( pen);
   356 			break;
   357 		case PolyParabel:	
   358 			p->setBrush( QBrush(col));
   359 			p->setPen( pen);
   360 			break;
   361 		default:
   362 			break;
   363 	} // switch (style)	
   364 }
   365 
   366 QColor LinkableMapObj::getLinkColor()
   367 {
   368 	return linkcolor;
   369 }
   370 
   371 void LinkableMapObj::setVisibility (bool v)
   372 {
   373 	MapObj::setVisibility (v);
   374 	bool visnow=visible;
   375 
   376 	// We can hide the link, while object is not selected
   377 	if (hideLinkUnselected && !selected)
   378 		visnow=false;
   379 
   380 	if (visnow) 
   381 	{
   382 		bottomline->show();
   383 		switch (style)
   384 		{
   385 			case Line:
   386 				if (l) l->show();
   387 				break;
   388 			case Parabel:	
   389 				for (int i=0; i<segment.size(); ++i)
   390 					segment.at(i)->show();
   391 				break;	
   392 			case PolyLine:
   393 				if (p) p->show();
   394 				break;
   395 			case PolyParabel:	
   396 				if (p) p->show();
   397 				break;
   398 			default:
   399 				break;
   400 		}
   401 	} else 
   402 	{
   403 		bottomline->hide();
   404 		switch (style)
   405 		{
   406 			case Line:
   407 				if (l) l->hide();
   408 				break;
   409 			case Parabel:	
   410 				for (int i=0; i<segment.size(); ++i)
   411 					segment.at(i)->hide();
   412 				break;	
   413 			case PolyLine:
   414 				if (p) p->hide();
   415 				break;
   416 			case PolyParabel:	
   417 				if (p) p->hide();
   418 				break;
   419 			default:
   420 				break;
   421 		}
   422 	}	
   423 }
   424 
   425 void LinkableMapObj::setOrientation()
   426 {
   427 	Orientation orientOld=orientation;
   428 
   429 	if (!parObj) 
   430 	{
   431 		orientation=UndefinedOrientation;
   432 		return;
   433 	}
   434 		
   435     // Set orientation, first look for orientation of parent
   436     if (parObj->getOrientation() != UndefinedOrientation ) 
   437 		// use the orientation of the parent:
   438 		orientation=parObj->getOrientation();
   439     else
   440     {
   441 		// calc orientation depending on position rel to parent
   442 		if (absPos.x() < QPointF(parObj->getChildPos() ).x() )
   443 			orientation=LeftOfCenter; 
   444 		else
   445 			orientation=RightOfCenter;
   446     }
   447 	if (orientOld!=orientation) requestReposition();
   448 }
   449 
   450 void LinkableMapObj::updateLink()
   451 {
   452     // needs:
   453     //	childPos of parent
   454     //	orient   of parent
   455     //	style
   456     // 
   457     // sets:
   458     //	orientation
   459     //	childPos	(by calling setDockPos())
   460     //	parPos		(by calling setDockPos())
   461 	//  bottomlineY
   462     //	drawing of the link itself
   463 
   464 	// updateLink is called from move, but called from constructor we don't
   465 	// have parents yet...
   466 	if (style==UndefinedStyle) return;	
   467 
   468 	switch (linkpos)
   469 	{
   470 		case Middle:
   471 			bottomlineY=bbox.top() + bbox.height()/2;	// draw link to middle (of frame)
   472 			break;
   473 		case Bottom:
   474 			bottomlineY=bbox.bottom()-1;	// draw link to bottom of box
   475 			break;
   476 	}
   477 	
   478     double p2x,p2y;								// Set P2 Before setting
   479 	if (!link2ParPos)
   480 	{
   481 		p2x=QPointF( parObj->getChildPos() ).x();	// P1, we have to look at
   482 		p2y=QPointF( parObj->getChildPos() ).y();	// orientation
   483 	} else	
   484 	{
   485 		p2x=QPointF( parObj->getParPos() ).x();	
   486 		p2y=QPointF( parObj->getParPos() ).y();
   487 	} 
   488 
   489 	setDockPos(); // Call overloaded method
   490 	setOrientation();
   491 
   492 	double p1x=parPos.x();	// Link is drawn from P1 to P2
   493 	double p1y=parPos.y();
   494 
   495 	double vx=p2x - p1x;	// V=P2-P1
   496 	double vy=p2y - p1y;
   497 
   498 	// Draw the horizontal line below heading (from ChildPos to ParPos)
   499 	//bottomline->prepareGeometryChange();
   500 	bottomline->setLine (QLine (qRound(childPos.x()),
   501 		qRound(childPos.y()),
   502 		qRound(p1x),
   503 		qRound(p1y) ));
   504 
   505 	double a;	// angle
   506 	if (vx > -0.000001 && vx < 0.000001)
   507 		a=M_PI_2;
   508 	else
   509 		a=atan( vy / vx );
   510 	// "turning point" for drawing polygonal links
   511 	QPointF tp (-qRound(sin (a)*thickness_start), qRound(cos (a)*thickness_start));	
   512 	
   513     // Draw the link
   514 	switch (style)
   515 	{
   516 		case Line:
   517 			//l->prepareGeometryChange();
   518 			l->setLine( QLine(qRound (parPos.x()),
   519 				qRound(parPos.y()),
   520 				qRound(p2x),
   521 				qRound(p2y) ));
   522 			break;	
   523 		case Parabel:	
   524 			parabel (pa0, p1x,p1y,p2x,p2y);
   525 			for (int i=0; i<segment.size(); ++i)
   526 			{
   527 				//segment.at(i)->prepareGeometryChange();
   528 				segment.at(i)->setLine(QLineF( pa0.at(i).x(), pa0.at(i).y(),pa0.at(i+1).x(),pa0.at(i+1).y()));
   529 			}	
   530 			break;
   531 		case PolyLine:
   532 			pa0.clear();
   533 			pa0<<QPointF (qRound(p2x+tp.x()), qRound(p2y+tp.y()));
   534 			pa0<<QPointF (qRound(p2x-tp.x()), qRound(p2y-tp.y()));
   535 			pa0<<QPointF (qRound (parPos.x()), qRound(parPos.y()) );
   536 			//p->prepareGeometryChange();
   537 			p->setPolygon(QPolygonF (pa0));
   538 			break;
   539 		case PolyParabel:	
   540 			parabel (pa1, p1x,p1y,p2x+tp.x(),p2y+tp.y());
   541 			parabel (pa2, p1x,p1y,p2x-tp.x(),p2y-tp.y());
   542 			pa0.clear();
   543 			for (int i=0;i<=arcsegs;i++)
   544 				pa0 << QPointF (pa1.at(i));
   545 			for (int i=0;i<=arcsegs;i++)
   546 				pa0 << QPointF (pa2.at(arcsegs-i));
   547 			//p->prepareGeometryChange();
   548 			p->setPolygon(QPolygonF (pa0));
   549 			break;
   550 		default:
   551 			break;
   552 	} // switch (style)	
   553 }
   554 	
   555 LinkableMapObj* LinkableMapObj::getChildObj()
   556 {
   557     return childObj;
   558 }
   559 
   560 LinkableMapObj* LinkableMapObj::getParObj()
   561 {
   562     return parObj;
   563 }
   564 
   565 LinkableMapObj* LinkableMapObj::findObjBySelect (QString s)
   566 {
   567 	LinkableMapObj *lmo=this;
   568 	QString part;
   569 	QString typ;
   570 	QString num;
   571 	while (!s.isEmpty() )
   572 	{
   573 		part=s.section(",",0,0);
   574 		typ=part.left (3);
   575 		num=part.right(part.length() - 3);
   576 		if (typ=="mc:")
   577 		{
   578 			if (depth>0)
   579 				return false;	// in a subtree there is no center
   580 			else
   581 				break;
   582 		} else
   583 			if (typ=="bo:")
   584 				lmo=((BranchObj*)lmo)->getBranchNum (num.toInt());
   585 			else
   586 				if (typ=="fi:")
   587 					lmo=((BranchObj*)lmo)->getFloatImageNum (num.toUInt());
   588 		if (!lmo) break;
   589 		
   590 		if (s.contains(","))
   591 			s=s.right(s.length() - part.length() -1 );
   592 		else	
   593 			break;
   594 	}
   595 	return lmo;
   596 }
   597 
   598 QPointF LinkableMapObj::getChildPos()
   599 {
   600     return childPos;
   601 }
   602 
   603 QPointF LinkableMapObj::getParPos()
   604 {
   605     return parPos;
   606 }
   607 
   608 void LinkableMapObj::setUseOrientation (const bool &b)
   609 {	
   610 	if (useOrientation!=b)
   611 	{
   612 		useOrientation=b;
   613 		requestReposition();
   614 	}	
   615 }
   616 
   617 LinkableMapObj::Orientation LinkableMapObj::getOrientation()
   618 {
   619     return orientation;
   620 }
   621 
   622 int LinkableMapObj::getDepth()
   623 {
   624     return depth;
   625 }
   626 
   627 void LinkableMapObj::setMapEditor (MapEditor *me)
   628 {
   629 	mapEditor=me;
   630 	model=mapEditor->getModel();
   631 }
   632 
   633 MapEditor* LinkableMapObj::getMapEditor ()
   634 {
   635 	return mapEditor;
   636 }
   637 
   638 QPointF LinkableMapObj::getRandPos()
   639 {
   640 	// Choose a random position with given distance to parent:
   641 	double a=rand()%360 * 2 * M_PI / 360;
   642     return QPointF ( (int)( + 150*cos (a)),
   643                     (int)( + 150*sin (a)));
   644 }
   645 
   646 void LinkableMapObj::reposition()
   647 {
   648 }
   649 
   650 void LinkableMapObj::requestReposition()
   651 {
   652 	if (!repositionRequest)
   653 	{
   654 		// Pass on the request to parental objects, if this hasn't
   655 		// been done yet
   656 		repositionRequest=true;
   657 		if (parObj) parObj->requestReposition();
   658 	}
   659 }
   660 
   661 void LinkableMapObj::forceReposition()
   662 {
   663 	// Sometimes a reposition has to be done immediatly: For example
   664 	// if the note editor flag changes, there is no user event in mapeditor
   665 	// which could collect requests for a reposition.
   666 	// Then we have to call forceReposition()
   667 	// But no rule without exception: While loading a map or undoing it,
   668 	// we want to block expensive repositioning, but just do it once at
   669 	// the end, thus check first:
   670 
   671 	if (model->isRepositionBlocked()) return;	
   672 	
   673 	// Pass on the request to parent objects, if this hasn't been done yet
   674 	if (parObj) 
   675 		parObj->forceReposition(); 
   676 	else 
   677 		reposition(); 
   678 }
   679 
   680 bool LinkableMapObj::repositionRequested()
   681 {
   682 	return repositionRequest;
   683 }
   684 
   685 
   686 void LinkableMapObj::select()
   687 {
   688 	// select and unselect are still needed to
   689 	// handle hiding of links
   690     selected=true;
   691 	setVisibility (visible);
   692 }
   693 
   694 
   695 void LinkableMapObj::unselect()
   696 {
   697     selected=false;
   698 	// Maybe we have to hide the link:
   699 	setVisibility (visible);
   700 }
   701 
   702 void LinkableMapObj::parabel (QPolygonF &ya, double p1x, double p1y, double p2x, double p2y)
   703 
   704 {
   705 	double vx=p2x - p1x;	// V=P2-P1
   706 	double vy=p2y - p1y;
   707 
   708 	double dx;				// delta x during calculation of parabel
   709 	
   710 	double pnx;				// next point
   711 	double pny;
   712 	double m;
   713 
   714 	if (vx > -0.0001 && vx < 0.0001)
   715 		m=0;
   716 	else	
   717 		m=(vy / (vx*vx));
   718 	dx=vx/(arcsegs);
   719 	ya.clear();
   720 	ya<<QPointF (p1x,p1y);
   721 	for (int i=1;i<=arcsegs;i++)
   722 	{	
   723 		pnx=p1x+dx;
   724 		pny=m*(pnx-parPos.x())*(pnx-parPos.x())+parPos.y();
   725 		ya<<QPointF (pnx,pny);
   726 		p1x=pnx;
   727 		p1y=pny;
   728 	}	
   729 }
   730 
   731 QString LinkableMapObj::getLinkAttr ()
   732 {
   733 	if (hideLinkUnselected)
   734 		return attribut ("hideLink","true");
   735 	else
   736 		return attribut ("hideLink","false");
   737 	
   738 }
   739