branchobj.cpp
author insilmaril
Tue, 03 Jan 2006 09:44:41 +0000
changeset 168 8814a667241a
parent 166 325958acb69b
child 169 aa48c7b52549
permissions -rw-r--r--
1.7.6 New features for floatimages and fixes
     1 #include "branchobj.h"
     2 #include "texteditor.h"
     3 #include "mapeditor.h"
     4 #include "mainwindow.h"
     5 
     6 extern TextEditor *textEditor;
     7 extern Main *mainWindow;
     8 extern FlagRowObj *standardFlagsDefault;
     9 extern QAction *actionEditOpenURL;
    10 
    11 
    12 /////////////////////////////////////////////////////////////////
    13 // BranchObj
    14 /////////////////////////////////////////////////////////////////
    15 
    16 BranchObj* BranchObj::itLast=NULL;
    17 
    18 
    19 BranchObj::BranchObj () :OrnamentedObj()
    20 {
    21 //    cout << "Const BranchObj ()\n";
    22     setParObj (this);	
    23     init();
    24     depth=-1;
    25 }
    26 
    27 BranchObj::BranchObj (QCanvas* c):OrnamentedObj (c)
    28 {
    29 //    cout << "Const BranchObj (c)  called from MapCenterObj (c)\n";
    30 	parObj=NULL;
    31     canvas=c;
    32 }
    33 
    34 BranchObj::BranchObj (QCanvas* c, LinkableMapObj* p):OrnamentedObj (c)
    35 {
    36 //    cout << "Const BranchObj (c,p)\n";
    37     canvas=c;
    38     setParObj (p);	
    39     depth=p->getDepth()+1;
    40 	if (depth==1)
    41 		// Calc angle to mapCenter if I am a mainbranch
    42 		// needed for reordering the mainbranches clockwise 
    43 		// around mapcenter 
    44 		angle=getAngle (QPoint ((int)(x() - parObj->getChildPos().x() ), 
    45 								(int)(y() - parObj->getChildPos().y() ) ) );
    46     init();
    47 }
    48 
    49 BranchObj::~BranchObj ()
    50 {
    51 //	cout << "Destr BranchObj of "<<this<<endl;
    52 	// Check, if this branch was the last child to be deleted
    53 	// If so, unset the scrolled flags
    54 
    55 	BranchObj *po=(BranchObj*)(parObj);
    56 	BranchObj *bo;
    57 	if (po)
    58 	{
    59 		bo=((BranchObj*)(parObj))->getLastBranch();
    60 		if (!bo) po->unScroll();
    61 	}
    62 	clear();
    63 }
    64 
    65 bool BranchObj::operator< ( const BranchObj & other )
    66 {
    67     return  angle < other.angle;
    68 }
    69 
    70 bool BranchObj::operator== ( const BranchObj & other )
    71 {
    72     return angle == other.angle;
    73 }
    74 
    75 int BranchObjPtrList::compareItems ( QPtrCollection::Item i, QPtrCollection::Item j)
    76 {
    77 	// Make sure PtrList::find works
    78 	if (i==j) return 0;
    79 
    80 	if ( ((BranchObj*)(i))->angle > ((BranchObj*)(j))->angle )
    81 		return 1;
    82 	else
    83 		return -1;
    84 }
    85 
    86 void BranchObj::init () 
    87 {
    88     branch.setAutoDelete (false);
    89     floatimage.setAutoDelete (true);
    90     xlink.setAutoDelete (false);
    91 
    92 	if (parObj)
    93 	{
    94 		absPos=getRandPos();
    95 		absPos+=parObj->getChildPos();
    96 	}
    97 
    98     lastSelectedBranch=-1;
    99 
   100     setChildObj(this);
   101 
   102 	scrolled=false;
   103 	tmpUnscrolled=false;
   104 
   105 	url="";
   106 	vymLink="";
   107 }
   108 
   109 void BranchObj::copy (BranchObj* other)
   110 {
   111     OrnamentedObj::copy(other);
   112 
   113 	branch.clear();
   114     BranchObj* b;
   115     for (b=other->branch.first(); b;b=other->branch.next() ) 
   116 		// Make deep copy of b
   117 		// Because addBranch again calls copy for the childs,
   118 		// Those will get a deep copy, too
   119 		addBranch(b);	
   120 
   121 	FloatImageObj *fi;
   122 	for (fi=other->floatimage.first(); fi;fi=other->floatimage.next() )
   123 		addFloatImage (fi);
   124 
   125 	scrolled=other->scrolled;
   126 	tmpUnscrolled=other->tmpUnscrolled;
   127 	setVisibility (other->visible);
   128 
   129 	url=other->url;
   130 	vymLink=other->vymLink;
   131 
   132 	angle=other->angle;
   133 
   134     positionBBox();
   135 }
   136 
   137 void BranchObj::clear() 
   138 {
   139 	floatimage.clear();
   140 	while (!xlink.isEmpty())
   141 		deleteXLink (xlink.first() );
   142 
   143 	BranchObj *bo;
   144 	while (!branch.isEmpty())
   145 	{
   146 		bo=branch.first();
   147 		branch.removeFirst();
   148 		delete (bo);
   149 	}
   150 }
   151 
   152 int BranchObj::getNum()
   153 {
   154 	if (parObj)
   155 		return ((BranchObj*)(parObj))->getNum ((BranchObj*)(this));
   156 	else
   157 		return 0;
   158 }
   159 
   160 int BranchObj::getNum(BranchObj *bo)
   161 {
   162 	// keep current pointer in branch, 
   163 	// otherwise save might fail
   164 	int cur=branch.at();
   165 	int ind=branch.findRef (bo);
   166 	branch.at(cur);
   167 	return ind;
   168 }
   169 
   170 int BranchObj::getFloatImageNum(FloatImageObj *fio)
   171 {
   172 	return floatimage.findRef (fio);
   173 }
   174 
   175 int BranchObj::countBranches()
   176 {
   177 	return branch.count();
   178 }
   179 
   180 int BranchObj::countFloatImages()
   181 {
   182 	return floatimage.count();
   183 }
   184 
   185 int BranchObj::countXLinks()
   186 {
   187 	return xlink.count();
   188 }
   189 
   190 void BranchObj::setParObjTmp(LinkableMapObj* lmo, QPoint m, int off)
   191 {
   192 	// Temporary link to lmo
   193 	// m is position of mouse pointer 
   194 	// offset 0: default 1: below lmo   -1 above lmo  (if possible)
   195 
   196 
   197 	BranchObj* o=(BranchObj*)(lmo);
   198 	if (!parObjTmpBuf) 
   199 		parObjTmpBuf=parObj;
   200 
   201 	// ignore mapcenter and mainbranch
   202 	if (lmo->getDepth()<2) off=0;
   203 	if (off==0)
   204 		link2ParPos=false;
   205 	else
   206 		link2ParPos=true;
   207 	parObj=o;
   208 
   209 	depth=parObj->getDepth()+1;
   210 
   211 	// setLinkStyle calls updateLink, only set it once
   212 	if (style!=getDefLinkStyle() ) setLinkStyle (getDefLinkStyle());
   213 
   214 	// Move temporary to new position at destination
   215 	// Usually the positioning would be done by reposition(),
   216 	// but then also the destination branch would "Jump" around...
   217 	// Better just do it approximately
   218 	if (depth==1)
   219 	{	// new parent is the mapcenter itself
   220 
   221 		QPoint p= normalise ( QPoint (m.x() - o->getChildPos().x(),
   222 									  m.y() - o->getChildPos().y() ));
   223 		if (p.x()<0) p.setX( p.x()-bbox.width() );
   224 		move2RelPos (p);
   225 	} else
   226 	{	
   227 		int y;
   228 		if (off==0)
   229 		{
   230 			// new parent is just a branch, link to it
   231 			QRect t=o->getBBoxSizeWithChilds();
   232 			if (o->getLastBranch())
   233 				y=t.y() + t.height() ;
   234 			else
   235 				y=t.y();
   236 
   237 		} else
   238 		{
   239 			if (off<0)
   240 				// we want to link above lmo
   241 				y=o->y() - height() + 5;
   242 			else	
   243 				// we want to link below lmo
   244 				// Bottom of sel should be 5 pixels above
   245 				// the bottom of the branch _below_ the target:
   246 				// Don't try to find that branch, guess 12 pixels
   247 				y=o->getChildPos().y()  -height() + 12; 
   248 		}	
   249 		if (o->getOrientation()==OrientLeftOfCenter)
   250 			move ( o->getChildPos().x() - linkwidth, y );
   251 		else	
   252 			move (o->getChildPos().x() + linkwidth, y );
   253 	}	
   254 
   255 	// updateLink is called implicitly in move
   256 	reposition();	// FIXME shouldn't be this a request?
   257 }
   258 
   259 void BranchObj::unsetParObjTmp()
   260 {
   261 	if (parObjTmpBuf) 
   262 	{
   263 		link2ParPos=false;
   264 		parObj=parObjTmpBuf;
   265 		parObjTmpBuf=NULL;
   266 		depth=parObj->getDepth()+1;
   267 		setLinkStyle (getDefLinkStyle() );
   268 		updateLink();
   269 	}		
   270 }
   271 
   272 void BranchObj::unScroll()
   273 {
   274 	if (tmpUnscrolled) resetTmpUnscroll();
   275 	if (scrolled) toggleScroll();
   276 }
   277 
   278 void BranchObj::toggleScroll()
   279 {
   280 	BranchObj *bo;
   281 	if (scrolled)
   282 	{
   283 		scrolled=false;
   284 		systemFlags->deactivate("scrolledright");
   285 		for (bo=branch.first(); bo; bo=branch.next() )
   286 		{
   287 			bo->setVisibility(true);
   288 		}
   289 	} else
   290 	{
   291 		scrolled=true;
   292 		systemFlags->activate("scrolledright");
   293 		for (bo=branch.first(); bo; bo=branch.next() )
   294 		{
   295 			bo->setVisibility(false);
   296 		}
   297 	}
   298 	calcBBoxSize();
   299 	positionBBox();	
   300 	move (absPos.x(), absPos.y() );
   301 	forceReposition();
   302 }
   303 
   304 bool BranchObj::isScrolled()
   305 {
   306 	return scrolled;
   307 }
   308 
   309 bool BranchObj::hasScrolledParent(BranchObj *start)
   310 {
   311 	// Calls parents recursivly to
   312 	// find out, if we are scrolled at all.
   313 	// But ignore myself, just look at parents.
   314 
   315 	if (this !=start && scrolled) return true;
   316 
   317 	BranchObj* bo=(BranchObj*)(parObj);
   318 	if (bo) 
   319 		return bo->hasScrolledParent(start);
   320 	else
   321 		return false;
   322 }
   323 
   324 void BranchObj::tmpUnscroll()
   325 {
   326 	// Unscroll parent (recursivly)
   327 	BranchObj* bo=(BranchObj*)(parObj);
   328 	if (bo) bo->tmpUnscroll();
   329 		
   330 	// Unscroll myself
   331 	if (scrolled)
   332 	{
   333 		tmpUnscrolled=true;
   334 		systemFlags->activate("tmpUnscrolledright");
   335 		toggleScroll();
   336 	}	
   337 }
   338 
   339 void BranchObj::resetTmpUnscroll()
   340 {
   341 	// Unscroll parent (recursivly)
   342 	BranchObj* bo=(BranchObj*)(parObj);
   343 	if (bo)
   344 		bo->resetTmpUnscroll();
   345 		
   346 	// Unscroll myself
   347 	if (tmpUnscrolled)
   348 	{
   349 		tmpUnscrolled=false;
   350 		systemFlags->deactivate("tmpUnscrolledright");
   351 		toggleScroll();
   352 	}	
   353 }
   354 
   355 void BranchObj::setVisibility(bool v, int toDepth)
   356 {
   357     if (depth <= toDepth)
   358     {
   359 		frame->setVisibility(v);
   360 		heading->setVisibility(v);
   361 		systemFlags->setVisibility(v);
   362 		standardFlags->setVisibility(v);
   363 		LinkableMapObj::setVisibility (v);
   364 		
   365 		if (!scrolled && (depth < toDepth))
   366 		{
   367 			// Now go recursivly through all childs
   368 			BranchObj* b;
   369 			for (b=branch.first(); b;b=branch.next() ) 
   370 				b->setVisibility (v,toDepth);	
   371 			FloatImageObj *fio;
   372 			for (fio=floatimage.first(); fio; fio=floatimage.next())
   373 				fio->setVisibility (v);
   374 			XLinkObj* xlo;
   375 			for (xlo=xlink.first(); xlo;xlo=xlink.next() ) 
   376 				xlo->setVisibility ();	
   377 		}
   378     } // depth <= toDepth	
   379 	requestReposition();
   380 }	
   381 
   382 void BranchObj::setVisibility(bool v)
   383 {
   384     setVisibility (v,MAX_DEPTH);
   385 }
   386 
   387 
   388 void BranchObj::setLinkColor ()
   389 {
   390 	// Overloaded from LinkableMapObj
   391 	// BranchObj can use color of heading
   392 
   393 	if (mapEditor)
   394 		if (mapEditor->getLinkColorHint()==HeadingColor)
   395 			LinkableMapObj::setLinkColor (heading->getColor() );
   396 		else	
   397 			LinkableMapObj::setLinkColor ();
   398 }
   399 
   400 void BranchObj::setColor (QColor col, bool colorChilds)
   401 {
   402     heading->setColor(col);
   403 	setLinkColor();
   404     if (colorChilds) 
   405     {
   406 		BranchObj *bo;
   407 		for (bo=branch.first(); bo; bo=branch.next() )
   408 			bo->setColor(col,colorChilds);
   409     }	
   410 }
   411 
   412 QColor BranchObj::getColor()
   413 {
   414 	return heading->getColor();
   415 }
   416 
   417 BranchObj* BranchObj::first()
   418 {
   419 	itLast=NULL;	
   420 	return this; 
   421 }
   422 	
   423 BranchObj* BranchObj::next()
   424 {
   425 	BranchObj *lmo;
   426 	BranchObj *bo=branch.first();
   427 	BranchObj *po=(BranchObj*)(parObj);
   428 
   429 	if (!itLast)
   430 	{	// We are just beginning at the mapCenter
   431 		if (bo) 
   432 		{
   433 			itLast=this;
   434 			return bo;
   435 		}	
   436 		else
   437 		{
   438 			itLast=NULL;
   439 			return NULL;
   440 		}	
   441 	}
   442 
   443 	if (itLast==parObj)
   444 	{	// We come from above
   445 		if (bo)
   446 		{
   447 			// there are childs, go there
   448 			itLast=this;
   449 			return bo;
   450 		}	
   451 		else
   452 		{	// no childs, try to go up again
   453 			if (po)
   454 			{
   455 				// go up
   456 				itLast=this;
   457 				lmo=po->next();
   458 				itLast=this;
   459 				return lmo;
   460 
   461 			}	
   462 			else
   463 			{
   464 				// can't go up, I am mapCenter
   465 				itLast=NULL;
   466 				return NULL;
   467 			}	
   468 		}
   469 	}
   470 
   471 	// Try to find last child, we came from, in my own childs
   472 	bool searching=true;
   473 	while (bo && searching)
   474 	{
   475 		if (itLast==bo) searching=false;
   476 		bo=branch.next();
   477 	}
   478 	if (!searching)
   479 	{	// found lastLMO in my childs
   480 		if (bo)
   481 		{
   482 			// found a brother of lastLMO 
   483 			itLast=this;
   484 			return bo;
   485 		}	
   486 		else
   487 		{
   488 			if (po)
   489 			{
   490 				// go up
   491 				itLast=this;
   492 				lmo=po->next();
   493 				itLast=this;
   494 				return lmo;
   495 			}
   496 			else
   497 			{
   498 				// can't go up, I am mapCenter
   499 				itLast=NULL;
   500 				return NULL;
   501 			}	
   502 		}
   503 	}
   504 
   505 	// couldn't find last child, it must be a nephew of mine
   506 	bo=branch.first();
   507 	if (bo)
   508 	{
   509 		// proceed with my first child
   510 		itLast=this;	
   511 		return bo;
   512 	}	
   513 	else
   514 	{
   515 		// or go back to my parents
   516 		if (po)
   517 		{
   518 			// go up
   519 			itLast=this;
   520 			lmo=po->next();
   521 			itLast=this;
   522 			return lmo;
   523 		}	
   524 		else
   525 		{
   526 			// can't go up, I am mapCenter
   527 			itLast=NULL;
   528 			return NULL;
   529 		}	
   530 	}	
   531 }
   532 
   533 BranchObj* BranchObj::getLastIterator()
   534 {
   535 	return itLast;
   536 }
   537 
   538 void BranchObj::setLastIterator(BranchObj* it)
   539 {
   540 	itLast=it;
   541 }
   542 
   543 
   544 void BranchObj::move (double x, double y)
   545 {
   546 	OrnamentedObj::move (x,y);
   547     positionBBox();
   548 }
   549 
   550 void BranchObj::move (QPoint p)
   551 {
   552 	move (p.x(), p.y());
   553 }
   554 
   555 void BranchObj::moveBy (double x, double y)
   556 {
   557 	OrnamentedObj::moveBy (x,y);
   558     positionBBox();
   559     BranchObj* b;
   560     for (b=branch.first(); b;b=branch.next() ) 
   561 		b->moveBy (x,y);
   562 }
   563 	
   564 void BranchObj::moveBy (QPoint p)
   565 {
   566 	moveBy (p.x(), p.y());
   567 }
   568 
   569 
   570 void BranchObj::positionBBox()
   571 {
   572 	/*// TODO testing (optimization)
   573 	QString h=getHeading();
   574 	if (!h.isEmpty())
   575 		cout << "BO::positionBBox("<<h<<")\n";
   576 	else	
   577 		cout << "BO::positionBBox (noHeading)\n";
   578 */		
   579 
   580 	// Position contents by moving OO
   581 	OrnamentedObj::move (absPos.x(),absPos.y());
   582  
   583 	// It seems that setting x,y also affects width,height
   584 	int w_old=bbox.width();
   585 	int h_old=bbox.height();
   586     bbox.setX (absPos.x() );
   587 	bbox.setY (absPos.y() );
   588 	bbox.setWidth(w_old);
   589 	bbox.setHeight(h_old);
   590 	
   591 	setSelBox();
   592 
   593 	// set the frame
   594 	frame->setRect(QRect(bbox.x(),bbox.y(),bbox.width(),bbox.height() ) );
   595 
   596 	// Update links to other branches
   597 	XLinkObj *xlo;
   598     for (xlo=xlink.first(); xlo; xlo=xlink.next() )
   599 		xlo->updateXLink();
   600 }
   601 
   602 void BranchObj::calcBBoxSize()
   603 {
   604     QSize heading_r=heading->getSize();
   605     int heading_w=static_cast <int> (heading_r.width() );
   606     int heading_h=static_cast <int> (heading_r.height() );
   607     QSize sysflags_r=systemFlags->getSize();
   608 	int sysflags_h=sysflags_r.height();
   609 	int sysflags_w=sysflags_r.width();
   610     QSize stanflags_r=standardFlags->getSize();
   611 	int stanflags_h=stanflags_r.height();
   612 	int stanflags_w=stanflags_r.width();
   613     int w;
   614     int h;
   615 
   616 	// set width to sum of all widths
   617 	w=heading_w + sysflags_w + stanflags_w;
   618 	// set height to maximum needed height
   619 	h=max (sysflags_h,stanflags_h);
   620 	h=max (h,heading_h);
   621 
   622     w+=frame->getBorder();
   623     h+=frame->getBorder();
   624     bbox.setSize (QSize (w,h));
   625 }
   626 
   627 LinkableMapObj* BranchObj::findMapObj(QPoint p, LinkableMapObj* excludeLMO)
   628 {
   629 	// Search branches
   630     BranchObj *b;
   631     LinkableMapObj *lmo;
   632     for (b=branch.first(); b; b=branch.next() )
   633     {	
   634 		lmo=b->findMapObj(p, excludeLMO);
   635 		if (lmo != NULL) return lmo;
   636     }
   637 	
   638 	// Search myself
   639     if (inBBox (p) && (this != excludeLMO) && isVisibleObj() ) 
   640 		return this;
   641 
   642 	// Search float images
   643 	FloatImageObj *foi;
   644     for (foi=floatimage.first(); foi; foi=floatimage.next() )
   645 		if (foi->inBBox(p) && 
   646 			(foi != excludeLMO) && 
   647 			foi->getParObj()!= excludeLMO &&
   648 			foi->isVisibleObj() 
   649 		) return foi;
   650 
   651     return NULL;
   652 }
   653 
   654 void BranchObj::setHeading(QString s)
   655 {
   656 /* FIXME testing only
   657 	cout << "BO::setHeading ("<<s<<")\n";
   658 	cout << "   bo.pos="<<absPos<<endl;
   659 	cout << "   ho.pos="<<heading->getPos()<<endl;
   660 */	
   661     heading->setText(s);	// set new heading
   662 	calcBBoxSize();			// recalculate bbox
   663     positionBBox();			// rearrange contents
   664 	requestReposition();
   665 }
   666 
   667 void BranchObj::setURL(QString s)
   668 {
   669 	url=s;
   670 	if (!url.isEmpty())
   671 		systemFlags->activate("url");
   672 	else	
   673 		systemFlags->deactivate("url");
   674 	calcBBoxSize();			// recalculate bbox
   675     positionBBox();			// rearrange contents
   676 	forceReposition();
   677 }
   678 
   679 QString BranchObj::getURL()
   680 {
   681 	return url;
   682 }
   683 
   684 void BranchObj::setVymLink(QString s)
   685 {
   686 	if (!s.isEmpty())
   687 	{
   688 		// We need the relative (from loading) 
   689 		// or absolute path (from User event)
   690 		// and build the absolute path.
   691 		// Note: If we have relative, use path of
   692 		// current map to build absolute path
   693 		QDir d(s);
   694 		if (!d.path().startsWith ("/"))
   695 		{
   696 			QString p=mapEditor->getDestPath();
   697 			int i=p.findRev("/",-1);
   698 			d.setPath(p.left(i)+"/"+s);
   699 			d.convertToAbs();
   700 		}
   701 		vymLink=d.path();
   702 		systemFlags->activate("vymLink");
   703 	}	
   704 	else	
   705 	{
   706 		systemFlags->deactivate("vymLink");
   707 		vymLink="";
   708 	}	
   709 	calcBBoxSize();			// recalculate bbox
   710     positionBBox();			// rearrange contents
   711 	forceReposition();
   712 }
   713 
   714 QString BranchObj::getVymLink()
   715 {
   716 	return vymLink;
   717 }
   718 
   719 QString BranchObj::saveToDir (const QString &tmpdir,const QString &prefix, const QPoint& offset)
   720 {
   721     QString s,a;
   722 	QString scrolledAttr;
   723 	if (scrolled) 
   724 		scrolledAttr=attribut ("scrolled","yes");
   725 	else
   726 		scrolledAttr="";
   727 
   728 	QString posAttr;
   729 	if (depth<2) posAttr=
   730 		attribut("absPosX",QString().setNum(absPos.x(),10)) +
   731 		attribut("absPosY",QString().setNum(absPos.y(),10)); 
   732 	else
   733 		posAttr="";
   734 
   735 	QString linkAttr=getLinkAttr();
   736 
   737 	QString urlAttr;
   738 	if (!url.isEmpty())
   739 		urlAttr=attribut ("url",url);
   740 
   741 	QString vymLinkAttr;
   742 	if (!vymLink.isEmpty())
   743 		vymLinkAttr=attribut ("vymLink",convertToRel(mapEditor->getDestPath(),vymLink) );
   744 
   745 	QString frameAttr;
   746 	if (frame->getFrameType()!=NoFrame)
   747 		frameAttr=attribut ("frameType",frame->getFrameTypeName());
   748 	else
   749 		frameAttr="";
   750 
   751 	// save area, if not scrolled
   752 	QString areaAttr;
   753 	if (!((BranchObj*)(parObj))->isScrolled() )
   754 	{
   755 		areaAttr=
   756 			attribut("x1",QString().setNum(absPos.x()-offset.x(),10)) +
   757 			attribut("y1",QString().setNum(absPos.y()-offset.y(),10)) +
   758 			attribut("x2",QString().setNum(absPos.x()+width()-offset.x(),10)) +
   759 			attribut("y2",QString().setNum(absPos.y()+height()-offset.y(),10));
   760 
   761 	} else
   762 		areaAttr="";
   763 	
   764     s=beginElement ("branch" +scrolledAttr +posAttr +linkAttr +urlAttr +vymLinkAttr +frameAttr +areaAttr );
   765     incIndent();
   766 
   767 	// save heading
   768     s+=valueElement("heading", getHeading(),
   769 		attribut ("textColor",QColor(heading->getColor()).name()));
   770 
   771 	// save names of flags set
   772 	s+=standardFlags->saveToDir(tmpdir,prefix,0);
   773 	
   774 	// save note
   775 	if (!note.isEmpty() )
   776 		s+=note.saveToDir();
   777 	
   778 	// Save branches
   779     BranchObj *bo;
   780     for (bo=branch.first(); bo; bo=branch.next() )
   781 		s+=bo->saveToDir(tmpdir,prefix,offset);
   782 
   783 	// Save FloatImages
   784 	FloatImageObj *fio;
   785 	for (fio=floatimage.first(); fio; fio=floatimage.next() )
   786 		s+=fio->saveToDir (tmpdir,prefix,offset);
   787 
   788 	// Save XLinks
   789 	XLinkObj *xlo;
   790     for (xlo=xlink.first(); xlo; xlo=xlink.next() )
   791 		s+=xlo->saveToDir();
   792 
   793     decIndent();
   794     s+=endElement   ("branch");
   795     return s;
   796 }
   797 
   798 void BranchObj::addXLink (XLinkObj *xlo)
   799 {
   800 	xlink.append (xlo);
   801 	
   802 }
   803 
   804 void BranchObj::removeXLinkRef (XLinkObj *xlo)
   805 {
   806 	xlink.remove (xlo);
   807 }
   808 
   809 void BranchObj::deleteXLink(XLinkObj *xlo)
   810 {
   811 	xlo->deactivate();
   812 	if (!xlo->isUsed()) delete (xlo);
   813 }
   814 
   815 void BranchObj::deleteXLinkAt (int i)
   816 {
   817 	XLinkObj *xlo=xlink.at(i);
   818 	xlo->deactivate();
   819 	if (!xlo->isUsed()) delete(xlo);
   820 }
   821 
   822 XLinkObj* BranchObj::XLinkAt (int i)
   823 {
   824 	return xlink.at(i);
   825 }
   826 
   827 int BranchObj::countXLink()
   828 {
   829 	return xlink.count();
   830 }
   831 
   832 BranchObj* BranchObj::XLinkTargetAt (int i)
   833 {
   834 	if (xlink.at(i))
   835 		return xlink.at(i)->otherBranch (this);
   836 	else
   837 		return NULL;
   838 }
   839 
   840 LinkableMapObj* BranchObj::addFloatImage ()
   841 {
   842 	FloatImageObj *newfi=new FloatImageObj (canvas,this);
   843 	floatimage.append (newfi);
   844 	if (hasScrolledParent(this) )
   845 		newfi->setVisibility (false);
   846 	else	
   847 		newfi->setVisibility(visible);
   848 	requestReposition();
   849 	return newfi;
   850 }
   851 
   852 LinkableMapObj* BranchObj::addFloatImage (FloatImageObj *fio)
   853 {
   854 	FloatImageObj *newfi=new FloatImageObj (canvas,this);
   855 	floatimage.append (newfi);
   856 	newfi->copy (fio);
   857 	if (hasScrolledParent(this) )
   858 		newfi->setVisibility (false);
   859 	else	
   860 		newfi->setVisibility(visible);
   861 	requestReposition();
   862 	return newfi;
   863 }
   864 
   865 FloatImageObj* BranchObj::getFirstFloatImage ()
   866 {
   867     return floatimage.first();
   868 }
   869 
   870 FloatImageObj* BranchObj::getLastFloatImage ()
   871 {
   872     return floatimage.last();
   873 }
   874 
   875 FloatImageObj* BranchObj::getFloatImageNum (const uint &i)
   876 {
   877     return floatimage.at(i);
   878 }
   879 
   880 void BranchObj::removeFloatImage (FloatImageObj *fio)
   881 {
   882 	floatimage.remove (fio);
   883 	requestReposition();
   884 }
   885 
   886 void BranchObj::savePosInAngle ()
   887 {
   888 	// Save position in angle
   889     BranchObj *b;
   890 	int i=0;
   891     for (b=branch.first(); b; b=branch.next() )
   892 	{
   893 		b->angle=i;
   894 		i++;
   895 	}
   896 }
   897 
   898 void BranchObj::setDefAttr (BranchModification mod)
   899 {
   900 	int fontsize;
   901 	switch (depth)
   902 	{
   903 		case 0: fontsize=16; break;
   904 		case 1: fontsize=12; break;
   905 		default: fontsize=10; break;
   906 	}	
   907 
   908 	setLinkColor ();
   909 	setLinkStyle(getDefLinkStyle());
   910 	QFont font("Sans Serif,8,-1,5,50,0,0,0,0,0");
   911 	font.setPointSize(fontsize);
   912 	heading->setFont(font );
   913 
   914 	if (mod==NewBranch)
   915 		setColor (((BranchObj*)(parObj))->getColor(),false);
   916 	
   917 	calcBBoxSize();
   918 }
   919 
   920 BranchObj* BranchObj::addBranch()
   921 {
   922     BranchObj* newbo=new BranchObj(canvas,this);
   923     branch.append (newbo);
   924     newbo->setParObj(this);
   925 	newbo->setDefAttr(NewBranch);
   926     newbo->setHeading ("new");
   927 	if (scrolled)
   928 		newbo->setVisibility (false);
   929 	else	
   930 		newbo->setVisibility(visible);
   931 	newbo->updateLink();	
   932 	requestReposition();
   933 	return newbo;
   934 }
   935 
   936 BranchObj* BranchObj::addBranch(BranchObj* bo)
   937 {
   938     BranchObj* newbo=new BranchObj(canvas,this);
   939     branch.append (newbo);
   940     newbo->copy(bo);
   941     newbo->setParObj(this);
   942 	newbo->setDefAttr(MovedBranch);
   943 	if (scrolled)
   944 		newbo->setVisibility (false);
   945 	else	
   946 		newbo->setVisibility(bo->visible);
   947 	newbo->updateLink();	
   948 	requestReposition();
   949 	return newbo;
   950 }
   951 
   952 BranchObj* BranchObj::addBranchPtr(BranchObj* bo)
   953 {
   954 	branch.append (bo);
   955 	bo->setParObj (this);
   956 	bo->depth=depth+1;
   957 	bo->setDefAttr(MovedBranch);
   958 	if (scrolled) tmpUnscroll();
   959 	setLastSelectedBranch (bo);
   960 	return bo;
   961 }
   962 
   963 BranchObj* BranchObj::insertBranch(int pos)
   964 {
   965 	savePosInAngle();
   966 	// Add new bo and resort branches
   967 	BranchObj *newbo=addBranch ();
   968 	newbo->angle=pos-0.5;
   969 	branch.sort();
   970 	return newbo;
   971 }
   972 
   973 BranchObj* BranchObj::insertBranch(BranchObj* bo, int pos)
   974 {
   975 	savePosInAngle();
   976 	// Add new bo and resort branches
   977 	bo->angle=pos-0.5;
   978 	BranchObj *newbo=addBranch (bo);
   979 	branch.sort();
   980 	return newbo;
   981 }
   982 
   983 BranchObj* BranchObj::insertBranchPtr (BranchObj* bo, int pos)
   984 {
   985 	savePosInAngle();
   986 	// Add new bo and resort branches
   987 	bo->angle=pos-0.5;
   988 	branch.append (bo);
   989 	bo->setParObj (this);
   990 	bo->depth=depth+1;
   991 	bo->setDefAttr (MovedBranch);
   992 	if (scrolled) tmpUnscroll();
   993 	setLastSelectedBranch (bo);
   994 	branch.sort();
   995 	return bo;
   996 }
   997 
   998 void BranchObj::removeBranchHere(BranchObj* borem)
   999 {
  1000 	// This removes the branch bo from list, but 
  1001 	// inserts its childs at the place of bo
  1002 	BranchObj *bo;
  1003 	bo=borem->getLastBranch();
  1004 	int pos=borem->getNum();
  1005 	while (bo)
  1006 	{
  1007 		bo->moveBranchTo (this,pos+1);
  1008 		bo=borem->getLastBranch();
  1009 	}	
  1010 	removeBranch (borem);
  1011 }
  1012 
  1013 void BranchObj::removeChilds()
  1014 {
  1015 	clear();
  1016 }
  1017 
  1018 void BranchObj::removeBranch(BranchObj* bo)
  1019 {
  1020     // if bo is not in branch remove returns false, we
  1021     // don't care...
  1022 	
  1023     if (branch.remove (bo))
  1024 		delete (bo);
  1025 	else
  1026 		qWarning ("BranchObj::removeBranch tried to remove non existing branch?!\n");
  1027 	requestReposition();
  1028 }
  1029 
  1030 void BranchObj::removeBranchPtr(BranchObj* bo)
  1031 {
  1032 	branch.remove (bo);
  1033 	requestReposition();
  1034 }
  1035 
  1036 void BranchObj::setLastSelectedBranch (BranchObj* bo)
  1037 {
  1038     lastSelectedBranch=branch.find(bo);
  1039 }
  1040 
  1041 BranchObj* BranchObj::getLastSelectedBranch ()
  1042 {
  1043     if (lastSelectedBranch>=0) 
  1044 	{
  1045 		BranchObj* bo=branch.at(lastSelectedBranch);
  1046 		if (bo) return bo;
  1047     }	
  1048     return branch.first();
  1049 }
  1050 
  1051 BranchObj* BranchObj::getFirstBranch ()
  1052 {
  1053     return branch.first();
  1054 }
  1055 
  1056 BranchObj* BranchObj::getLastBranch ()
  1057 {
  1058     return branch.last();
  1059 }
  1060 
  1061 BranchObj* BranchObj::getBranchNum (const uint &i)
  1062 {
  1063     return branch.at(i);
  1064 }
  1065 
  1066 
  1067 BranchObj* BranchObj::moveBranchUp(BranchObj* bo1) // move a branch up (modify myself)
  1068 {
  1069 	savePosInAngle();
  1070     int i=branch.find(bo1);
  1071     if (i>0) 
  1072 	{	// -1 if bo1 not found 
  1073 		branch.at(i)->angle--;
  1074 		branch.at(i-1)->angle++;
  1075 		branch.sort();
  1076 		return branch.at(i-1);
  1077 	} else
  1078 		return branch.at(i);
  1079 }
  1080 
  1081 BranchObj* BranchObj::moveBranchDown(BranchObj* bo1)
  1082 {
  1083 	savePosInAngle();
  1084     int i=branch.find(bo1);
  1085 	int j;
  1086 	if (branch.next())
  1087 	{
  1088 		j = branch.at();
  1089 		branch.at(i)->angle++;
  1090 		branch.at(j)->angle--;
  1091 		branch.sort();
  1092 		return branch.at(j);
  1093 	} else
  1094 		return branch.at(i);
  1095 }
  1096 
  1097 BranchObj* BranchObj::moveBranchTo (BranchObj* dst, int pos)
  1098 {
  1099 	// Find current parent and 
  1100 	// remove pointer to myself there
  1101 	if (!dst) return NULL;
  1102 	BranchObj *par=(BranchObj*)(parObj);
  1103 	if (par)
  1104 		par->removeBranchPtr (this);
  1105 	else
  1106 		return NULL;
  1107 
  1108 	// Create new pointer to myself at dst
  1109 	if (pos<0||dst->getDepth()==0)
  1110 	{	
  1111 		// links myself as last branch at dst
  1112 		dst->addBranchPtr (this);
  1113 		updateLink();
  1114 		return this;
  1115 	} else
  1116 	{
  1117 		// inserts me at pos in parent of dst
  1118 		if (par)
  1119 		{
  1120 			BranchObj *bo=dst->insertBranchPtr (this,pos);
  1121 			bo->setDefAttr(MovedBranch);
  1122 			updateLink();
  1123 			return bo;
  1124 
  1125 		} else
  1126 			return NULL;
  1127 	}	
  1128 }
  1129 
  1130 void BranchObj::alignRelativeTo (QPoint ref)
  1131 {
  1132 /* TODO testing
  1133 	if (!getHeading().isEmpty())
  1134 		cout << "BO::alignRelTo "<<getHeading()<<endl;
  1135 	else	
  1136 		cout << "BO::alignRelTo  ???"<<endl;
  1137 	cout << "  d="<<depth<<endl;
  1138 */	
  1139 	int th = bboxTotal.height();	
  1140 
  1141 	// If I am the mapcenter or a mainbranch, reposition heading
  1142 	if (depth<2)
  1143 	{	//FIXME optimize this   move for MCO needed to initially position text in box...
  1144 		if (depth==1)
  1145 		{
  1146 			move (absPos.x(),absPos.y());
  1147 			// Calc angle to mapCenter if I am a mainbranch
  1148 			// needed for reordering the mainbranches clockwise 
  1149 			// around mapcenter 
  1150 			angle=getAngle (QPoint ((int)(x() - parObj->getChildPos().x() ), 
  1151 									(int)(y() - parObj->getChildPos().y() ) ) );
  1152 		}	
  1153 	} 
  1154 	else
  1155     {
  1156 		// Align myself depending on orientation and parent, but
  1157 		// only if I am not the mainbranch or mapcenter itself
  1158 		switch (orientation) 
  1159 		{
  1160 			case OrientLeftOfCenter:
  1161 				move (ref.x()-bbox.width(), ref.y() + (th-bbox.height())/2 );
  1162 			break;
  1163 			case OrientRightOfCenter:	
  1164 				move (ref.x(), ref.y() + (th-bbox.height())/2 );
  1165 			break;
  1166 			default:
  1167 				cout <<"LMO::alignRelativeTo: oops, no orientation given...\n";
  1168 			break;
  1169 		}		
  1170     }		
  1171 
  1172 	FloatImageObj *fio;
  1173     for (fio=floatimage.first(); fio; fio=floatimage.next() )
  1174 		fio->reposition();
  1175 
  1176 	if (scrolled) return;
  1177 
  1178     // Set reference point for alignment of childs
  1179     QPoint ref2;
  1180     if (orientation==OrientLeftOfCenter)
  1181 		ref2.setX(childPos.x() - linkwidth);
  1182     else	
  1183 		ref2.setX(childPos.x() + linkwidth);
  1184 
  1185 	if (depth==1)
  1186 		ref2.setY(absPos.y()-(bboxTotal.height()-bbox.height())/2);
  1187 	else	
  1188 		ref2.setY(ref.y() );	
  1189 
  1190     // Align the childs depending on reference point 
  1191     BranchObj *b;
  1192     for (b=branch.first(); b; b=branch.next() )
  1193     {	
  1194 		b->alignRelativeTo (ref2);
  1195 		ref2.setY(ref2.y() + b->getBBoxSizeWithChilds().height() );
  1196     }
  1197 }
  1198 
  1199 
  1200 void BranchObj::reposition()
  1201 {	
  1202 /* TODO testing only
  1203 	if (!getHeading().isEmpty())
  1204 		cout << "BO::reposition  "<<getHeading()<<endl;
  1205 	else	
  1206 		cout << "BO::reposition  ???"<<endl;
  1207 */		
  1208 	if (depth==0)
  1209 	{
  1210 		// only calculate the sizes once. If the deepest LMO 
  1211 		// changes its height,
  1212 		// all upper LMOs have to change, too.
  1213 		calcBBoxSizeWithChilds();
  1214 	    alignRelativeTo ( QPoint (absPos.x(),
  1215 			absPos.y()-(bboxTotal.height()-bbox.height())/2) );
  1216 		branch.sort();	
  1217 	} else
  1218 	{
  1219 		// This is only important for moving branches:
  1220 		// For editing a branch it isn't called...
  1221 	    alignRelativeTo ( QPoint (absPos.x(),
  1222 							absPos.y()-(bboxTotal.height()-bbox.height())/2) );
  1223 	}
  1224 }
  1225 
  1226 
  1227 QRect BranchObj::getTotalBBox()
  1228 {
  1229 	QRect r=bbox;
  1230 
  1231 	if (scrolled) return r;
  1232 
  1233 	BranchObj* b;
  1234 	for (b=branch.first();b ;b=branch.next() )
  1235 		r=addBBox(b->getTotalBBox(),r);
  1236 
  1237 	FloatImageObj* fio;
  1238 	for (fio=floatimage.first();fio ;fio=floatimage.next() )
  1239 		r=addBBox(fio->getTotalBBox(),r);
  1240 		
  1241 	return r;
  1242 }
  1243 
  1244 QRect BranchObj::getBBoxSizeWithChilds()
  1245 {
  1246 	return bboxTotal;
  1247 }
  1248 
  1249 void BranchObj::calcBBoxSizeWithChilds()
  1250 {
  1251 	// This is called only from reposition and
  1252 	// and only for mapcenter. So it won't be
  1253 	// called more than once for a single user 
  1254 	// action
  1255 	
  1256 	// Calculate size of LMO including all childs (to align them later)
  1257 
  1258 	bboxTotal.setX(bbox.x() );
  1259 	bboxTotal.setY(bbox.y() );
  1260 
  1261 	// if branch is scrolled, ignore childs, but still consider floatimages
  1262 	if (scrolled)
  1263 	{
  1264 		bboxTotal.setWidth (bbox.width());
  1265 		bboxTotal.setHeight(bbox.height());
  1266 		return;
  1267 	}
  1268 	
  1269 	QRect r(0,0,0,0);
  1270 	QRect br;
  1271 	// Now calculate recursivly
  1272 	// sum of heights 
  1273 	// maximum of widths 
  1274 	// minimum of y
  1275 	BranchObj* b;
  1276 	for (b=branch.first();b ;b=branch.next() )
  1277 	{
  1278 		b->calcBBoxSizeWithChilds();
  1279 		br=b->getBBoxSizeWithChilds();
  1280 		r.setWidth( max (br.width(), r.width() ));
  1281 		r.setHeight(br.height() + r.height() );
  1282 		if (br.y()<bboxTotal.y()) bboxTotal.setY(br.y());
  1283 	}
  1284 	// Add myself and also
  1285 	// add width of link to sum if necessary
  1286 	if (branch.isEmpty())
  1287 		bboxTotal.setWidth (bbox.width() + r.width() );
  1288 	else	
  1289 		bboxTotal.setWidth (bbox.width() + r.width() + linkwidth);
  1290 	bboxTotal.setHeight(max (r.height(),  bbox.height() ) );
  1291 //	frame->setRect(QRect(bbox.x(),bbox.y(),bbox.width(),bbox.height() ) );
  1292 }
  1293 
  1294 void BranchObj::select()
  1295 {
  1296 	// set Text in Editor	
  1297 	textEditor->setText(note.getNote() );
  1298 	QString fnh=note.getFilenameHint();
  1299 	if (fnh!="")
  1300 		textEditor->setFilenameHint(note.getFilenameHint() );
  1301 	else	
  1302 		textEditor->setFilenameHint(getHeading() );
  1303 	textEditor->setFontHint (note.getFontHint() );
  1304 
  1305     LinkableMapObj::select();
  1306 	// Tell parent that I am selected now:
  1307 	BranchObj* po=(BranchObj*)(parObj);
  1308     if (po)	// TODO	    Try to get rid of this cast...
  1309         po->setLastSelectedBranch(this);
  1310 		
  1311 	// temporary unscroll, if we have scrolled parents somewhere
  1312 	if (parObj) ((BranchObj*)(parObj))->tmpUnscroll();
  1313 
  1314 	// Show URL and link in statusbar
  1315 	QString status;
  1316 	if (!url.isEmpty()) status+="URL: "+url+"  ";
  1317 	if (!vymLink.isEmpty()) status+="Link: "+vymLink;
  1318 	if (!status.isEmpty()) mainWindow->statusMessage (status);
  1319 
  1320 	// Update Toolbar
  1321 	standardFlags->updateToolbar();
  1322 
  1323 	// Update Browserbutton
  1324 	if (!url.isEmpty())
  1325 		actionEditOpenURL->setEnabled (true);
  1326 	else	
  1327 		actionEditOpenURL->setEnabled (false);
  1328 
  1329 	// Update actions in mapeditor
  1330 	mapEditor->updateActions();
  1331 }
  1332 
  1333 void BranchObj::unselect()
  1334 {
  1335 	LinkableMapObj::unselect();
  1336 	// Delete any messages like vymLink in StatusBar
  1337 	mainWindow->statusMessage ("");
  1338 
  1339 	// save note from editor and set flag
  1340 	// text is done by updateNoteFlag(), just save
  1341 	// filename here
  1342 	note.setFilenameHint (textEditor->getFilename());
  1343 
  1344 	// reset temporary unscroll, if we have scrolled parents somewhere
  1345 	if (parObj) ((BranchObj*)(parObj))->resetTmpUnscroll();
  1346 
  1347 	// Erase content of editor 
  1348 	textEditor->setInactive();
  1349 
  1350 	// unselect all buttons in toolbar
  1351 	standardFlagsDefault->updateToolbar();
  1352 }
  1353 
  1354 QString BranchObj::getSelectString()
  1355 {
  1356 	QString s;
  1357 	if (parObj)
  1358 	{
  1359 		if (depth==1)
  1360 			s= "bo:" + QString("%1").arg(getNum());
  1361 		else	
  1362 			s= ((BranchObj*)(parObj))->getSelectString() + ",bo:" + QString("%1").arg(getNum());
  1363 	} else
  1364 		s="mc:";
  1365 	return s;
  1366 }
  1367