4 * KTreeView implementation
6 * Copyright (C) 1997-1999 Johannes Sixt
8 * based on KTreeList, which is
9 * Copyright (C) 1996 Keith Brown and KtSoft
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details. You should have received a copy
20 * of the GNU General Public License along with this program; if not, write
21 * to the Free Software Foundation, Inc, 675 Mass Ave, Cambridge, MA 02139,
25 #include <ktreeview.h>
26 #include "ktreeview.moc"
27 #include <qapplication.h> /* used for QApplication::closingDown() */
28 #include <qkeycode.h> /* used for keyboard interface */
29 #include <qpainter.h> /* used to paint items */
30 #include <qptrstack.h>
34 * -------------------------------------------------------------------
38 * -------------------------------------------------------------------
42 KTreeViewItem::KTreeViewItem(const QString
& theText
) :
47 delayedExpanding(false),
57 // constructor that takes a pixmap
58 KTreeViewItem::KTreeViewItem(const QString
& theText
,
59 const QPixmap
& thePixmap
) :
64 delayedExpanding(false),
76 KTreeViewItem::~KTreeViewItem()
78 // remove the children
79 KTreeViewItem
* i
= child
;
87 // appends a direct child
88 void KTreeViewItem::appendChild(KTreeViewItem
* newChild
)
90 newChild
->parent
= this;
91 newChild
->setOwner(owner
);
96 KTreeViewItem
* lastChild
= getChild();
97 while (lastChild
->hasSibling()) {
98 lastChild
= lastChild
->getSibling();
100 lastChild
->sibling
= newChild
;
102 newChild
->sibling
= 0;
106 // returns the bounding rectangle of the item content (not including indent
107 // and branches) for hit testing
108 QRect
KTreeViewItem::boundingRect(int indent
) const
110 const QFontMetrics
& fm
= owner
->fontMetrics();
113 int rectW
= width(indent
, fm
) - rectX
;
114 int rectH
= height(fm
);
115 return QRect(rectX
, rectY
, rectW
, rectH
);
118 // returns the child item at the specified index
119 KTreeViewItem
* KTreeViewItem::childAt(int index
) const
123 KTreeViewItem
* item
= getChild();
124 while (index
> 0 && item
!= 0) {
125 item
= item
->getSibling();
131 // returns the number of children this item has
132 uint
KTreeViewItem::childCount() const
137 /* returns the index of the given child item in this item's branch */
138 int KTreeViewItem::childIndex(KTreeViewItem
* searched
) const
140 assert(searched
!= 0);
142 KTreeViewItem
* item
= getChild();
143 while (item
!= 0 && item
!= searched
) {
144 item
= item
->getSibling();
147 return item
== 0 ? -1 : index
;
150 // indicates whether mouse press is in expand button
151 inline bool KTreeViewItem::expandButtonClicked(const QPoint
& coord
) const
153 return expandButton
.contains(coord
);
156 // returns a pointer to first child item
157 KTreeViewItem
* KTreeViewItem::getChild() const
162 // returns the parent of this item
163 KTreeViewItem
* KTreeViewItem::getParent() const
168 // returns reference to the item pixmap
169 const QPixmap
& KTreeViewItem::getPixmap() const
174 // returns the sibling below this item
175 KTreeViewItem
* KTreeViewItem::getSibling() const
180 // returns a pointer to the item text
181 const QString
& KTreeViewItem::getText() const
186 // indicates whether this item has any children
187 bool KTreeViewItem::hasChild() const
192 // indicates whether this item has a parent
193 bool KTreeViewItem::hasParent() const
198 // indicates whether this item has a sibling below it
199 bool KTreeViewItem::hasSibling() const
204 int KTreeViewItem::height() const
207 return height(owner
->fontMetrics());
210 // returns the maximum height of text and pixmap including margins
211 int KTreeViewItem::height(const QFontMetrics
& fm
) const
213 int maxHeight
= pixmap
.height();
214 int textHeight
= fm
.height();
215 maxHeight
= textHeight
> maxHeight
? textHeight
: maxHeight
;
216 return maxHeight
+ 4;
219 // inserts child item at specified index in branch
220 void KTreeViewItem::insertChild(int index
, KTreeViewItem
* newChild
)
223 appendChild(newChild
);
226 newChild
->parent
= this;
227 newChild
->setOwner(owner
);
229 newChild
->sibling
= getChild();
233 KTreeViewItem
* prevItem
= getChild();
234 KTreeViewItem
* nextItem
= prevItem
->getSibling();
235 while (--index
> 0 && nextItem
) {
237 nextItem
= prevItem
->getSibling();
239 prevItem
->sibling
= newChild
;
240 newChild
->sibling
= nextItem
;
245 // indicates whether this item is displayed expanded
246 // NOTE: a TRUE response does not necessarily indicate the item
248 bool KTreeViewItem::isExpanded() const
253 // returns true if all ancestors are expanded
254 bool KTreeViewItem::isVisible() const
256 for (KTreeViewItem
* p
= getParent(); p
!= 0; p
= p
->getParent()) {
257 if (!p
->isExpanded())
263 bool KTreeViewItem::keyEvent(QKeyEvent
* /*ev*/)
265 return false; /* not handled */
268 bool KTreeViewItem::mouseEvent(QMouseEvent
* /*ev*/, const QPoint
& /*itemCoord*/)
270 return false; /* not handled */
273 // paint this item, including tree branches and expand button
274 void KTreeViewItem::paint(QPainter
* p
, int indent
, const QColorGroup
& cg
,
275 bool highlighted
) const
277 assert(getParent() != 0); /* can't paint root item */
282 int cellHeight
= height(p
->fontMetrics());
285 paintTree(p
, indent
, cellHeight
, cg
);
289 * If this item has at least one child and expand button drawing is
290 * enabled, set the rect for the expand button for later mouse press
291 * bounds checking, and draw the button.
293 if (doExpandButton
&& (child
|| delayedExpanding
)) {
294 paintExpandButton(p
, indent
, cellHeight
, cg
);
297 // now draw the item pixmap and text, if applicable
298 int pixmapX
= indent
;
299 int pixmapY
= (cellHeight
- pixmap
.height()) / 2;
300 p
->drawPixmap(pixmapX
, pixmapY
, pixmap
);
303 paintText(p
, indent
, cellHeight
, cg
, highlighted
);
308 void KTreeViewItem::paintExpandButton(QPainter
* p
, int indent
, int cellHeight
,
309 const QColorGroup
& cg
) const
311 int parentLeaderX
= indent
- (owner
->itemIndent
/ 2);
312 int cellCenterY
= cellHeight
/ 2;
314 QRect
paintRect(parentLeaderX
- 4, cellCenterY
- 4, 9, 9);
315 p
->setBrush(cg
.base());
316 p
->setPen(cg
.foreground());
317 p
->drawRect(paintRect
);
319 p
->drawLine(parentLeaderX
- 2, cellCenterY
,
320 parentLeaderX
+ 2, cellCenterY
);
322 p
->drawLine(parentLeaderX
- 2, cellCenterY
,
323 parentLeaderX
+ 2, cellCenterY
);
324 p
->drawLine(parentLeaderX
, cellCenterY
- 2,
325 parentLeaderX
, cellCenterY
+ 2);
327 p
->setBrush(NoBrush
);
330 * The area that the user can click to collapse and expand the tree is
331 * somewhat larger than the painted expand button.
333 expandButton
.setRect(indent
- owner
->itemIndent
, 0,
334 owner
->itemIndent
, cellHeight
);
337 // paint the highlight
338 void KTreeViewItem::paintHighlight(QPainter
* p
, int indent
, const QColorGroup
& colorGroup
,
342 fc
= colorGroup
.text();
343 QRect textRect
= textBoundingRect(indent
);
345 textRect
.coords(&l
, &t
, &r
, &b
);
347 outerRect
.setCoords(l
- 2, t
- 2, r
+ 2, b
+ 2);
349 p
->fillRect(textRect
, fc
); /* highlight background */
351 p
->drawRect(outerRect
);
353 p
->fillRect(outerRect
, fc
); /* highlight background */
357 // draw the text, highlighted if requested
358 void KTreeViewItem::paintText(QPainter
* p
, int indent
, int cellHeight
,
359 const QColorGroup
& cg
, bool highlighted
) const
361 int textX
= indent
+ pixmap
.width() + 3;
362 int textY
= (cellHeight
- p
->fontMetrics().height()) / 2 +
363 p
->fontMetrics().ascent();
366 paintHighlight(p
, indent
, cg
, owner
->hasFocus());
367 p
->setPen(cg
.base());
368 p
->setBackgroundColor(cg
.text());
371 p
->setPen(cg
.text());
372 p
->setBackgroundColor(cg
.base());
374 p
->drawText(textX
, textY
, text
);
377 // paint the tree structure
378 void KTreeViewItem::paintTree(QPainter
* p
, int indent
, int cellHeight
,
379 const QColorGroup
& cg
) const
381 int parentLeaderX
= indent
- (owner
->itemIndent
/ 2);
382 int cellCenterY
= cellHeight
/ 2;
383 int cellBottomY
= cellHeight
- 1;
384 int itemLeaderX
= indent
- 1;
386 p
->setPen(cg
.background());
389 * If this is not the first item in the tree draw the line up
390 * towards parent or sibling.
392 if (parent
->parent
!= 0 || parent
->getChild() != this)
393 p
->drawLine(parentLeaderX
, 0, parentLeaderX
, cellCenterY
);
395 // draw the line down towards sibling
397 p
->drawLine(parentLeaderX
, cellCenterY
, parentLeaderX
, cellBottomY
);
400 * If this item has children or siblings in the tree or is a child of
401 * an item other than the root item then draw the little line from the
402 * item out to the left.
404 if (sibling
|| (doExpandButton
&& (child
|| delayedExpanding
)) ||
405 parent
->parent
!= 0 ||
407 * The following handles the case of an item at the end of the
408 * topmost level which doesn't have children.
410 parent
->getChild() != this)
412 p
->drawLine(parentLeaderX
, cellCenterY
, itemLeaderX
, cellCenterY
);
416 * If there are siblings of ancestors below, draw our portion of the
417 * branches that extend through this cell.
419 KTreeViewItem
* prevRoot
= parent
;
420 while (prevRoot
->getParent() != 0) { /* while not root item */
421 assert(prevRoot
->owner
== owner
);
422 if (prevRoot
->hasSibling()) {
423 int sibLeaderX
= owner
->indentation(prevRoot
) - (owner
->itemIndent
/ 2);
424 p
->drawLine(sibLeaderX
, 0, sibLeaderX
, cellBottomY
);
426 prevRoot
= prevRoot
->getParent();
430 // removes the given (direct) child from the branch
431 bool KTreeViewItem::removeChild(KTreeViewItem
* theChild
)
433 // search item in list of children
434 KTreeViewItem
* prevItem
= 0;
435 KTreeViewItem
* toRemove
= getChild();
436 while (toRemove
&& toRemove
!= theChild
) {
438 toRemove
= toRemove
->getSibling();
444 child
= toRemove
->getSibling();
446 prevItem
->sibling
= toRemove
->getSibling();
449 toRemove
->setOwner(0);
451 assert((numChildren
== 0) == (child
== 0));
453 return toRemove
!= 0;
456 // sets the delayed-expanding flag
457 void KTreeViewItem::setDelayedExpanding(bool flag
)
459 delayedExpanding
= flag
;
462 // sets the draw expand button flag of this item
463 void KTreeViewItem::setDrawExpandButton(bool doit
)
465 doExpandButton
= doit
;
468 // sets the draw text flag of this item
469 void KTreeViewItem::setDrawText(bool doit
)
474 // sets the draw tree branch flag of this item
475 void KTreeViewItem::setDrawTree(bool doit
)
480 // sets the expanded flag of this item
481 void KTreeViewItem::setExpanded(bool is
)
486 // sets the owner of this item and its children siblings
487 void KTreeViewItem::setOwner(KTreeView
* newOwner
, bool includeSiblings
)
489 /* Note: set owner of children's siblings! */
492 getChild()->setOwner(newOwner
, true);
493 if (includeSiblings
&& getSibling())
494 getSibling()->setOwner(newOwner
, true);
497 // sets the item pixmap to the given pixmap
498 void KTreeViewItem::setPixmap(const QPixmap
& pm
)
503 // sets the item text to the given string
504 void KTreeViewItem::setText(const QString
& t
)
509 // counts the child items and stores the result in numChildren
510 void KTreeViewItem::synchNumChildren()
513 KTreeViewItem
* item
= getChild();
516 item
= item
->getSibling();
521 * returns the bounding rect of the item text in cell coordinates couldn't
522 * get QFontMetrics::boundingRect() to work right so I made my own
524 QRect
KTreeViewItem::textBoundingRect(int indent
) const
526 const QFontMetrics
& fm
= owner
->fontMetrics();
527 int cellHeight
= height(fm
);
528 int rectX
= indent
+ pixmap
.width() + 2;
529 int rectY
= (cellHeight
- fm
.height()) / 2;
530 int rectW
= fm
.width(text
) + 2;
531 int rectH
= fm
.height();
532 return QRect(rectX
, rectY
, rectW
, rectH
);
535 // returns the total width of text and pixmap, including margins, spacing
536 // and indent, or -1 if empty -- SHOULD NEVER BE -1!
537 int KTreeViewItem::width(int indent
) const
539 return width(indent
, owner
->fontMetrics());
542 // The width of an item is composed of the following:
543 // - indentation (indent with times level)
545 // - 2 pixels for highlight border
549 // - 2 pixels for highlight border
550 int KTreeViewItem::width(int indent
, const QFontMetrics
& fm
) const
552 return indent
+ pixmap
.width() + fm
.width(text
) + 6;
557 * -------------------------------------------------------------------
561 * -------------------------------------------------------------------
565 KTreeView::KTreeView(QWidget
*parent
,
568 TableView(parent
, name
, f
),
571 drawExpandButton(true),
577 moveCurrentToSibling(false),
580 rubberband_mode(false)
584 setBackgroundColor(colorGroup().base());
586 treeRoot
= new KTreeViewItem
;
587 treeRoot
->setExpanded(true);
588 treeRoot
->owner
= this;
590 visibleItems
= new KTreeViewItem
*[itemCapacity
];
591 // clear those pointers
592 for (int j
= itemCapacity
-1; j
>= 0; j
--) {
598 KTreeView::~KTreeView()
602 delete[] visibleItems
;
606 // appends a child to the item at the given index with the given text
608 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
611 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
612 appendChildItem(item
, index
);
615 // appends a child to the item at the end of the given path with
616 // the given text and pixmap
617 void KTreeView::appendChildItem(const char* theText
, const QPixmap
& thePixmap
,
618 const KPath
& thePath
)
620 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
621 appendChildItem(item
, thePath
);
624 // appends the given item to the children of the item at the given index
625 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, int index
)
627 /* find parent item and append new item to parent's sub tree */
628 KTreeViewItem
* parentItem
= itemAt(index
);
631 appendChildItem(parentItem
, newItem
);
634 // appends the given item to the children of the item at the end of the
636 void KTreeView::appendChildItem(KTreeViewItem
* newItem
, const KPath
& thePath
)
638 /* find parent item and append new item to parent's sub tree */
639 KTreeViewItem
* parentItem
= itemAt(thePath
);
642 appendChildItem(parentItem
, newItem
);
645 // translate mouse coord to cell coord
646 QPoint
KTreeView::cellCoords(int row
, const QPoint
& widgetCoord
)
648 int cellX
= 0, cellY
= 0;
650 rowYPos(row
, &cellY
);
651 return QPoint(widgetCoord
.x() - cellX
, widgetCoord
.y() - cellY
);
654 // find item at specified index and change pixmap and/or text
655 void KTreeView::changeItem(const char *newText
,
656 const QPixmap
*newPixmap
,
659 KTreeViewItem
*item
= itemAt(index
);
661 changeItem(item
, index
, newText
, newPixmap
);
664 // find item at end of specified path, and change pixmap and/or text
665 void KTreeView::changeItem(const char* newText
,
666 const QPixmap
* newPixmap
,
667 const KPath
& thePath
)
669 KTreeViewItem
* item
= itemAt(thePath
);
671 int index
= itemRow(item
);
672 changeItem(item
, index
, newText
, newPixmap
);
676 // clear all items from list and erase display
677 void KTreeView::clear()
681 /* somewhat of a hack for takeItem so it doesn't update the current item... */
684 bool autoU
= autoUpdate();
685 setAutoUpdate(FALSE
);
686 QStack
<KTreeViewItem
> stack
;
687 stack
.push(treeRoot
);
688 while(!stack
.isEmpty()) {
689 KTreeViewItem
*item
= stack
.pop();
690 if(item
->hasChild()) {
692 stack
.push(item
->getChild());
694 else if(item
->hasSibling()) {
696 stack
.push(item
->getSibling());
698 else if(item
->getParent() != 0) {
704 if(goingDown
|| QApplication::closingDown())
706 setAutoUpdate(autoU
);
707 if(autoU
&& isVisible())
711 // return a count of all the items in the tree, whether visible or not
712 uint
KTreeView::count()
715 forEveryItem(&KTreeView::countItem
, (void *)&total
);
719 // returns the index of the current (highlighted) item
720 int KTreeView::currentItem() const
725 // collapses the item at the specified row index.
726 void KTreeView::collapseItem(int index
, bool emitSignal
)
728 KTreeViewItem
* item
= itemAt(index
);
730 collapseSubTree(item
, emitSignal
);
733 // expands the item at the specified row indes.
734 void KTreeView::expandItem(int index
, bool emitSignal
)
736 KTreeViewItem
* item
= itemAt(index
);
738 expandSubTree(item
, emitSignal
);
741 // returns the depth the tree is automatically expanded to when
743 int KTreeView::expandLevel() const
748 // visits every item in the tree, visible or not and applies
749 // the user supplied function with the item and user data passed as parameters
750 // if user supplied function returns true, traversal ends and function returns
751 bool KTreeView::forEveryItem(KForEveryFunc func
, void* user
, KTreeViewItem
* item
)
756 assert(item
->owner
== this);
757 item
= item
->getChild();
760 // visit the siblings
761 if ((*func
)(item
, user
)) {
764 // visit the children (recursively)
765 if (item
->hasChild()) {
766 if (forEveryItem(func
, user
, item
))
769 item
= item
->getSibling();
774 // visits every visible item in the tree in order and applies the
775 // user supplied function with the item and user data passed as parameters
776 // if user supplied function returns TRUE, traversal ends and function
778 bool KTreeView::forEveryVisibleItem(KForEveryFunc func
, void *user
,
784 // children are invisible (hence, nothing to do)
785 // if item is invisible or collapsed
786 if (!item
->isVisible() || !item
->isExpanded()) {
790 assert(item
->owner
== this);
791 item
= item
->getChild();
794 // visit the siblings
795 if ((*func
)(item
, user
)) {
798 // visit the children (recursively)
799 if (item
->hasChild() && item
->isExpanded()) {
800 if (forEveryVisibleItem(func
, user
, item
))
803 item
= item
->getSibling();
808 // returns a pointer to the KTreeViewItem at the current index
809 // or 0 if no current item
810 KTreeViewItem
*KTreeView::getCurrentItem()
812 if(current
== -1) return 0;
813 return itemAt(current
);
816 // returns the current indent spacing
817 int KTreeView::indentSpacing()
822 // inserts a new item with the specified text and pixmap before
823 // or after the item at the given index, depending on the value
825 // if index is negative, appends item to tree at root level
826 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
827 int row
, bool prefix
)
829 KTreeViewItem
* refItem
= itemAt(row
);
831 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
833 bool success
= insertItem(refItem
, item
, prefix
);
839 // inserts a new item with the specified text and pixmap before
840 // or after the item at the end of the given path, depending on the value
842 bool KTreeView::insertItem(const char* theText
, const QPixmap
& thePixmap
,
843 const KPath
& path
, bool prefix
)
845 KTreeViewItem
* refItem
= itemAt(path
);
847 KTreeViewItem
* item
= new KTreeViewItem(theText
, thePixmap
);
849 bool success
= insertItem(refItem
, item
, prefix
);
855 // inserts the given item or derived object into the tree before
856 // or after the item at the given index, depending on the value
858 // if index is negative, appends item to tree at root level
859 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
860 int index
, bool prefix
)
862 // find the item currently at the index, if there is one
863 KTreeViewItem
* refItem
= itemAt(index
);
865 // insert new item at the appropriate place
866 return insertItem(refItem
, newItem
, prefix
);
869 // inserts the given item or derived object into the tree before
870 // or after the item at the end of the given path, depending on the value
872 bool KTreeView::insertItem(KTreeViewItem
* newItem
,
873 const KPath
& thePath
, bool prefix
)
875 // find the item currently at the end of the path, if there is one
876 KTreeViewItem
* refItem
= itemAt(thePath
);
878 // insert new item at appropriate place
879 return insertItem(refItem
, newItem
, prefix
);
883 * returns pointer to KTreeViewItem at the specifed row or 0 if row is out
886 KTreeViewItem
* KTreeView::itemAt(int row
) const
888 if (row
< 0 || row
>= numRows()) {
892 // lookup the item in the list of visible items
893 assert(row
< itemCapacity
);
894 KTreeViewItem
* i
= visibleItems
[row
];
900 // returns pointer to KTreeViewItem at the end of the
901 // path or 0 if not found
902 KTreeViewItem
* KTreeView::itemAt(const KPath
& path
)
907 // need a copy of the path because recursiveFind will destroy it
908 KPath pathCopy
= path
;
910 return recursiveFind(pathCopy
);
913 // computes the path of the item at the specified index
914 // if index is invalid, nothing is done.
915 void KTreeView::itemPath(int row
, KPath
& path
)
917 KTreeViewItem
* item
= itemAt(row
);
919 itemPath(item
, path
);
923 // returns the row in the visible tree of the given item or
925 int KTreeView::itemRow(KTreeViewItem
* item
)
927 if (item
->owner
== this) {
928 // search in list of visible items
929 for (int i
= numRows()-1; i
>= 0; i
--) {
930 if (visibleItems
[i
] == item
) {
940 * move the subtree at the specified index up one branch level (make root
941 * item a sibling of its current parent)
943 void KTreeView::join(int index
)
945 KTreeViewItem
*item
= itemAt(index
);
951 * move the subtree at the specified index up one branch level (make root
952 * item a sibling of it's current parent)
954 void KTreeView::join(const KPath
& path
)
956 KTreeViewItem
*item
= itemAt(path
);
961 /* move item at specified index one slot down in its parent's sub tree */
962 void KTreeView::lowerItem(int index
)
964 KTreeViewItem
*item
= itemAt(index
);
969 /* move item at specified path one slot down in its parent's sub tree */
970 void KTreeView::lowerItem(const KPath
& path
)
972 KTreeViewItem
* item
= itemAt(path
);
977 /* move item at specified index one slot up in its parent's sub tree */
978 void KTreeView::raiseItem(int index
)
980 KTreeViewItem
* item
= itemAt(index
);
985 /* move item at specified path one slot up in its parent's sub tree */
986 void KTreeView::raiseItem(const KPath
& path
)
988 KTreeViewItem
* item
= itemAt(path
);
993 // remove the item at the specified index and delete it
994 void KTreeView::removeItem(int index
)
996 KTreeViewItem
*item
= itemAt(index
);
1003 // remove the item at the end of the specified path and delete it
1004 void KTreeView::removeItem(const KPath
& thePath
)
1006 KTreeViewItem
* item
= itemAt(thePath
);
1013 void KTreeView::scrollVisible(KTreeViewItem
* item
, bool children
)
1017 int row
= itemRow(item
);
1019 return; /* do nothing if invisible */
1021 if (children
&& item
->isExpanded()) {
1022 // we are concerned about children
1023 if (!rowIsVisible(row
)) {
1024 // just move to the top
1027 // this is the complicated part
1028 // count the visible children (including grandchildren)
1030 forEveryVisibleItem(countItem
, &numVisible
, item
);
1031 // if the last child is visible, do nothing
1032 if (rowIsVisible(row
+ numVisible
))
1035 * Basically, item will become the top cell; but if there are
1036 * more visible rows in the widget than we have children, then
1037 * we don't move that far.
1039 int remain
= lastRowVisible()-topCell()-numVisible
;
1043 setTopCell(QMAX(0,row
-remain
));
1047 // we are not concerned about children
1048 if (rowIsVisible(row
))
1050 // just move the item to the top
1055 // sets the current item and hightlights it, emitting signals
1056 void KTreeView::setCurrentItem(int row
)
1060 int numVisible
= numRows();
1061 if (row
> numVisible
)
1063 int oldCurrent
= current
;
1065 if (oldCurrent
< numVisible
)
1066 updateCell(oldCurrent
, 0);
1068 updateCell(current
, 0, false);
1069 emit
highlighted(current
);
1073 // enables/disables drawing of expand button
1074 void KTreeView::setExpandButtonDrawing(bool enable
)
1076 if (drawExpandButton
== enable
)
1078 drawExpandButton
= enable
;
1080 // the user parameter is cast to a bool in setItemExpandButtonDrawing
1081 forEveryItem(&KTreeView::setItemExpandButtonDrawing
, enable
? &enable
: 0);
1083 if (autoUpdate() && isVisible())
1087 // sets depth to which subtrees are automatically expanded, and
1088 // redraws tree if auto update enabled
1089 void KTreeView::setExpandLevel(int level
)
1091 if (expansion
== level
)
1094 KTreeViewItem
* item
= getCurrentItem();
1095 forEveryItem(&KTreeView::setItemExpandLevel
, 0);
1097 if (item
->getParent()->isExpanded())
1099 item
= item
->getParent();
1102 setCurrentItem(itemRow(item
));
1103 if (autoUpdate() && isVisible())
1107 // sets the indent margin for all branches and repaints if auto update enabled
1108 void KTreeView::setIndentSpacing(int spacing
)
1110 if (itemIndent
== spacing
)
1112 itemIndent
= spacing
;
1114 if (autoUpdate() && isVisible())
1118 void KTreeView::setMoveCurrentToSibling(bool m
)
1120 moveCurrentToSibling
= m
;
1123 // enables/disables display of item text (keys)
1124 void KTreeView::setShowItemText(bool enable
)
1126 if (showText
== enable
)
1130 // the user parameter is cast to a bool in setItemShowText
1131 forEveryItem(&KTreeView::setItemShowText
, enable
? &enable
: 0);
1133 if (autoUpdate() && isVisible())
1137 // enables/disables tree branch drawing
1138 void KTreeView::setTreeDrawing(bool enable
)
1140 if (drawTree
== enable
)
1144 // the user parameter is cast to a bool in setItemTreeDrawing
1145 forEveryItem(&KTreeView::setItemTreeDrawing
, enable
? &enable
: 0);
1147 if (autoUpdate() && isVisible())
1151 // indicates whether item text keys are displayed
1152 bool KTreeView::showItemText() const
1157 // indents the item at the given index, splitting the tree into
1159 void KTreeView::split(int index
)
1161 KTreeViewItem
*item
= itemAt(index
);
1166 // indents the item at the given path, splitting the tree into
1168 void KTreeView::split(const KPath
& path
)
1170 KTreeViewItem
* item
= itemAt(path
);
1175 // removes item at specified index from tree but does not delete it
1176 // returns pointer to the item or 0 if not succesful
1177 KTreeViewItem
*KTreeView::takeItem(int index
)
1179 KTreeViewItem
*item
= itemAt(index
);
1185 // removes item at specified path from tree but does not delete it
1186 // returns pointer to the item or 0 if not successful
1187 KTreeViewItem
* KTreeView::takeItem(const KPath
& path
)
1189 KTreeViewItem
* item
= itemAt(path
);
1195 // indicates whether tree branches are drawn
1196 bool KTreeView::treeDrawing() const
1202 // appends a child to the specified parent item (note: a child, not a sibling, is added!)
1203 void KTreeView::appendChildItem(KTreeViewItem
* theParent
,
1204 KTreeViewItem
* newItem
)
1206 theParent
->appendChild(newItem
);
1209 newItem
->setDrawExpandButton(drawExpandButton
);
1210 newItem
->setDrawTree(drawTree
);
1211 newItem
->setDrawText(showText
);
1212 if (level(newItem
) < expansion
) {
1213 newItem
->setExpanded(true);
1216 // fix up branch levels of any children that the new item may already have
1217 if(newItem
->hasChild()) {
1218 fixChildren(newItem
);
1221 // if necessary, adjust cell width, number of rows and repaint
1222 if (newItem
->isVisible() || theParent
->childCount() == 1) {
1223 bool autoU
= autoUpdate();
1224 setAutoUpdate(false);
1225 updateVisibleItems();
1226 setAutoUpdate(autoU
);
1227 if (autoU
&& isVisible())
1232 // returns the height of the cell(row) at the specified row (index)
1233 int KTreeView::cellHeight(int row
) const
1235 return itemAt(row
)->height(fontMetrics());
1238 // returns the width of the cells. Note: this is mostly for derived classes
1239 // which have more than 1 column
1240 int KTreeView::cellWidth(int /*col*/) const
1242 return maxItemWidth
;
1245 // changes the given item with the new text and/or pixmap
1246 void KTreeView::changeItem(KTreeViewItem
* toChange
, int itemRow
,
1247 const char* newText
, const QPixmap
* newPixmap
)
1249 int indent
= indentation(toChange
);
1250 int oldWidth
= toChange
->width(indent
);
1252 toChange
->setText(newText
);
1254 toChange
->setPixmap(*newPixmap
);
1255 if(oldWidth
!= toChange
->width(indent
))
1259 if(autoUpdate() && rowIsVisible(itemRow
))
1260 updateCell(itemRow
, 0);
1263 // collapses the subtree at the specified item
1264 void KTreeView::collapseSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1266 assert(subRoot
->owner
== this);
1267 if (!subRoot
->isExpanded())
1270 // must move the current item if it is visible
1271 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1273 subRoot
->setExpanded(false);
1274 if (subRoot
->isVisible()) {
1275 bool autoU
= autoUpdate();
1276 setAutoUpdate(false);
1277 updateVisibleItems();
1278 // re-seat current item
1280 setCurrentItem(itemRow(cur
));
1283 emit
collapsed(itemRow(subRoot
));
1285 setAutoUpdate(autoU
);
1286 if (autoU
&& isVisible())
1291 // used by count() with forEach() function to count total number
1292 // of items in the tree
1293 bool KTreeView::countItem(KTreeViewItem
*, void* total
)
1295 int* t
= static_cast<int*>(total
);
1300 // expands the subtree at the given item
1301 void KTreeView::expandSubTree(KTreeViewItem
* subRoot
, bool emitSignal
)
1303 assert(subRoot
->owner
== this);
1304 if (subRoot
->isExpanded())
1307 // must move the current item if it is visible
1308 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1312 if (subRoot
->delayedExpanding
) {
1313 emit
expanding(subRoot
, allow
);
1318 subRoot
->setExpanded(true);
1320 if (subRoot
->isVisible()) {
1321 bool autoU
= autoUpdate();
1322 setAutoUpdate(false);
1323 updateVisibleItems();
1324 // re-seat current item
1326 setCurrentItem(itemRow(cur
));
1329 emit
expanded(itemRow(subRoot
));
1331 setAutoUpdate(autoU
);
1332 if (autoU
&& isVisible())
1337 // fix up branch levels out of whack from split/join operations on the tree
1338 void KTreeView::fixChildren(KTreeViewItem
*parentItem
)
1340 KTreeViewItem
* childItem
= 0;
1341 KTreeViewItem
* siblingItem
= 0;
1342 // int childBranch = parentItem->getBranch() + 1;
1343 if(parentItem
->hasChild()) {
1344 childItem
= parentItem
->getChild();
1345 // childItem->setBranch(childBranch);
1346 childItem
->owner
= parentItem
->owner
;
1347 fixChildren(childItem
);
1349 while(childItem
&& childItem
->hasSibling()) {
1350 siblingItem
= childItem
->getSibling();
1351 // siblingItem->setBranch(childBranch);
1352 siblingItem
->owner
= parentItem
->owner
;
1353 fixChildren(siblingItem
);
1354 childItem
= siblingItem
;
1359 * Handle QFocusEvent processing by setting current item to top row if
1360 * there is no current item, and updates cell to add or delete the focus
1361 * rectangle on the highlight bar. The base class is not called because it
1362 * does a repaint() which causes flicker.
1364 void KTreeView::focusInEvent(QFocusEvent
*)
1366 if (current
< 0 && numRows() > 0)
1367 setCurrentItem(topCell());
1368 updateCell(current
, 0);
1371 void KTreeView::focusOutEvent(QFocusEvent
*)
1373 updateCell(current
, 0);
1376 // called by updateCellWidth() for each item in the visible list
1377 bool KTreeView::getMaxItemWidth(KTreeViewItem
* item
, void* user
)
1379 assert(item
->owner
!= 0);
1380 int indent
= item
->owner
->indentation(item
);
1381 int* maxW
= static_cast<int*>(user
);
1382 int w
= item
->width(indent
);
1388 int KTreeView::indentation(KTreeViewItem
* item
) const
1390 return level(item
) * itemIndent
+ itemIndent
+ 3;
1393 // inserts the new item before or after the reference item, depending
1394 // on the value of prefix
1395 bool KTreeView::insertItem(KTreeViewItem
* referenceItem
,
1396 KTreeViewItem
* newItem
,
1399 assert(newItem
!= 0);
1400 assert(referenceItem
== 0 || referenceItem
->owner
== this);
1402 /* set the new item's state */
1403 newItem
->setDrawExpandButton(drawExpandButton
);
1404 newItem
->setDrawTree(drawTree
);
1405 newItem
->setDrawText(showText
);
1406 KTreeViewItem
* parentItem
;
1407 if (referenceItem
) {
1408 parentItem
= referenceItem
->getParent();
1409 int insertIndex
= parentItem
->childIndex(referenceItem
);
1412 parentItem
->insertChild(insertIndex
, newItem
);
1415 // no reference item, append at end of visible tree
1417 parentItem
= treeRoot
;
1418 parentItem
->appendChild(newItem
);
1421 // set item expansion
1422 if (level(newItem
) < expansion
)
1423 newItem
->setExpanded(true);
1425 // fix up branch levels of any children
1426 if (newItem
->hasChild())
1427 fixChildren(newItem
);
1429 // if repaint necessary, do it if visible and auto update
1431 if (newItem
->isVisible() || parentItem
->childCount() == 1) {
1432 bool autoU
= autoUpdate();
1433 setAutoUpdate(FALSE
);
1434 updateVisibleItems();
1435 setAutoUpdate(autoU
);
1436 if (autoU
&& isVisible())
1443 * returns pointer to item's path
1445 void KTreeView::itemPath(KTreeViewItem
* item
, KPath
& path
) const
1448 assert(item
->owner
== this);
1449 if (item
!= treeRoot
) {
1450 itemPath(item
->getParent(), path
);
1451 path
.push(item
->getText());
1456 * joins the item's branch into the tree, making the item a sibling of its
1459 void KTreeView::join(KTreeViewItem
*item
)
1461 KTreeViewItem
*itemParent
= item
->getParent();
1462 if(itemParent
->hasParent()) {
1463 bool autoU
= autoUpdate();
1464 setAutoUpdate(FALSE
);
1466 insertItem(itemParent
, item
, FALSE
);
1467 setAutoUpdate(autoU
);
1468 if(autoU
&& isVisible())
1473 // handles keyboard interface
1474 void KTreeView::keyPressEvent(QKeyEvent
* e
)
1477 return; /* nothing to do */
1479 /* if there's no current item, make the top item current */
1480 if (currentItem() < 0)
1481 setCurrentItem(topCell());
1482 assert(currentItem() >= 0); /* we need a current item */
1483 assert(itemAt(currentItem()) != 0); /* we really need a current item */
1485 // give currentItem a chance to handle the event
1486 if (itemAt(currentItem())->keyEvent(e
))
1487 return; /* handled */
1489 int pageSize
, delta
;
1490 KTreeViewItem
* item
;
1495 // make previous item current, scroll up if necessary
1496 if (currentItem() > 0) {
1497 setCurrentItem(currentItem() - 1);
1498 scrollVisible(itemAt(currentItem()), false);
1502 // make next item current, scroll down if necessary
1503 if (currentItem() < numRows() - 1) {
1504 setCurrentItem(currentItem() + 1);
1505 if (currentItem() > lastRowVisible()) {
1506 // scrollVisible is not feasible here because
1507 // it scrolls the item to the top
1508 setTopCell(topCell() + currentItem() - lastRowVisible());
1509 } else if (currentItem() < topCell()) {
1510 setTopCell(currentItem());
1515 // move highlight one page down and scroll down
1516 delta
= currentItem() - topCell();
1517 pageSize
= lastRowVisible() - topCell();
1518 setTopCell(QMIN(topCell() + pageSize
, numRows() - 1));
1519 setCurrentItem(QMIN(topCell() + delta
, numRows() - 1));
1522 // move highlight one page up and scroll up
1523 delta
= currentItem() - topCell();
1524 pageSize
= lastRowVisible() - topCell();
1525 setTopCell(QMAX(topCell() - pageSize
, 0));
1526 setCurrentItem(QMAX(topCell() + delta
, 0));
1530 // if current item has subtree and is collapsed, expand it
1531 item
= itemAt(currentItem());
1532 if (item
->isExpanded() && item
->hasChild() && key
== Key_Right
) {
1533 // going right on an expanded item is like going down
1537 expandSubTree(item
, true);
1538 scrollVisible(item
, true);
1543 // if current item has subtree and is expanded, collapse it
1544 item
= itemAt(currentItem());
1545 if ((!item
->isExpanded() || !item
->hasChild()) && key
== Key_Left
) {
1546 // going left on a collapsed item goes to its parent
1547 item
= item
->getParent();
1548 if (item
== treeRoot
)
1549 break; /* we're already at the top */
1550 assert(item
->isVisible());
1551 setCurrentItem(itemRow(item
));
1553 collapseSubTree(item
, true);
1555 scrollVisible(item
, false);
1559 // select the current item
1560 if (currentItem() >= 0)
1561 emit
selected(currentItem());
1568 // handles keyboard interface
1569 void KTreeView::keyReleaseEvent(QKeyEvent
* e
)
1571 if (currentItem() >= 0 && itemAt(currentItem()) != 0)
1572 itemAt(currentItem())->keyEvent(e
);
1575 int KTreeView::level(KTreeViewItem
* item
) const
1578 assert(item
->owner
== this);
1579 assert(item
!= treeRoot
);
1581 item
= item
->parent
->parent
; /* since item != treeRoot, there is a parent */
1583 item
= item
->parent
;
1589 /* move specified item down one slot in parent's subtree */
1590 void KTreeView::lowerItem(KTreeViewItem
*item
)
1592 KTreeViewItem
*itemParent
= item
->getParent();
1593 uint itemChildIndex
= itemParent
->childIndex(item
);
1594 if(itemChildIndex
< itemParent
->childCount() - 1) {
1595 bool autoU
= autoUpdate();
1596 setAutoUpdate(FALSE
);
1598 insertItem(itemParent
->childAt(itemChildIndex
), item
, FALSE
);
1599 setAutoUpdate(autoU
);
1600 if(autoU
&& isVisible())
1605 // handle mouse double click events by selecting the clicked item
1606 // and emitting the signal
1607 void KTreeView::mouseDoubleClickEvent(QMouseEvent
* e
)
1609 // find out which row has been clicked
1610 int itemClicked
= findRow(e
->y());
1612 if (itemClicked
< 0)
1613 return; /* invalid row, do nothing */
1615 KTreeViewItem
* item
= itemAt(itemClicked
);
1619 // translate mouse coord to cell coord
1620 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1623 if (item
->mouseEvent(e
, cellCoord
))
1627 int indent
= indentation(item
);
1628 if (item
->boundingRect(indent
).contains(cellCoord
))
1629 emit
selected(itemClicked
);
1632 // handle mouse movement events
1633 void KTreeView::mouseMoveEvent(QMouseEvent
* e
)
1635 // in rubberband_mode we actually scroll the window now
1636 if (rubberband_mode
) {
1637 move_rubberband(e
->pos());
1639 // else forward to current item
1640 int current
= currentItem();
1641 if (current
>= 0 && itemAt(current
))
1642 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1647 // handle single mouse presses
1648 void KTreeView::mousePressEvent(QMouseEvent
* e
)
1650 /* first: cancel rubberbanding if it's on */
1651 if (rubberband_mode
)
1653 // another button was pressed while rubberbanding, stop the move.
1654 // RB: if we allow other buttons while rubberbanding the tree can expand
1655 // while rubberbanding - we then need to recalculate and resize the
1656 // rubberband rect and show the new size
1661 // find out which row has been clicked
1662 int itemClicked
= findRow(e
->y());
1664 // nothing to do if not on valid row
1665 if (itemClicked
< 0)
1667 KTreeViewItem
* item
= itemAt(itemClicked
);
1671 // translate mouse coord to cell coord
1672 QPoint cellCoord
= cellCoords(itemClicked
, e
->pos());
1674 // give the item a crack
1675 if (item
->mouseEvent(e
, cellCoord
))
1676 return; /* event eaten by item */
1678 // check for rubberbanding
1679 if (e
->button() == MidButton
)
1681 // RB: the MMB is hardcoded to the "rubberband" scroll mode
1682 if (!rubberband_mode
) {
1683 start_rubberband(e
->pos());
1688 if (e
->button() == RightButton
) {
1689 emit
rightPressed(itemClicked
, e
->pos());
1691 /* hit test expand button (doesn't set currentItem) */
1692 else if (item
->expandButtonClicked(cellCoord
)) {
1693 if (item
->isExpanded()) {
1694 collapseSubTree(item
, true);
1696 expandSubTree(item
, true);
1697 scrollVisible(item
, true); /* make children visible */
1701 else if (item
->boundingRect(indentation(item
)).contains(cellCoord
)) {
1702 setCurrentItem(itemClicked
);
1706 // handle mouse release events
1707 void KTreeView::mouseReleaseEvent(QMouseEvent
*e
)
1709 /* if it's the MMB end rubberbanding */
1710 if (rubberband_mode
) {
1711 if (e
->button() == MidButton
)
1715 // forward to current item
1716 int current
= currentItem();
1717 if (current
>= 0 && itemAt(current
))
1718 itemAt(current
)->mouseEvent(e
, cellCoords(current
, e
->pos()));
1721 // rubberband move: draw the rubberband
1722 void KTreeView::draw_rubberband()
1725 * RB: I'm using a white pen because of the XorROP mode. I would prefer
1726 * to draw the rectangle in red but I don't now how to get a pen which
1727 * draws red in XorROP mode (this depends on the background). In fact
1728 * the color should be configurable.
1731 if (!rubberband_mode
) return;
1732 QPainter
paint(this);
1733 paint
.setPen(white
);
1734 paint
.setRasterOp(XorROP
);
1735 paint
.drawRect(xOffset()*viewWidth()/totalWidth(),
1736 yOffset()*viewHeight()/totalHeight(),
1737 rubber_width
+1, rubber_height
+1);
1741 // rubberband move: start move
1742 void KTreeView::start_rubberband(const QPoint
& where
)
1744 if (rubberband_mode
) { // Oops!
1747 /* RB: Don't now, if this check is necessary */
1748 if (!viewWidth() || !viewHeight()) return;
1749 if (!totalWidth() || !totalHeight()) return;
1751 // calculate the size of the rubberband rectangle
1752 rubber_width
= viewWidth()*viewWidth()/totalWidth();
1753 if (rubber_width
> viewWidth()) rubber_width
= viewWidth();
1754 rubber_height
= viewHeight()*viewHeight()/totalHeight();
1755 if (rubber_height
> viewHeight()) rubber_height
= viewHeight();
1757 // remember the cursor position and the actual offset
1758 rubber_startMouse
= where
;
1759 rubber_startX
= xOffset();
1760 rubber_startY
= yOffset();
1761 rubberband_mode
=TRUE
;
1765 // rubberband move: end move
1766 void KTreeView::end_rubberband()
1768 if (!rubberband_mode
) return;
1770 rubberband_mode
= FALSE
;
1773 // rubberband move: hanlde mouse moves
1774 void KTreeView::move_rubberband(const QPoint
& where
)
1776 if (!rubberband_mode
) return;
1778 // look how much the mouse moved and calc the new scroll position
1779 QPoint delta
= where
- rubber_startMouse
;
1780 int nx
= rubber_startX
+ delta
.x() * totalWidth() / viewWidth();
1781 int ny
= rubber_startY
+ delta
.y() * totalHeight() / viewHeight();
1783 // check the new position (and make it valid)
1785 else if (nx
> maxXOffset()) nx
= maxXOffset();
1787 else if (ny
> maxYOffset()) ny
= maxYOffset();
1789 // redraw the rubberband at the new position
1796 // paints the cell at the specified row and col
1797 // col is ignored for now since there is only one
1798 void KTreeView::paintCell(QPainter
* p
, int row
, int)
1800 KTreeViewItem
* item
= itemAt(row
);
1804 QColorGroup cg
= colorGroup();
1805 int indent
= indentation(item
);
1806 item
->paint(p
, indent
, cg
,
1807 current
== row
); /* highlighted */
1811 /* This is needed to make the kcontrol's color setup working (Marcin Dalecki) */
1812 void KTreeView::paletteChange(const QPalette
&)
1814 setBackgroundColor(colorGroup().base());
1819 /* raise the specified item up one slot in parent's subtree */
1820 void KTreeView::raiseItem(KTreeViewItem
*item
)
1822 KTreeViewItem
*itemParent
= item
->getParent();
1823 int itemChildIndex
= itemParent
->childIndex(item
);
1824 if(itemChildIndex
> 0) {
1825 bool autoU
= autoUpdate();
1826 setAutoUpdate(FALSE
);
1828 insertItem(itemParent
->childAt(--itemChildIndex
), item
, TRUE
);
1829 setAutoUpdate(autoU
);
1830 if(autoU
&& isVisible())
1835 // find the item at the path
1836 KTreeViewItem
* KTreeView::recursiveFind(KPath
& path
)
1842 QString searchString
= path
.pop();
1844 // find the parent item
1845 KTreeViewItem
* parent
= recursiveFind(path
);
1850 * Iterate through the parent's children searching for searchString.
1852 KTreeViewItem
* sibling
= parent
->getChild();
1853 while (sibling
!= 0) {
1854 if (searchString
== sibling
->getText()) {
1855 break; /* found it! */
1857 sibling
= sibling
->getSibling();
1862 void KTreeView::setItemExpanded(KTreeViewItem
* item
)
1864 if (level(item
) < expansion
) {
1865 expandSubTree(item
, true);
1867 collapseSubTree(item
, true);
1871 // called by setExpandLevel for each item in tree
1872 bool KTreeView::setItemExpandLevel(KTreeViewItem
* item
, void*)
1874 assert(item
->owner
!= 0);
1875 item
->owner
->setItemExpanded(item
);
1879 // called by setExpandButtonDrawing for every item in tree
1880 // the parameter drawButton is used as (and implicitly cast to) a bool
1881 bool KTreeView::setItemExpandButtonDrawing(KTreeViewItem
* item
,
1884 item
->setDrawExpandButton(drawButton
);
1888 // called by setShowItemText for every item in tree
1889 // the parameter newDrawText is used as (and implicitly cast to) a bool
1890 bool KTreeView::setItemShowText(KTreeViewItem
* item
,
1893 item
->setDrawText(newDrawText
);
1897 // called by setTreeDrawing for every item in tree
1898 // the parameter drawTree is used as (and implicitly cast to) a bool
1899 bool KTreeView::setItemTreeDrawing(KTreeViewItem
* item
, void* drawTree
)
1901 item
->setDrawTree(drawTree
);
1905 // makes the item a child of the item above it, splitting
1906 // the tree into a new branch
1907 void KTreeView::split(KTreeViewItem
*item
)
1909 KTreeViewItem
*itemParent
= item
->getParent();
1910 int itemChildIndex
= itemParent
->childIndex(item
);
1911 if(itemChildIndex
== 0)
1913 bool autoU
= autoUpdate();
1914 setAutoUpdate(FALSE
);
1916 appendChildItem(itemParent
->childAt(--itemChildIndex
), item
);
1917 setAutoUpdate(autoU
);
1918 if(autoU
&& isVisible())
1922 // removes the item from the tree without deleting it
1923 void KTreeView::takeItem(KTreeViewItem
* item
)
1925 assert(item
->owner
== this);
1927 // TODO: go over this function again
1929 bool wasVisible
= item
->isVisible();
1931 * If we have a current item, make sure that it is not in the subtree
1932 * that we are about to remove. If the current item is in the part
1933 * below the taken-out subtree, we must move it up a number of rows if
1934 * the taken-out subtree is at least partially visible.
1936 KTreeViewItem
* cur
= current
>= 0 ? itemAt(current
) : 0;
1937 KTreeViewItem
* oldCurrent
= cur
;
1938 if (wasVisible
&& cur
!= 0) {
1939 KTreeViewItem
* c
= cur
;
1940 while (c
!= 0 && c
!= item
) {
1944 // move current item to parent
1945 cur
= item
->getParent();
1946 if (cur
== treeRoot
) {
1948 // move it to next or previous sibling
1949 if (moveCurrentToSibling
) {
1950 if (item
->getSibling() != 0) {
1951 cur
= item
->getSibling();
1952 } else if (treeRoot
->getChild() != item
) {
1953 cur
= treeRoot
->getChild();
1954 while (cur
!= 0 && cur
->getSibling() != item
)
1955 cur
= cur
->getSibling();
1961 KTreeViewItem
* parentItem
= item
->getParent();
1962 parentItem
->removeChild(item
);
1964 if (wasVisible
|| parentItem
->childCount() == 0) {
1965 bool autoU
= autoUpdate();
1966 setAutoUpdate(FALSE
);
1967 updateVisibleItems();
1968 setAutoUpdate(autoU
);
1969 if (autoU
&& isVisible())
1973 // re-seat the current item
1974 // row changes if cur is below the taken item
1975 current
= cur
!= 0 ? itemRow(cur
) : -1;
1976 // signal must be emitted only if item really changed
1977 if (cur
!= oldCurrent
) {
1978 updateCell(current
, 0, false);
1979 emit
highlighted(current
);
1983 // visits each item, calculates the maximum width
1984 // and updates TableView
1985 void KTreeView::updateCellWidth()
1987 // make cells at least 1 pixel wide to avoid singularities (division by zero)
1989 forEveryVisibleItem(&KTreeView::getMaxItemWidth
, &maxW
);
1990 maxItemWidth
= maxW
;
1994 int xoff
= xOffset();
1995 int yoff
= yOffset();
1996 if (xoff
> maxXOffset()) xoff
= maxXOffset();
1997 if (yoff
> maxYOffset()) yoff
= maxYOffset();
1999 setOffset(xoff
, yoff
);
2002 void KTreeView::updateVisibleItems()
2006 updateVisibleItemRec(treeRoot
, index
, count
);
2007 assert(index
== count
);
2012 void KTreeView::updateVisibleItemRec(KTreeViewItem
* item
, int& index
, int& count
)
2014 if (!item
->isExpanded()) {
2015 // no visible items if not expanded
2020 * Record the children of item in the list of visible items.
2022 * Don't register item itself, it's already in the list. Also only
2023 * allocate new space for children.
2025 count
+= item
->childCount();
2026 if (count
> itemCapacity
) {
2028 int newCapacity
= itemCapacity
;
2030 newCapacity
+= newCapacity
;
2031 } while (newCapacity
< count
);
2032 KTreeViewItem
** newItems
= new KTreeViewItem
*[newCapacity
];
2033 // clear the unneeded space
2034 for (int i
= index
; i
< newCapacity
; i
++) {
2037 // move already accumulated items over
2038 for (int i
= index
-1; i
>= 0; i
--) {
2039 newItems
[i
] = visibleItems
[i
];
2041 delete[] visibleItems
;
2042 visibleItems
= newItems
;
2043 itemCapacity
= newCapacity
;
2046 for (KTreeViewItem
* i
= item
->getChild(); i
!= 0; i
= i
->getSibling()) {
2047 visibleItems
[index
++] = i
;
2048 updateVisibleItemRec(i
, index
, count
);