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