branchobj.cpp
author insilmaril
Thu, 22 Sep 2005 12:14:23 +0000
changeset 164 d442a66e9121
parent 162 2cf3413b6ac9
child 166 325958acb69b
permissions -rw-r--r--
new way to handle tmpdir, minor changes
     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 	/*
   574 	QString h=getHeading();
   575 	if (!h.isEmpty())
   576 		cout << "BO::positionBBox("<<h<<")\n";
   577 	else	
   578 		cout << "BO::positionBBox (noHeading)\n";
   579 	*/	
   580 
   581     heading->positionBBox();
   582 	systemFlags->positionBBox();
   583 	standardFlags->positionBBox();
   584 	// It seems that setting x,y also affects width,height
   585 	int w_old=bbox.width();
   586 	int h_old=bbox.height();
   587     bbox.setX (absPos.x() );
   588 	bbox.setY (absPos.y() );
   589 	bbox.setWidth(w_old);
   590 	bbox.setHeight(h_old);
   591 	
   592 	setSelBox();
   593 
   594 	// set the frame
   595 	frame->setRect(QRect(bbox.x(),bbox.y(),bbox.width(),bbox.height() ) );
   596 
   597 	// Update links to other branches
   598 	XLinkObj *xlo;
   599     for (xlo=xlink.first(); xlo; xlo=xlink.next() )
   600 		xlo->updateXLink();
   601 }
   602 
   603 void BranchObj::calcBBoxSize()
   604 {
   605     QSize heading_r=heading->getSize();
   606     int heading_w=static_cast <int> (heading_r.width() );
   607     int heading_h=static_cast <int> (heading_r.height() );
   608     QSize sysflags_r=systemFlags->getSize();
   609 	int sysflags_h=sysflags_r.height();
   610 	int sysflags_w=sysflags_r.width();
   611     QSize stanflags_r=standardFlags->getSize();
   612 	int stanflags_h=stanflags_r.height();
   613 	int stanflags_w=stanflags_r.width();
   614     int w;
   615     int h;
   616 
   617 	// set width to sum of all widths
   618 	w=heading_w + sysflags_w + stanflags_w;
   619 	// set height to maximum needed height
   620 	h=max (sysflags_h,stanflags_h);
   621 	h=max (h,heading_h);
   622 
   623     w+=frame->getBorder();
   624     h+=frame->getBorder();
   625     bbox.setSize (QSize (w,h));
   626 }
   627 
   628 LinkableMapObj* BranchObj::findMapObj(QPoint p, LinkableMapObj* excludeLMO)
   629 {
   630 	// Search branches
   631     BranchObj *b;
   632     LinkableMapObj *lmo;
   633     for (b=branch.first(); b; b=branch.next() )
   634     {	
   635 		lmo=b->findMapObj(p, excludeLMO);
   636 		if (lmo != NULL) return lmo;
   637     }
   638 	
   639 	// Search myself
   640     if (inBBox (p) && (this != excludeLMO) && isVisibleObj() ) 
   641 		return this;
   642 
   643 	// Search float images
   644 	FloatImageObj *foi;
   645     for (foi=floatimage.first(); foi; foi=floatimage.next() )
   646 		if (foi->inBBox(p) && 
   647 			(foi != excludeLMO) && 
   648 			foi->getParObj()!= excludeLMO &&
   649 			foi->isVisibleObj() 
   650 		) return foi;
   651 
   652     return NULL;
   653 }
   654 
   655 void BranchObj::setHeading(QString s)
   656 {
   657     heading->setText(s);	// set new heading
   658 	calcBBoxSize();			// recalculate bbox
   659     positionBBox();			// rearrange contents
   660 	requestReposition();
   661 }
   662 
   663 void BranchObj::setURL(QString s)
   664 {
   665 	url=s;
   666 	if (!url.isEmpty())
   667 		systemFlags->activate("url");
   668 	else	
   669 		systemFlags->deactivate("url");
   670 	calcBBoxSize();			// recalculate bbox
   671     positionBBox();			// rearrange contents
   672 	forceReposition();
   673 }
   674 
   675 QString BranchObj::getURL()
   676 {
   677 	return url;
   678 }
   679 
   680 void BranchObj::setVymLink(QString s)
   681 {
   682 	if (!s.isEmpty())
   683 	{
   684 		// We need the relative (from loading) 
   685 		// or absolute path (from User event)
   686 		// and build the absolute path.
   687 		// Note: If we have relative, use path of
   688 		// current map to build absolute path
   689 		QDir d(s);
   690 		if (!d.path().startsWith ("/"))
   691 		{
   692 			QString p=mapEditor->getDestPath();
   693 			int i=p.findRev("/",-1);
   694 			d.setPath(p.left(i)+"/"+s);
   695 			d.convertToAbs();
   696 		}
   697 		vymLink=d.path();
   698 		systemFlags->activate("vymLink");
   699 	}	
   700 	else	
   701 	{
   702 		systemFlags->deactivate("vymLink");
   703 		vymLink="";
   704 	}	
   705 	calcBBoxSize();			// recalculate bbox
   706     positionBBox();			// rearrange contents
   707 	forceReposition();
   708 }
   709 
   710 QString BranchObj::getVymLink()
   711 {
   712 	return vymLink;
   713 }
   714 
   715 QString BranchObj::saveToDir (const QString &tmpdir,const QString &prefix, const QPoint& offset)
   716 {
   717     QString s,a;
   718 	QString scrolledAttr;
   719 	if (scrolled) 
   720 		scrolledAttr=attribut ("scrolled","yes");
   721 	else
   722 		scrolledAttr="";
   723 
   724 	QString posAttr;
   725 	if (depth<2) posAttr=
   726 		attribut("absPosX",QString().setNum(absPos.x(),10)) +
   727 		attribut("absPosY",QString().setNum(absPos.y(),10)); 
   728 	else
   729 		posAttr="";
   730 
   731 	QString linkAttr=getLinkAttr();
   732 
   733 	QString urlAttr;
   734 	if (!url.isEmpty())
   735 		urlAttr=attribut ("url",url);
   736 
   737 	QString vymLinkAttr;
   738 	if (!vymLink.isEmpty())
   739 		vymLinkAttr=attribut ("vymLink",convertToRel(mapEditor->getDestPath(),vymLink) );
   740 
   741 	QString frameAttr;
   742 	if (frame->getFrameType()!=NoFrame)
   743 		frameAttr=attribut ("frameType",frame->getFrameTypeName());
   744 	else
   745 		frameAttr="";
   746 
   747 	// save area, if not scrolled
   748 	QString areaAttr;
   749 	if (!((BranchObj*)(parObj))->isScrolled() )
   750 	{
   751 		areaAttr=
   752 			attribut("x1",QString().setNum(absPos.x()-offset.x(),10)) +
   753 			attribut("y1",QString().setNum(absPos.y()-offset.y(),10)) +
   754 			attribut("x2",QString().setNum(absPos.x()+width()-offset.x(),10)) +
   755 			attribut("y2",QString().setNum(absPos.y()+height()-offset.y(),10));
   756 
   757 	} else
   758 		areaAttr="";
   759 	
   760     s=beginElement ("branch" +scrolledAttr +posAttr +linkAttr +urlAttr +vymLinkAttr +frameAttr +areaAttr );
   761     incIndent();
   762 
   763 	// save heading
   764     s+=valueElement("heading", getHeading(),
   765 		attribut ("textColor",QColor(heading->getColor()).name()));
   766 
   767 	// save names of flags set
   768 	s+=standardFlags->saveToDir(tmpdir,prefix,0);
   769 	
   770 	// save note
   771 	if (!note.isEmpty() )
   772 		s+=note.saveToDir();
   773 	
   774 	// Save branches
   775     BranchObj *bo;
   776     for (bo=branch.first(); bo; bo=branch.next() )
   777 		s+=bo->saveToDir(tmpdir,prefix,offset);
   778 
   779 	// Save FloatImages
   780 	FloatImageObj *fio;
   781 	for (fio=floatimage.first(); fio; fio=floatimage.next() )
   782 		s+=fio->saveToDir (tmpdir,prefix);
   783 
   784 	// Save XLinks
   785 	XLinkObj *xlo;
   786     for (xlo=xlink.first(); xlo; xlo=xlink.next() )
   787 		s+=xlo->saveToDir();
   788 
   789     decIndent();
   790     s+=endElement   ("branch");
   791     return s;
   792 }
   793 
   794 void BranchObj::addXLink (XLinkObj *xlo)
   795 {
   796 	xlink.append (xlo);
   797 	
   798 }
   799 
   800 void BranchObj::removeXLinkRef (XLinkObj *xlo)
   801 {
   802 	xlink.remove (xlo);
   803 }
   804 
   805 void BranchObj::deleteXLink(XLinkObj *xlo)
   806 {
   807 	xlo->deactivate();
   808 	if (!xlo->isUsed()) delete (xlo);
   809 }
   810 
   811 void BranchObj::deleteXLinkAt (int i)
   812 {
   813 	XLinkObj *xlo=xlink.at(i);
   814 	xlo->deactivate();
   815 	if (!xlo->isUsed()) delete(xlo);
   816 }
   817 
   818 XLinkObj* BranchObj::XLinkAt (int i)
   819 {
   820 	return xlink.at(i);
   821 }
   822 
   823 int BranchObj::countXLink()
   824 {
   825 	return xlink.count();
   826 }
   827 
   828 BranchObj* BranchObj::XLinkTargetAt (int i)
   829 {
   830 	if (xlink.at(i))
   831 		return xlink.at(i)->otherBranch (this);
   832 	else
   833 		return NULL;
   834 }
   835 
   836 LinkableMapObj* BranchObj::addFloatImage ()
   837 {
   838 	FloatImageObj *newfi=new FloatImageObj (canvas,this);
   839 	floatimage.append (newfi);
   840 	if (hasScrolledParent(this) )
   841 		newfi->setVisibility (false);
   842 	else	
   843 		newfi->setVisibility(visible);
   844 	requestReposition();
   845 	return newfi;
   846 }
   847 
   848 LinkableMapObj* BranchObj::addFloatImage (FloatImageObj *fio)
   849 {
   850 	FloatImageObj *newfi=new FloatImageObj (canvas,this);
   851 	floatimage.append (newfi);
   852 	newfi->copy (fio);
   853 	if (hasScrolledParent(this) )
   854 		newfi->setVisibility (false);
   855 	else	
   856 		newfi->setVisibility(visible);
   857 	requestReposition();
   858 	return newfi;
   859 }
   860 
   861 FloatImageObj* BranchObj::getFirstFloatImage ()
   862 {
   863     return floatimage.first();
   864 }
   865 
   866 FloatImageObj* BranchObj::getLastFloatImage ()
   867 {
   868     return floatimage.last();
   869 }
   870 
   871 FloatImageObj* BranchObj::getFloatImageNum (const uint &i)
   872 {
   873     return floatimage.at(i);
   874 }
   875 
   876 void BranchObj::removeFloatImage (FloatImageObj *fio)
   877 {
   878 	floatimage.remove (fio);
   879 	requestReposition();
   880 }
   881 
   882 void BranchObj::savePosInAngle ()
   883 {
   884 	// Save position in angle
   885     BranchObj *b;
   886 	int i=0;
   887     for (b=branch.first(); b; b=branch.next() )
   888 	{
   889 		b->angle=i;
   890 		i++;
   891 	}
   892 }
   893 
   894 void BranchObj::setDefAttr (BranchModification mod)
   895 {
   896 	int fontsize;
   897 	switch (depth)
   898 	{
   899 		case 0: fontsize=16; break;
   900 		case 1: fontsize=12; break;
   901 		default: fontsize=10; break;
   902 	}	
   903 
   904 	setLinkColor ();
   905 	setLinkStyle(getDefLinkStyle());
   906 	QFont font("Sans Serif,8,-1,5,50,0,0,0,0,0");
   907 	font.setPointSize(fontsize);
   908 	heading->setFont(font );
   909 
   910 	if (mod==NewBranch)
   911 		setColor (((BranchObj*)(parObj))->getColor(),false);
   912 	
   913 	calcBBoxSize();
   914 }
   915 
   916 BranchObj* BranchObj::addBranch()
   917 {
   918     BranchObj* newbo=new BranchObj(canvas,this);
   919     branch.append (newbo);
   920     newbo->setParObj(this);
   921 	newbo->setDefAttr(NewBranch);
   922     newbo->setHeading ("new");
   923 	if (scrolled)
   924 		newbo->setVisibility (false);
   925 	else	
   926 		newbo->setVisibility(visible);
   927 	newbo->updateLink();	
   928 	requestReposition();
   929 	return newbo;
   930 }
   931 
   932 BranchObj* BranchObj::addBranch(BranchObj* bo)
   933 {
   934     BranchObj* newbo=new BranchObj(canvas,this);
   935     branch.append (newbo);
   936     newbo->copy(bo);
   937     newbo->setParObj(this);
   938 	newbo->setDefAttr(MovedBranch);
   939 	if (scrolled)
   940 		newbo->setVisibility (false);
   941 	else	
   942 		newbo->setVisibility(bo->visible);
   943 	newbo->updateLink();	
   944 	requestReposition();
   945 	return newbo;
   946 }
   947 
   948 BranchObj* BranchObj::addBranchPtr(BranchObj* bo)
   949 {
   950 	branch.append (bo);
   951 	bo->setParObj (this);
   952 	bo->depth=depth+1;
   953 	bo->setDefAttr(MovedBranch);
   954 	if (scrolled) tmpUnscroll();
   955 	setLastSelectedBranch (bo);
   956 	return bo;
   957 }
   958 
   959 BranchObj* BranchObj::insertBranch(int pos)
   960 {
   961 	savePosInAngle();
   962 	// Add new bo and resort branches
   963 	BranchObj *newbo=addBranch ();
   964 	newbo->angle=pos-0.5;
   965 	branch.sort();
   966 	return newbo;
   967 }
   968 
   969 BranchObj* BranchObj::insertBranch(BranchObj* bo, int pos)
   970 {
   971 	savePosInAngle();
   972 	// Add new bo and resort branches
   973 	bo->angle=pos-0.5;
   974 	BranchObj *newbo=addBranch (bo);
   975 	branch.sort();
   976 	return newbo;
   977 }
   978 
   979 BranchObj* BranchObj::insertBranchPtr (BranchObj* bo, int pos)
   980 {
   981 	savePosInAngle();
   982 	// Add new bo and resort branches
   983 	bo->angle=pos-0.5;
   984 	branch.append (bo);
   985 	bo->setParObj (this);
   986 	bo->depth=depth+1;
   987 	bo->setDefAttr (MovedBranch);
   988 	if (scrolled) tmpUnscroll();
   989 	setLastSelectedBranch (bo);
   990 	branch.sort();
   991 	return bo;
   992 }
   993 
   994 void BranchObj::removeBranchHere(BranchObj* borem)
   995 {
   996 	// This removes the branch bo from list, but 
   997 	// inserts its childs at the place of bo
   998 	BranchObj *bo;
   999 	bo=borem->getLastBranch();
  1000 	int pos=borem->getNum();
  1001 	while (bo)
  1002 	{
  1003 		bo->moveBranchTo (this,pos+1);
  1004 		bo=borem->getLastBranch();
  1005 	}	
  1006 	removeBranch (borem);
  1007 }
  1008 
  1009 void BranchObj::removeChilds()
  1010 {
  1011 	clear();
  1012 }
  1013 
  1014 void BranchObj::removeBranch(BranchObj* bo)
  1015 {
  1016     // if bo is not in branch remove returns false, we
  1017     // don't care...
  1018 	
  1019     if (branch.remove (bo))
  1020 		delete (bo);
  1021 	else
  1022 		qWarning ("BranchObj::removeBranch tried to remove non existing branch?!\n");
  1023 	requestReposition();
  1024 }
  1025 
  1026 void BranchObj::removeBranchPtr(BranchObj* bo)
  1027 {
  1028 	branch.remove (bo);
  1029 	requestReposition();
  1030 }
  1031 
  1032 void BranchObj::setLastSelectedBranch (BranchObj* bo)
  1033 {
  1034     lastSelectedBranch=branch.find(bo);
  1035 }
  1036 
  1037 BranchObj* BranchObj::getLastSelectedBranch ()
  1038 {
  1039     if (lastSelectedBranch>=0) 
  1040 	{
  1041 		BranchObj* bo=branch.at(lastSelectedBranch);
  1042 		if (bo) return bo;
  1043     }	
  1044     return branch.first();
  1045 }
  1046 
  1047 BranchObj* BranchObj::getFirstBranch ()
  1048 {
  1049     return branch.first();
  1050 }
  1051 
  1052 BranchObj* BranchObj::getLastBranch ()
  1053 {
  1054     return branch.last();
  1055 }
  1056 
  1057 BranchObj* BranchObj::getBranchNum (const uint &i)
  1058 {
  1059     return branch.at(i);
  1060 }
  1061 
  1062 
  1063 BranchObj* BranchObj::moveBranchUp(BranchObj* bo1) // move a branch up (modify myself)
  1064 {
  1065 	savePosInAngle();
  1066     int i=branch.find(bo1);
  1067     if (i>0) 
  1068 	{	// -1 if bo1 not found 
  1069 		branch.at(i)->angle--;
  1070 		branch.at(i-1)->angle++;
  1071 		branch.sort();
  1072 		return branch.at(i-1);
  1073 	} else
  1074 		return branch.at(i);
  1075 }
  1076 
  1077 BranchObj* BranchObj::moveBranchDown(BranchObj* bo1)
  1078 {
  1079 	savePosInAngle();
  1080     int i=branch.find(bo1);
  1081 	int j;
  1082 	if (branch.next())
  1083 	{
  1084 		j = branch.at();
  1085 		branch.at(i)->angle++;
  1086 		branch.at(j)->angle--;
  1087 		branch.sort();
  1088 		return branch.at(j);
  1089 	} else
  1090 		return branch.at(i);
  1091 }
  1092 
  1093 BranchObj* BranchObj::moveBranchTo (BranchObj* dst, int pos)
  1094 {
  1095 	// Find current parent and 
  1096 	// remove pointer to myself there
  1097 	if (!dst) return NULL;
  1098 	BranchObj *par=(BranchObj*)(parObj);
  1099 	if (par)
  1100 		par->removeBranchPtr (this);
  1101 	else
  1102 		return NULL;
  1103 
  1104 	// Create new pointer to myself at dst
  1105 	if (pos<0||dst->getDepth()==0)
  1106 	{	
  1107 		// links myself as last branch at dst
  1108 		dst->addBranchPtr (this);
  1109 		updateLink();
  1110 		return this;
  1111 	} else
  1112 	{
  1113 		// inserts me at pos in parent of dst
  1114 		if (par)
  1115 		{
  1116 			BranchObj *bo=dst->insertBranchPtr (this,pos);
  1117 			bo->setDefAttr(MovedBranch);
  1118 			updateLink();
  1119 			return bo;
  1120 
  1121 		} else
  1122 			return NULL;
  1123 	}	
  1124 }
  1125 
  1126 void BranchObj::alignRelativeTo (QPoint ref)
  1127 {
  1128 /* TODO testing
  1129 	if (!getHeading().isEmpty())
  1130 		cout << "BO::alignRelTo "<<getHeading()<<endl;
  1131 	else	
  1132 		cout << "BO::alignRelTo  ???"<<endl;
  1133 	cout << "  d="<<depth<<endl;
  1134 */	
  1135 	int th = bboxTotal.height();	
  1136 
  1137 	// If I am the mapcenter or a mainbranch, reposition heading
  1138 	if (depth<2)
  1139 	{
  1140 		move (absPos.x(),absPos.y());
  1141 		if (depth==1)
  1142 		{
  1143 			// Calc angle to mapCenter if I am a mainbranch
  1144 			// needed for reordering the mainbranches clockwise 
  1145 			// around mapcenter 
  1146 			angle=getAngle (QPoint ((int)(x() - parObj->getChildPos().x() ), 
  1147 									(int)(y() - parObj->getChildPos().y() ) ) );
  1148 		}	
  1149 	} 
  1150 	else
  1151     {
  1152 		// Align myself depending on orientation and parent, but
  1153 		// only if I am not the mainbranch or mapcenter itself
  1154 		switch (orientation) 
  1155 		{
  1156 			case OrientLeftOfCenter:
  1157 				move (ref.x()-bbox.width(), ref.y() + (th-bbox.height())/2 );
  1158 			break;
  1159 			case OrientRightOfCenter:	
  1160 				move (ref.x(), ref.y() + (th-bbox.height())/2 );
  1161 			break;
  1162 			default:
  1163 				cout <<"LMO::alignRelativeTo: oops, no orientation given...\n";
  1164 			break;
  1165 		}		
  1166     }		
  1167 
  1168 	FloatImageObj *fio;
  1169     for (fio=floatimage.first(); fio; fio=floatimage.next() )
  1170 		fio->reposition();
  1171 
  1172 	if (scrolled) return;
  1173 
  1174     // Set reference point for alignment of childs
  1175     QPoint ref2;
  1176     if (orientation==OrientLeftOfCenter)
  1177 		ref2.setX(childPos.x() - linkwidth);
  1178     else	
  1179 		ref2.setX(childPos.x() + linkwidth);
  1180 
  1181 	if (depth==1)
  1182 		ref2.setY(absPos.y()-(bboxTotal.height()-bbox.height())/2);
  1183 	else	
  1184 		ref2.setY(ref.y() );	
  1185 
  1186     // Align the childs depending on reference point 
  1187     BranchObj *b;
  1188     for (b=branch.first(); b; b=branch.next() )
  1189     {	
  1190 		b->alignRelativeTo (ref2);
  1191 		ref2.setY(ref2.y() + b->getBBoxSizeWithChilds().height() );
  1192     }
  1193 }
  1194 
  1195 
  1196 void BranchObj::reposition()
  1197 {	
  1198 /* TODO testing only
  1199 	if (!getHeading().isEmpty())
  1200 		cout << "BO::reposition  "<<getHeading()<<endl;
  1201 	else	
  1202 		cout << "BO::reposition  ???"<<endl;
  1203 */		
  1204 	if (depth==0)
  1205 	{
  1206 		// only calculate the sizes once. If the deepest LMO 
  1207 		// changes its height,
  1208 		// all upper LMOs have to change, too.
  1209 		calcBBoxSizeWithChilds();
  1210 	    alignRelativeTo ( QPoint (absPos.x(),
  1211 			absPos.y()-(bboxTotal.height()-bbox.height())/2) );
  1212 		branch.sort();	
  1213 	} else
  1214 	{
  1215 		// This is only important for moving branches:
  1216 		// For editing a branch it isn't called...
  1217 	    alignRelativeTo ( QPoint (absPos.x(),
  1218 							absPos.y()-(bboxTotal.height()-bbox.height())/2) );
  1219 	}
  1220 }
  1221 
  1222 
  1223 QRect BranchObj::getTotalBBox()
  1224 {
  1225 	QRect r=bbox;
  1226 
  1227 	if (scrolled) return r;
  1228 
  1229 	BranchObj* b;
  1230 	for (b=branch.first();b ;b=branch.next() )
  1231 		r=addBBox(b->getTotalBBox(),r);
  1232 
  1233 	FloatImageObj* fio;
  1234 	for (fio=floatimage.first();fio ;fio=floatimage.next() )
  1235 		r=addBBox(fio->getTotalBBox(),r);
  1236 		
  1237 	return r;
  1238 }
  1239 
  1240 QRect BranchObj::getBBoxSizeWithChilds()
  1241 {
  1242 	return bboxTotal;
  1243 }
  1244 
  1245 void BranchObj::calcBBoxSizeWithChilds()
  1246 {
  1247 	// This is called only from reposition and
  1248 	// and only for mapcenter. So it won't be
  1249 	// called more than once for a single user 
  1250 	// action
  1251 	
  1252 	// Calculate size of LMO including all childs (to align them later)
  1253 
  1254 	bboxTotal.setX(bbox.x() );
  1255 	bboxTotal.setY(bbox.y() );
  1256 
  1257 	// if branch is scrolled, ignore childs, but still consider floatimages
  1258 	if (scrolled)
  1259 	{
  1260 		bboxTotal.setWidth (bbox.width());
  1261 		bboxTotal.setHeight(bbox.height());
  1262 		return;
  1263 	}
  1264 	
  1265 	QRect r(0,0,0,0);
  1266 	QRect br;
  1267 	// Now calculate recursivly
  1268 	// sum of heights 
  1269 	// maximum of widths 
  1270 	// minimum of y
  1271 	BranchObj* b;
  1272 	for (b=branch.first();b ;b=branch.next() )
  1273 	{
  1274 		b->calcBBoxSizeWithChilds();
  1275 		br=b->getBBoxSizeWithChilds();
  1276 		r.setWidth( max (br.width(), r.width() ));
  1277 		r.setHeight(br.height() + r.height() );
  1278 		if (br.y()<bboxTotal.y()) bboxTotal.setY(br.y());
  1279 	}
  1280 	// Add myself and also
  1281 	// add width of link to sum if necessary
  1282 	if (branch.isEmpty())
  1283 		bboxTotal.setWidth (bbox.width() + r.width() );
  1284 	else	
  1285 		bboxTotal.setWidth (bbox.width() + r.width() + linkwidth);
  1286 	bboxTotal.setHeight(max (r.height(),  bbox.height() ) );
  1287 //	frame->setRect(QRect(bbox.x(),bbox.y(),bbox.width(),bbox.height() ) );
  1288 }
  1289 
  1290 void BranchObj::select()
  1291 {
  1292 	// set Text in Editor	
  1293 	textEditor->setText(note.getNote() );
  1294 	QString fnh=note.getFilenameHint();
  1295 	if (fnh!="")
  1296 		textEditor->setFilenameHint(note.getFilenameHint() );
  1297 	else	
  1298 		textEditor->setFilenameHint(getHeading() );
  1299 	textEditor->setFontHint (note.getFontHint() );
  1300 
  1301     LinkableMapObj::select();
  1302 	// Tell parent that I am selected now:
  1303 	BranchObj* po=(BranchObj*)(parObj);
  1304     if (po)	// TODO	    Try to get rid of this cast...
  1305         po->setLastSelectedBranch(this);
  1306 		
  1307 	// temporary unscroll, if we have scrolled parents somewhere
  1308 	if (parObj) ((BranchObj*)(parObj))->tmpUnscroll();
  1309 
  1310 	// Show URL and link in statusbar
  1311 	QString status;
  1312 	if (!url.isEmpty()) status+="URL: "+url+"  ";
  1313 	if (!vymLink.isEmpty()) status+="Link: "+vymLink;
  1314 	if (!status.isEmpty()) mainWindow->statusMessage (status);
  1315 
  1316 	// Update Toolbar
  1317 	standardFlags->updateToolbar();
  1318 
  1319 	// Update Browserbutton
  1320 	if (!url.isEmpty())
  1321 		actionEditOpenURL->setEnabled (true);
  1322 	else	
  1323 		actionEditOpenURL->setEnabled (false);
  1324 
  1325 	// Update actions in mapeditor
  1326 	mapEditor->updateActions();
  1327 }
  1328 
  1329 void BranchObj::unselect()
  1330 {
  1331 	LinkableMapObj::unselect();
  1332 	// Delete any messages like vymLink in StatusBar
  1333 	mainWindow->statusMessage ("");
  1334 
  1335 	// save note from editor and set flag
  1336 	// text is done by updateNoteFlag(), just save
  1337 	// filename here
  1338 	note.setFilenameHint (textEditor->getFilename());
  1339 
  1340 	// reset temporary unscroll, if we have scrolled parents somewhere
  1341 	if (parObj) ((BranchObj*)(parObj))->resetTmpUnscroll();
  1342 
  1343 	// Erase content of editor 
  1344 	textEditor->setInactive();
  1345 
  1346 	// unselect all buttons in toolbar
  1347 	standardFlagsDefault->updateToolbar();
  1348 }
  1349 
  1350 QString BranchObj::getSelectString()
  1351 {
  1352 	QString s;
  1353 	if (parObj)
  1354 	{
  1355 		if (depth==1)
  1356 			s= "bo:" + QString("%1").arg(getNum());
  1357 		else	
  1358 			s= ((BranchObj*)(parObj))->getSelectString() + ",bo:" + QString("%1").arg(getNum());
  1359 	} else
  1360 		s="mc:";
  1361 	return s;
  1362 }
  1363